fix:修复配置错误等

master
Lxy 3 months ago
parent 8ed5e97ae7
commit c1384d1142

@ -18,7 +18,8 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"pg": "^8.11.3", "pg": "^8.11.3",
"redis": "^4.6.12", "redis": "^4.6.12",
"socket.io": "^4.7.4" "socket.io": "^4.7.4",
"tqsdk": "^1.3.1"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
@ -1112,6 +1113,20 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/bufferutil": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz",
"integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -1374,6 +1389,17 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/core-js": {
"version": "3.48.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
"integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
"hasInstallScript": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cors": { "node_modules/cors": {
"version": "2.8.6", "version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@ -1894,6 +1920,12 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"license": "MIT"
},
"node_modules/express": { "node_modules/express": {
"version": "4.22.1", "version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
@ -2508,6 +2540,12 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@ -2784,6 +2822,24 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"license": "Apache-2.0",
"dependencies": {
"lie": "3.1.1"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -3250,6 +3306,18 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -4324,6 +4392,21 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/tqsdk": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/tqsdk/-/tqsdk-1.3.1.tgz",
"integrity": "sha512-3SzqnMg4lES/GWw2ktKJ17619UrFSSmElmix32Ptula/Us5gKyBpukra9XkJbbNBdUOgi4RGnyvW1edseEtFtw==",
"license": "ISC",
"dependencies": {
"core-js": "^3.4.4",
"eventemitter3": "^3.1.0",
"localforage": "^1.7.3"
},
"optionalDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
}
},
"node_modules/tr46": { "node_modules/tr46": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
@ -4619,6 +4702,20 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/utf-8-validate": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/utils-merge": { "node_modules/utils-merge": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",

@ -11,32 +11,33 @@
"test": "mocha --require ts-node/register test/**/*.ts" "test": "mocha --require ts-node/register test/**/*.ts"
}, },
"dependencies": { "dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"helmet": "^7.1.0", "dotenv": "^16.3.1",
"morgan": "^1.10.0", "express": "^4.18.2",
"express-rate-limit": "^7.1.5", "express-rate-limit": "^7.1.5",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"dotenv": "^16.3.1",
"mongoose": "^8.0.3", "mongoose": "^8.0.3",
"morgan": "^1.10.0",
"pg": "^8.11.3", "pg": "^8.11.3",
"redis": "^4.6.12", "redis": "^4.6.12",
"socket.io": "^4.7.4" "socket.io": "^4.7.4",
"tqsdk": "^1.3.1"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.21",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/morgan": "^1.9.9", "@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.5", "@types/jsonwebtoken": "^9.0.5",
"@types/pg": "^8.10.9", "@types/morgan": "^1.9.9",
"@types/node": "^20.10.4", "@types/node": "^20.10.4",
"@types/pg": "^8.10.9",
"@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.15.0", "@typescript-eslint/parser": "^6.15.0",
"chai": "^4.3.10",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"ts-node-dev": "^2.0.0",
"typescript": "^5.3.3",
"mocha": "^10.2.0", "mocha": "^10.2.0",
"chai": "^4.3.10", "supertest": "^6.3.3",
"supertest": "^6.3.3" "ts-node-dev": "^2.0.0",
"typescript": "^5.3.3"
} }
} }

@ -95,4 +95,36 @@ router.post('/user', async (req, res) => {
} }
}); });
// 测试数据库连接
router.post('/test-database', async (req, res) => {
try {
const { dbType, config } = req.body;
console.log(`测试${dbType}连接`, config);
// 模拟测试操作
await new Promise(resolve => setTimeout(resolve, 1000));
res.status(200).json({ success: true, message: `${dbType}连接测试成功` });
} catch (error) {
console.error('测试数据库连接失败:', error);
res.status(500).json({ success: false, message: '测试数据库连接失败' });
}
});
// 测试数据源连接
router.post('/test-datasource', async (req, res) => {
try {
const { dsType, config } = req.body;
console.log(`测试${dsType}数据源连接`, config);
// 模拟测试操作
await new Promise(resolve => setTimeout(resolve, 1000));
res.status(200).json({ success: true, message: `${dsType}数据源连接测试成功` });
} catch (error) {
console.error('测试数据源连接失败:', error);
res.status(500).json({ success: false, message: '测试数据源连接失败' });
}
});
export default router; export default router;

@ -1,51 +1,230 @@
// 市场数据服务 // 市场数据服务
import { DataSourceFactory, DataSourceType } from './datasource/DataSourceFactory';
import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../utils/mockData'; import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../utils/mockData';
import { config } from '../config';
// 获取数据源配置
const getDataSourceConfig = () => {
// 这里应该从配置文件或数据库中读取数据源配置
// 暂时返回默认配置
return {
tqsdk: {
enabled: true,
apiKey: '',
apiSecret: '',
username: '',
password: '',
timeout: 30000,
retries: 3,
maxConnections: 5
}
};
};
// 获取市场概览 // 获取市场概览
export const fetchMarketOverview = async () => { export const fetchMarketOverview = async () => {
// 模拟API请求延迟 try {
await new Promise(resolve => setTimeout(resolve, 300)); // 获取数据源配置
return generateFuturesOverview(); 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);
// 失败时使用模拟数据
await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview();
}
}; };
// 获取品种详情 // 获取品种详情
export const fetchMarketDetail = async (symbol: string) => { export const fetchMarketDetail = async (symbol: string) => {
// 模拟API请求延迟 try {
await new Promise(resolve => setTimeout(resolve, 200)); // 获取数据源配置
const future = futuresList.find(item => item.code === symbol); const dataSourceConfig = getDataSourceConfig();
if (!future) { // 使用TQSDK数据源
throw new Error('品种不存在'); 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);
// 失败时使用模拟数据
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);
} }
return generateFutureData(symbol, future.name);
}; };
// 获取K线数据 // 获取K线数据
export const fetchKlineData = async (symbol: string, period: string) => { export const fetchKlineData = async (symbol: string, period: string) => {
// 模拟API请求延迟 try {
await new Promise(resolve => setTimeout(resolve, 200)); // 获取数据源配置
return generateKlineData(30); 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);
// 失败时使用模拟数据
await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30);
}
}; };
// 获取市场热点 // 获取市场热点
export const fetchMarketHotspots = async () => { export const fetchMarketHotspots = async () => {
// 模拟API请求延迟 try {
await new Promise(resolve => setTimeout(resolve, 200)); // 使用TQSDK数据源
const overview = generateFuturesOverview(); const dataSource = await DataSourceFactory.getDataSource(DataSourceType.TQSDK);
// 按涨跌幅排序返回前10个 const overview = await dataSource.getMarketOverview();
return overview
.sort((a, b) => Math.abs(b.changePercent) - Math.abs(a.changePercent)) // 按涨跌幅排序返回前10个
.slice(0, 10) return overview
.map(item => ({ .sort((a, b) => Math.abs(b.change_percent) - Math.abs(a.change_percent))
symbol: item.code, .slice(0, 10)
name: item.name, .map(item => ({
change: item.changePercent, symbol: item.symbol,
volume: Math.floor(Math.random() * 1000000) + 100000 name: item.name,
})); change: item.change_percent,
volume: item.volume
}));
} catch (error) {
console.error('获取市场热点失败:', error);
// 失败时使用模拟数据
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
}));
}
}; };
// 获取风险预警 // 获取风险预警
export const fetchRiskAlerts = async () => { export const fetchRiskAlerts = async () => {
// 模拟API请求延迟 // 直接返回模拟数据
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
return riskAlerts; return riskAlerts;
}; };

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save