fix: 可正常获取K线数据;目前存在问题:1、前端显示K线存在问题;2、请求K线慢 ;解决方案:1、查找K线图显示问题;2、使用缓存策略,提前缓存各个品种的k线数据

master
Lxy 3 months ago
parent 0be07b8f8a
commit 6d0b554cee

@ -214,7 +214,7 @@ class RqDataAdapter(BaseDataAdapter):
print(f"无法获取真实数据:{'API未连接' if not self.api_connected else 'RQData不可用'}")
return None
except Exception as e:
print(f"获取K线数据失败{e}")
print(f"rqdata获取K线数据失败{e}")
# 不再自动返回模拟数据返回None
return None

@ -192,7 +192,7 @@ class TqSdkAdapter(BaseDataAdapter):
print(f"无法获取真实数据:{'API未连接' if not self.api else 'TQSDK不可用'}")
return None
except Exception as e:
print(f"获取K线数据失败{e}")
print(f"tqsdk获取K线数据失败{e}")
# 不再自动返回模拟数据返回None
return None

@ -39,7 +39,9 @@ def get_contracts():
exchange = request.args.get('exchange', '')
symbol = request.args.get('symbol', '')
print("正在获取合约数据..., exchange:", exchange, "symbol:", symbol)
contracts = data_fetcher.get_contracts(exchange=exchange, symbol=symbol)
print(f"获取到 {contracts} 合约")
return jsonify({'status': 'success', 'data': contracts})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500

@ -73,6 +73,7 @@ class ServiceImplementationClient {
const params: Record<string, string> = {};
if (exchange) params.exchange = exchange;
if (symbol) params.symbol = symbol;
logger.info(`Getting contracts for exchange ${exchange} and symbol ${symbol}`);
return this.get<{ status: string; data: any[] }>('/api/contracts', params);
}

