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.

252 lines
10 KiB

// 市场数据服务
import { DataSourceFactory, DataSourceType } from './datasource/DataSourceFactory';
import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../utils/mockData';
import { config } from '../config';
// 获取数据源配置
const getDataSourceConfig = () => {
// 从配置文件中读取数据源配置
return config.dataSource;
};
// 获取市场概览
export const fetchMarketOverview = async () => {
try {
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 使用TQSDK数据源
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
const overview = await dataSource.getMarketOverview();
// 转换为前端需要的格式
return overview.map(item => ({
code: item.symbol,
name: item.name,
currentPrice: item.price,
changePercent: item.change_percent,
winRate: Math.floor(Math.random() * 50) + 30, // 模拟胜率
atr: +(Math.random() * 5 + 0.5).toFixed(2), // 模拟ATR
adx: Math.floor(Math.random() * 60) + 10, // 模拟ADX
adxStatus: adx => {
if (adx < 20) return '无趋势/震荡';
if (adx < 40) return '弱趋势';
return '强趋势';
},
trends: {
'5MIN': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'30MIN': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'1HOUR': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'1DAY': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
}
},
tradingAdvice: {
entry: item.price,
stopLoss: item.price * (1 - 0.02 * (Math.random() + 0.5)),
target: item.price * (1 + 0.03 * (Math.random() + 0.5)),
resistance: item.price * (1 + 0.05 * (Math.random() + 0.5)),
support: item.price * (1 - 0.05 * (Math.random() + 0.5))
},
overallView: ['观望', '中线', '多头排列', '空头排列', '震荡'][Math.floor(Math.random() * 5)],
aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
}));
} catch (error) {
console.error('获取市场概览失败:', error);
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 检查是否启用了测试数据源
if (dataSourceConfig.test && dataSourceConfig.test.enabled) {
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview();
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取市场概览失败,请检查数据源配置');
}
}
};
// 获取品种详情
export const fetchMarketDetail = async (symbol: string) => {
try {
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 使用TQSDK数据源
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
const contract = await dataSource.getContractDetail(symbol);
const tick = await dataSource.getTickData(symbol);
// 转换为前端需要的格式
return {
code: contract.symbol,
name: contract.name,
fullName: `${contract.name}-${contract.symbol}605`,
currentPrice: tick.last_price,
changePercent: tick.price_change / tick.pre_close * 100,
winRate: Math.floor(Math.random() * 50) + 30,
atr: +(Math.random() * 5 + 0.5).toFixed(2),
adx: Math.floor(Math.random() * 60) + 10,
adxStatus: adx => {
if (adx < 20) return '无趋势/震荡';
if (adx < 40) return '弱趋势';
return '强趋势';
},
trends: {
'5MIN': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'30MIN': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'1HOUR': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
},
'1DAY': {
direction: ['看多', '看空', '观望'][Math.floor(Math.random() * 3)],
status: ['多头趋势', '空头趋势', '震荡'][Math.floor(Math.random() * 3)],
rsi: Math.floor(Math.random() * 80) + 10
}
},
indicators: {
macd: ['金叉向上', '死叉向下', '走平'][Math.floor(Math.random() * 3)],
rsi: `${Math.floor(Math.random() * 80) + 10}(中性)`,
bollinger: ['触及上轨', '触及下轨', '中轨附近'][Math.floor(Math.random() * 3)],
kdj: ['金叉向上', '死叉向下', '走平'][Math.floor(Math.random() * 3)]
},
tradingAdvice: {
entry: tick.last_price,
stopLoss: tick.last_price * (1 - 0.02 * (Math.random() + 0.5)),
target: tick.last_price * (1 + 0.03 * (Math.random() + 0.5)),
resistance: tick.last_price * (1 + 0.05 * (Math.random() + 0.5)),
support: tick.last_price * (1 - 0.05 * (Math.random() + 0.5))
},
riskLevel: ['低', '中等', '高'][Math.floor(Math.random() * 3)],
volatility: ['低', '中等', '高'][Math.floor(Math.random() * 3)],
overallView: ['观望', '中线', '多头排列', '空头排列', '震荡'][Math.floor(Math.random() * 5)],
aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
};
} catch (error) {
console.error(`获取品种${symbol}详情失败:`, error);
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 检查是否启用了测试数据源
if (dataSourceConfig.test && dataSourceConfig.test.enabled) {
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200));
const future = futuresList.find(item => item.code === symbol);
if (!future) {
throw new Error('品种不存在');
}
return generateFutureData(symbol, future.name);
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取品种详情失败,请检查数据源配置');
}
}
};
// 获取K线数据
export const fetchKlineData = async (symbol: string, period: string) => {
try {
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 使用TQSDK数据源
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
const klineData = await dataSource.getKlineData(symbol, period, 30);
// 转换为前端需要的格式
return klineData.map(item => ({
timestamp: item.datetime / 1000000000, // 转换为秒
open: item.open,
high: item.high,
low: item.low,
close: item.close,
volume: item.volume
}));
} catch (error) {
console.error(`获取合约${symbol}K线数据失败:`, error);
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 检查是否启用了测试数据源
if (dataSourceConfig.test && dataSourceConfig.test.enabled) {
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30);
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取K线数据失败请检查数据源配置');
}
}
};
// 获取市场热点
export const fetchMarketHotspots = async () => {
try {
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 使用TQSDK数据源
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
const overview = await dataSource.getMarketOverview();
// 按涨跌幅排序返回前10个
return overview
.sort((a, b) => Math.abs(b.change_percent) - Math.abs(a.change_percent))
.slice(0, 10)
.map(item => ({
symbol: item.symbol,
name: item.name,
change: item.change_percent,
volume: item.volume
}));
} catch (error) {
console.error('获取市场热点失败:', error);
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 检查是否启用了测试数据源
if (dataSourceConfig.test && dataSourceConfig.test.enabled) {
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200));
const overview = generateFuturesOverview();
// 按涨跌幅排序返回前10个
return overview
.sort((a, b) => Math.abs(b.changePercent) - Math.abs(a.changePercent))
.slice(0, 10)
.map(item => ({
symbol: item.code,
name: item.name,
change: item.changePercent,
volume: Math.floor(Math.random() * 1000000) + 100000
}));
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取市场热点失败,请检查数据源配置');
}
}
};
// 获取风险预警
export const fetchRiskAlerts = async () => {
// 直接返回模拟数据
await new Promise(resolve => setTimeout(resolve, 100));
return riskAlerts;
};