You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

306 lines
10 KiB

import React, { useState, useEffect, useRef } from 'react';
import { Card, Row, Col, Button, Select, Tabs, Statistic, Typography, Badge, Table } from 'antd';
import { ArrowUpOutlined, ArrowDownOutlined, LineChartOutlined, BarChartOutlined, PieChartOutlined } from '@ant-design/icons';
import { generateFutureData, generateKlineData } from '../../utils/mockData';
import useTheme from '../../hooks/useTheme';
// 导入Lightweight Charts
import { createChart } from 'lightweight-charts';
const { Title, Text } = Typography;
const { Option } = Select;
const { TabPane } = Tabs;
const { Column } = Table;
const Detail = () => {
const [selectedFuture, setSelectedFuture] = useState('MA');
const [futureData, setFutureData] = useState(generateFutureData('MA', '甲醇'));
const [timePeriod, setTimePeriod] = useState('1DAY');
const [chart, setChart] = useState(null);
const chartRef = useRef(null);
// 品种列表
const futuresList = [
{ code: 'MA', name: '甲醇' },
{ code: 'CU', name: '铜' },
{ code: 'SC', name: '原油' },
{ code: 'RB', name: '螺纹钢' },
{ code: 'P', name: '棕榈油' }
];
// K线数据
const klineData = generateKlineData(30);
// 切换品种
const handleFutureChange = (code) => {
const future = futuresList.find(f => f.code === code);
setSelectedFuture(code);
setFutureData(generateFutureData(code, future.name));
};
// 切换时间周期
const handleTimePeriodChange = (period) => {
setTimePeriod(period);
};
// 初始化K线图表
useEffect(() => {
if (chartRef.current) {
// 清除之前的图表
if (chart) {
chart.destroy();
}
// 创建新图表
const newChart = createChart(chartRef.current, {
width: chartRef.current.clientWidth,
height: 400,
layout: {
backgroundColor: '#ffffff',
textColor: '#333333'
},
grid: {
vertLines: {
color: '#f0f0f0'
},
horzLines: {
color: '#f0f0f0'
}
},
priceScale: {
borderColor: '#f0f0f0'
},
timeScale: {
borderColor: '#f0f0f0'
}
});
// 添加蜡烛图系列
const candleSeries = newChart.addCandlestickSeries({
upColor: '#52c41a',
downColor: '#ff4d4f',
borderUpColor: '#52c41a',
borderDownColor: '#ff4d4f',
wickUpColor: '#52c41a',
wickDownColor: '#ff4d4f'
});
// 添加成交量系列
const volumeSeries = newChart.addHistogramSeries({
color: '#82ca9d',
priceFormat: {
type: 'volume'
},
priceScaleId: '',
scaleMargins: {
top: 0.8, // 给蜡烛图留出空间
bottom: 0
}
});
// 准备数据
const candleData = klineData.map(item => ({
time: item.time,
open: parseFloat(item.open),
high: parseFloat(item.high),
low: parseFloat(item.low),
close: parseFloat(item.close)
}));
const volumeData = klineData.map(item => ({
time: item.time,
value: parseFloat(item.volume),
color: parseFloat(item.close) >= parseFloat(item.open) ? '#52c41a' : '#ff4d4f'
}));
// 设置数据
candleSeries.setData(candleData);
volumeSeries.setData(volumeData);
// 适配窗口大小
const handleResize = () => {
if (newChart) {
newChart.resize(chartRef.current.clientWidth, 400);
}
};
window.addEventListener('resize', handleResize);
setChart(newChart);
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
if (newChart) {
newChart.destroy();
}
};
}
}, []);
return (
<div>
{/* 页面头部 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col flex="auto">
<Title level={3}>{futureData.name} ({futureData.code}) 详情分析</Title>
<Text>{futureData.fullName}</Text>
</Col>
<Col flex="none">
<Select
defaultValue="MA"
style={{ width: 120, marginRight: 16 }}
onChange={handleFutureChange}
>
{futuresList.map(future => (
<Option key={future.code} value={future.code}>{future.name}</Option>
))}
</Select>
</Col>
</Row>
{/* 品种基本信息 */}
<Card style={{ marginBottom: 24 }}>
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic
title="当前价格"
value={futureData.currentPrice}
valueStyle={{ color: parseFloat(futureData.changePercent) > 0 ? '#52c41a' : '#ff4d4f' }}
suffix="元"
/>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic
title="涨跌幅"
value={futureData.changePercent}
valueStyle={{ color: parseFloat(futureData.changePercent) > 0 ? '#52c41a' : '#ff4d4f' }}
suffix="%"
/>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="胜率" value={futureData.winRate} suffix="%" />
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="ATR" value={futureData.atr} />
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="ADX" value={futureData.adx} />
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="趋势状态" value={futureData.adxStatus} />
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="风险等级" value={futureData.riskLevel} />
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<Statistic title="波动率" value={futureData.volatility} />
</Col>
</Row>
</Card>
{/* K线图表区 */}
<Card title="K线图表" style={{ marginBottom: 24 }}>
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<Select
defaultValue="1DAY"
style={{ width: 120 }}
onChange={handleTimePeriodChange}
>
<Option value="5MIN">5分钟</Option>
<Option value="30MIN">30分钟</Option>
<Option value="1HOUR">1小时</Option>
<Option value="1DAY">1</Option>
<Option value="1WEEK">1</Option>
</Select>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<Button icon={<LineChartOutlined />}>MA</Button>
<Button icon={<BarChartOutlined />}>MACD</Button>
<Button icon={<PieChartOutlined />}>KDJ</Button>
</div>
</div>
<div ref={chartRef} style={{ width: '100%', height: 400 }} />
</Card>
{/* 技术指标和AI研判区 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col xs={24} lg={12}>
<Card title="技术指标">
<Table dataSource={Object.entries(futureData.indicators).map(([key, value]) => ({ key, value }))} rowKey="key" size="small">
<Column title="指标" dataIndex="key" render={(text) => {
const indicatorNames = {
macd: 'MACD',
rsi: 'RSI',
bollinger: '布林带',
kdj: 'KDJ'
};
return indicatorNames[text] || text;
}} />
<Column title="状态" dataIndex="value" />
</Table>
</Card>
</Col>
<Col xs={24} lg={12}>
<Card title="多周期趋势">
<Table dataSource={Object.entries(futureData.trends).map(([period, data]) => ({ period, ...data }))} rowKey="period" size="small">
<Column title="周期" dataIndex="period" />
<Column title="方向" dataIndex="direction" render={(text) => (
<Badge status={text === '看多' ? 'success' : 'error'} text={text} />
)} />
<Column title="状态" dataIndex="status" />
<Column title="RSI" dataIndex="rsi" />
</Table>
</Card>
</Col>
</Row>
{/* 交易建议和AI研判区 */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col xs={24} lg={12}>
<Card title="交易建议">
<Row gutter={[16, 16]}>
<Col span={8}>
<Statistic title="入场价" value={futureData.tradingAdvice.entry} suffix="元" />
</Col>
<Col span={8}>
<Statistic title="止损价" value={futureData.tradingAdvice.stopLoss} suffix="元" />
</Col>
<Col span={8}>
<Statistic title="目标价" value={futureData.tradingAdvice.target} suffix="元" />
</Col>
</Row>
<div style={{ marginTop: 16, padding: 16, backgroundColor: '#f6ffed', border: '1px solid #b7eb8f', borderRadius: 4 }}>
<Text strong>AI建议</Text>
<Text>根据多周期分析当前{futureData.name}处于{futureData.trends[timePeriod].status}建议{futureData.trends[timePeriod].direction === '看多' ? '逢低做多' : '逢高做空'}</Text>
</div>
</Card>
</Col>
<Col xs={24} lg={12}>
<Card title="AI研判">
<div style={{ marginBottom: 16 }}>
<Text strong>整体判断</Text>
<Text>{futureData.name}当前处于{futureData.adxStatus}{futureData.trends[timePeriod].direction === '看多' ? '多头力量较强' : '空头力量较强'}</Text>
</div>
<div style={{ marginBottom: 16 }}>
<Text strong>技术面分析</Text>
<ul style={{ marginLeft: 20, marginTop: 8 }}>
<li>MACD{futureData.indicators.macd}</li>
<li>RSI{futureData.indicators.rsi}</li>
<li>布林带{futureData.indicators.bollinger}</li>
<li>KDJ{futureData.indicators.kdj}</li>
</ul>
</div>
<div>
<Text strong>风险提示</Text>
<Text>当前风险等级为{futureData.riskLevel}波动率{futureData.volatility}建议控制仓位严格设置止损</Text>
</div>
</Card>
</Col>
</Row>
</div>
);
};
export default Detail;