@ -39,14 +39,14 @@ export const fetchMarketOverview = async () => {
// 转换为数组
const contractList = Array.from(uniqueContracts.values());
logger.log(`获取到 ${contractList.length} 个独特品种`);
logger.log(`获取到 ${contractList.length} 个独特品种,分别是: ${contractList.map(c => c.code).join(', ')}`);
// 使用获取到的合约列表
const overview = [];
for (const future of contractList) {
try {
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}03`;
// 获取合约详情
logger.log(`获取合约${symbol}详情...`);
@ -131,104 +131,104 @@ export const fetchMarketOverview = async () => {
// service_implementation API 失败,尝试使用其他数据源
}
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
logger.log('获取数据源配置:', dataSourceConfig);
// 检查是否有可用的数据源
const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled;
if (!hasAvailableDataSource) {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
}
// 尝试使用TQSDK数据源
if (dataSourceConfig.tqsdk?.enabled) {
try {
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
// 使用用户指定的合约列表
const overview = [];
for (const future of futuresList) {
try {
// 构建合约符号使用小写代码因为TQAPI期望小写
const symbol = `${future.exchange}.${future.code.toLowerCase()}${new Date().getFullYear().toString().slice(-2)}05`;
// 获取合约详情和实时行情
const tick = await dataSource.getTickData(symbol);
overview.push({
code: future.code,
name: future.name,
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), // 模拟ATR
adx: Math.floor(Math.random() * 60) + 10, // 模拟ADX
adxStatus: (adx: number) => {
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: 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))
},
overallView: ['观望', '中线', '多头排列', '空头排列', '震荡'][Math.floor(Math.random() * 5)],
aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
});
} catch (error) {
logger.error(`获取合约${future.code}行情失败:`, error);
// 跳过获取失败的合约
continue;
}
}
return overview;
} catch (error) {
logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) {
logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview();
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取市场概览失败,所有数据源均不可用');
}
}
} else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源
logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview();
} else {
// 无可用数据源
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
}
// // 获取数据源配置
// const dataSourceConfig = getDataSourceConfig();
// logger.log('获取数据源配置:', dataSourceConfig);
// // 检查是否有可用的数据源
// const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled;
// if (!hasAvailableDataSource) {
// throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
// }
// // 尝试使用TQSDK数据源
// if (dataSourceConfig.tqsdk?.enabled) {
// try {
// const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
// // 使用用户指定的合约列表
// const overview = [];
// for (const future of futuresList) {
// try {
// // 构建合约符号使用小写代码因为TQAPI期望小写
// const symbol = `${future.exchange}.${future.code.toLowerCase()}${new Date().getFullYear().toString().slice(-2)}05`;
// // 获取合约详情和实时行情
// const tick = await dataSource.getTickData(symbol);
// overview.push({
// code: future.code,
// name: future.name,
// 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), // 模拟ATR
// adx: Math.floor(Math.random() * 60) + 10, // 模拟ADX
// adxStatus: (adx: number) => {
// 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: 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))
// },
// overallView: ['观望', '中线', '多头排列', '空头排列', '震荡'][Math.floor(Math.random() * 5)],
// aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
// });
// } catch (error) {
// logger.error(`获取合约${future.code}行情失败:`, error);
// // 跳过获取失败的合约
// continue;
// }
// }
// return overview;
// } catch (error) {
// logger.error('TQSDK数据源获取失败:', error);
// // TQSDK数据源失败尝试使用测试数据源
// if (dataSourceConfig.test?.enabled) {
// logger.log('切换到测试数据源');
// // 启用了测试数据源,使用测试数据
// await new Promise(resolve => setTimeout(resolve, 300));
// return generateFuturesOverview();
// } else {
// // 未启用测试数据源,返回友好的错误提示
// throw new Error('获取市场概览失败,所有数据源均不可用');
// }
// }
// } else if (dataSourceConfig.test?.enabled) {
// // 直接使用测试数据源
// logger.log('使用测试数据源');
// await new Promise(resolve => setTimeout(resolve, 300));
// return generateFuturesOverview();
// } else {
// // 无可用数据源
// throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
// }
} catch (error) {
logger.error('获取市场概览失败:', error);
// 直接返回友好的错误提示
@ -252,7 +252,7 @@ export const fetchMarketDetail = async (symbol: string) => {
logger.log('尝试使用 service_implementation API 获取品种详情...');
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}03`;
// 获取合约详情
logger.log(`获取合约${contractSymbol}详情...`);
@ -461,7 +461,7 @@ export const fetchKlineData = async (symbol: string, period: string) => {
logger.log('尝试使用 service_implementation API 获取K线数据...');
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}3`;
// 转换周期格式
let duration = period;
@ -517,57 +517,57 @@ export const fetchKlineData = async (symbol: string, period: string) => {
// service_implementation API 失败,尝试使用其他数据源
}
// 获取数据源配置
const dataSourceConfig = getDataSourceConfig();
// 检查是否有可用的数据源
const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled;
if (!hasAvailableDataSource) {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
}
// 尝试使用TQSDK数据源
if (dataSourceConfig.tqsdk?.enabled) {
try {
const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
// 构建合约符号使用小写代码因为TQAPI期望小写
const contractSymbol = `${future.exchange}.${future.code.toLowerCase()}${new Date().getFullYear().toString().slice(-2)}05`;
// 获取K线数据
const klineData = await dataSource.getKlineData(contractSymbol, 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) {
logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) {
logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30);
} else {
// 未启用测试数据源,返回友好的错误提示
throw new Error('获取K线数据失败所有数据源均不可用');
}
}
} else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源
logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30);
} else {
// 无可用数据源
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
}
// // 获取数据源配置
// const dataSourceConfig = getDataSourceConfig();
// // 检查是否有可用的数据源
// const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled;
// if (!hasAvailableDataSource) {
// throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
// }
// // 尝试使用TQSDK数据源
// if (dataSourceConfig.tqsdk?.enabled) {
// try {
// const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK, dataSourceConfig);
// // 构建合约符号使用小写代码因为TQAPI期望小写
// const contractSymbol = `${future.exchange}.${future.code.toLowerCase()}${new Date().getFullYear().toString().slice(-2)}05`;
// // 获取K线数据
// const klineData = await dataSource.getKlineData(contractSymbol, 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) {
// logger.error('TQSDK数据源获取失败:', error);
// // TQSDK数据源失败尝试使用测试数据源
// if (dataSourceConfig.test?.enabled) {
// logger.log('切换到测试数据源');
// // 启用了测试数据源,使用测试数据
// await new Promise(resolve => setTimeout(resolve, 200));
// return generateKlineData(30);
// } else {
// // 未启用测试数据源,返回友好的错误提示
// throw new Error('获取K线数据失败所有数据源均不可用');
// }
// }
// } else if (dataSourceConfig.test?.enabled) {
// // 直接使用测试数据源
// logger.log('使用测试数据源');
// await new Promise(resolve => setTimeout(resolve, 200));
// return generateKlineData(30);
// } else {
// // 无可用数据源
// throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
// }
} catch (error) {
logger.error(`获取合约${symbol}K线数据失败:`, error);
// 直接返回友好的错误提示
@ -610,7 +610,7 @@ export const fetchMarketHotspots = async () => {
for (const future of contractList) {
try {
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}03`;
// 获取合约详情
logger.log(`获取合约${symbol}详情...`);

Loading…
Cancel
Save