沪深300 与汇率负相关
This commit is contained in:
parent
f2824d88f7
commit
342042577d
81
pages/api/sh300-index.js
Normal file
81
pages/api/sh300-index.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { createPool } from 'mariadb';
|
||||||
|
|
||||||
|
async function handler(req, res) {
|
||||||
|
if (req.method !== 'GET') {
|
||||||
|
return res.status(405).json({ message: '只支持GET请求' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { startDate, endDate, limit } = req.query;
|
||||||
|
|
||||||
|
let pool;
|
||||||
|
try {
|
||||||
|
pool = createPool({
|
||||||
|
host: process.env.DB_HOST || '192.168.111.111',
|
||||||
|
port: parseInt(process.env.DB_PORT || '3306'),
|
||||||
|
user: process.env.DB_USER || 'root',
|
||||||
|
password: process.env.DB_PASSWORD || 'fullstack',
|
||||||
|
database: process.env.DB_NAME || 'iboard',
|
||||||
|
connectionLimit: 5
|
||||||
|
});
|
||||||
|
|
||||||
|
let query = 'SELECT date, close FROM econ_SH300Index';
|
||||||
|
const params = [];
|
||||||
|
const conditions = [];
|
||||||
|
|
||||||
|
if (startDate) {
|
||||||
|
conditions.push('date >= ?');
|
||||||
|
params.push(startDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endDate) {
|
||||||
|
conditions.push('date <= ?');
|
||||||
|
params.push(endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conditions.length > 0) {
|
||||||
|
query += ' WHERE ' + conditions.join(' AND ');
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ' ORDER BY date ASC';
|
||||||
|
|
||||||
|
if (limit) {
|
||||||
|
query += ' LIMIT ?';
|
||||||
|
params.push(parseInt(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await pool.query(query, params);
|
||||||
|
|
||||||
|
const data = result.map(row => {
|
||||||
|
let dateStr;
|
||||||
|
if (row.date instanceof Date) {
|
||||||
|
dateStr = row.date.toISOString().split('T')[0];
|
||||||
|
} else if (typeof row.date === 'string') {
|
||||||
|
dateStr = row.date;
|
||||||
|
} else {
|
||||||
|
dateStr = String(row.date);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
date: dateStr,
|
||||||
|
close: parseFloat(row.close)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取沪深300数据失败:', error);
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: '获取沪深300数据失败: ' + error.message
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
if (pool) {
|
||||||
|
await pool.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default handler;
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import { useState } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import Navbar from '../components/Navbar'
|
import Navbar from '../components/Navbar'
|
||||||
import Footer from '../components/Footer'
|
import Footer from '../components/Footer'
|
||||||
|
import TimeRangePicker from '../components/TimeRangePicker'
|
||||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
|
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
|
||||||
|
|
||||||
const usDebtData = [
|
const usDebtData = [
|
||||||
@ -28,6 +29,11 @@ const chinaDebtData = [
|
|||||||
|
|
||||||
export default function Strategy() {
|
export default function Strategy() {
|
||||||
const [selectedStrategy, setSelectedStrategy] = useState('us-debt-gdp')
|
const [selectedStrategy, setSelectedStrategy] = useState('us-debt-gdp')
|
||||||
|
const [sh300ExchangeData, setSh300ExchangeData] = useState([])
|
||||||
|
const [sh300Loading, setSh300Loading] = useState(false)
|
||||||
|
const [timeRange, setTimeRange] = useState('1m')
|
||||||
|
const [startDate, setStartDate] = useState('')
|
||||||
|
const [endDate, setEndDate] = useState('')
|
||||||
|
|
||||||
const strategies = [
|
const strategies = [
|
||||||
{
|
{
|
||||||
@ -37,9 +43,76 @@ export default function Strategy() {
|
|||||||
{
|
{
|
||||||
id: 'china-debt-gdp',
|
id: 'china-debt-gdp',
|
||||||
name: '中国政府债务/GDP'
|
name: '中国政府债务/GDP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sh300-exchange-rate',
|
||||||
|
name: '沪深300与汇率对比'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedStrategy === 'sh300-exchange-rate') {
|
||||||
|
fetchSh300ExchangeData()
|
||||||
|
}
|
||||||
|
}, [selectedStrategy, timeRange, startDate, endDate])
|
||||||
|
|
||||||
|
const handleTimeRangeChange = (range, start, end) => {
|
||||||
|
setTimeRange(range)
|
||||||
|
setStartDate(start)
|
||||||
|
setEndDate(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSh300ExchangeData = async () => {
|
||||||
|
setSh300Loading(true)
|
||||||
|
try {
|
||||||
|
let sh300Url = '/api/sh300-index'
|
||||||
|
let exchangeUrl = '/api/exchange-rate'
|
||||||
|
|
||||||
|
const params = []
|
||||||
|
if (timeRange === 'custom' && startDate && endDate) {
|
||||||
|
params.push(`startDate=${startDate}`)
|
||||||
|
params.push(`endDate=${endDate}`)
|
||||||
|
} else if (timeRange === '1m') {
|
||||||
|
params.push('limit=30')
|
||||||
|
} else if (timeRange === '3m') {
|
||||||
|
params.push('limit=90')
|
||||||
|
} else if (timeRange === '1y') {
|
||||||
|
params.push('limit=365')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.length > 0) {
|
||||||
|
sh300Url += '?' + params.join('&')
|
||||||
|
exchangeUrl += '?' + params.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
const [sh300Res, exchangeRes] = await Promise.all([
|
||||||
|
fetch(sh300Url),
|
||||||
|
fetch(exchangeUrl)
|
||||||
|
])
|
||||||
|
const sh300Json = await sh300Res.json()
|
||||||
|
const exchangeJson = await exchangeRes.json()
|
||||||
|
|
||||||
|
if (sh300Json.success && exchangeJson.success) {
|
||||||
|
const sh300Map = new Map(sh300Json.data.map(item => [item.date, item.close]))
|
||||||
|
const exchangeMap = new Map(exchangeJson.data.map(item => [item.date, item.rate]))
|
||||||
|
|
||||||
|
const allDates = [...new Set([...sh300Map.keys(), ...exchangeMap.keys()])].sort()
|
||||||
|
|
||||||
|
const mergedData = allDates.map(date => ({
|
||||||
|
date,
|
||||||
|
sh300: sh300Map.get(date) || null,
|
||||||
|
exchangeRate: exchangeMap.get(date) || null
|
||||||
|
})).filter(item => item.sh300 !== null && item.exchangeRate !== null)
|
||||||
|
|
||||||
|
setSh300ExchangeData(mergedData)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取数据失败:', error)
|
||||||
|
} finally {
|
||||||
|
setSh300Loading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<Head>
|
<Head>
|
||||||
@ -272,6 +345,46 @@ export default function Strategy() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{selectedStrategy === 'sh300-exchange-rate' && (
|
||||||
|
<div className="strategy-detail">
|
||||||
|
<h2 className="strategy-title">沪深300与汇率对比分析</h2>
|
||||||
|
<p className="strategy-description">
|
||||||
|
对比沪深300指数收盘价与人民币兑美元汇率的走势关系
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{sh300Loading ? (
|
||||||
|
<div className="loading">加载中...</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="chart-header">
|
||||||
|
<TimeRangePicker
|
||||||
|
value={timeRange}
|
||||||
|
onChange={handleTimeRangeChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="chart-section">
|
||||||
|
<h3 className="chart-title">沪深300与汇率对比(双Y轴)</h3>
|
||||||
|
<div className="chart-container">
|
||||||
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
|
<LineChart data={sh300ExchangeData} margin={{ top: 20, right: 60, left: 20, bottom: 5 }}>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="date" />
|
||||||
|
<YAxis yAxisId="left" domain={['dataMin - 100', 'dataMax + 100']} />
|
||||||
|
<YAxis yAxisId="right" orientation="right" domain={['dataMin - 0.05', 'dataMax + 0.05']} tickFormatter={(value) => value.toFixed(4)} />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
<Line yAxisId="left" type="monotone" dataKey="sh300" name="沪深300收盘价" stroke="#8884d8" strokeWidth={2} activeDot={{ r: 8 }} />
|
||||||
|
<Line yAxisId="right" type="monotone" dataKey="exchangeRate" name="汇率" stroke="#82ca9d" strokeWidth={2} activeDot={{ r: 8 }} />
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user