parent
0526feb278
commit
7c9ac8fae7
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "alpha-futures-backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "AI期货分析系统后端API服务",
|
||||||
|
"main": "dist/app.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "ts-node-dev --respawn --transpile-only src/app.ts",
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node dist/app.js",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"test": "mocha --require ts-node/register test/**/*.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"helmet": "^7.1.0",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
|
"express-rate-limit": "^7.1.5",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"mongoose": "^8.0.3",
|
||||||
|
"pg": "^8.11.3",
|
||||||
|
"redis": "^4.6.12",
|
||||||
|
"socket.io": "^4.7.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/cors": "^2.8.17",
|
||||||
|
"@types/morgan": "^1.9.9",
|
||||||
|
"@types/jsonwebtoken": "^9.0.5",
|
||||||
|
"@types/pg": "^8.10.9",
|
||||||
|
"@types/node": "^20.10.4",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||||
|
"@typescript-eslint/parser": "^6.15.0",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"ts-node-dev": "^2.0.0",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"mocha": "^10.2.0",
|
||||||
|
"chai": "^4.3.10",
|
||||||
|
"supertest": "^6.3.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchAIAnalysis, fetchMultiDimensionAnalysis, fetchTrendPrediction, fetchWinRateAssessment, fetchTechnicalIndicators } from '../services/analysisService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取AI分析
|
||||||
|
router.get('/ai/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchAIAnalysis(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取AI分析失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取多维度分析
|
||||||
|
router.get('/multi/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchMultiDimensionAnalysis(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取多维度分析失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取趋势预测
|
||||||
|
router.get('/trend/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchTrendPrediction(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取趋势预测失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取胜率评估
|
||||||
|
router.get('/winrate/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchWinRateAssessment(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取胜率评估失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取技术指标
|
||||||
|
router.get('/indicators/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchTechnicalIndicators(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取技术指标失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchDataSources, saveDataSource, fetchAIModels, saveAIModel, fetchSystemSettings, saveSystemSettings } from '../services/configService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取数据源列表
|
||||||
|
router.get('/datasources', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchDataSources();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取数据源列表失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存数据源配置
|
||||||
|
router.post('/datasources', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await saveDataSource(req.body);
|
||||||
|
res.status(200).json({ success: true, message: '配置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存数据源配置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取AI模型列表
|
||||||
|
router.get('/ai-models', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchAIModels();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取AI模型列表失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存AI模型配置
|
||||||
|
router.post('/ai-models', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await saveAIModel(req.body);
|
||||||
|
res.status(200).json({ success: true, message: '配置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存AI模型配置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取系统设置
|
||||||
|
router.get('/system', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchSystemSettings();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取系统设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存系统设置
|
||||||
|
router.post('/system', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await saveSystemSettings(req.body);
|
||||||
|
res.status(200).json({ success: true, message: '设置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存系统设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取用户设置
|
||||||
|
router.get('/user', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
preferences: {
|
||||||
|
theme: 'light',
|
||||||
|
language: 'zh-CN',
|
||||||
|
timezone: 'Asia/Shanghai'
|
||||||
|
},
|
||||||
|
notifications: {
|
||||||
|
email: true,
|
||||||
|
sms: false,
|
||||||
|
wechat: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取用户设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存用户设置
|
||||||
|
router.post('/user', async (req, res) => {
|
||||||
|
try {
|
||||||
|
// 模拟保存操作
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
res.status(200).json({ success: true, message: '设置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存用户设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchMarketOverview, fetchMarketDetail, fetchKlineData, fetchMarketHotspots, fetchRiskAlerts } from '../services/marketService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取市场概览
|
||||||
|
router.get('/overview', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchMarketOverview();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取市场概览失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取品种详情
|
||||||
|
router.get('/detail/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchMarketDetail(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取品种详情失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取K线数据
|
||||||
|
router.get('/klines/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const { period = '1H' } = req.query;
|
||||||
|
const data = await fetchKlineData(symbol, period as string);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取K线数据失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取市场热点
|
||||||
|
router.get('/hotspots', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchMarketHotspots();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取市场热点失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取风险预警
|
||||||
|
router.get('/alerts', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchRiskAlerts();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取风险预警失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchPushSettings, savePushSettings, testPush, fetchPushHistory } from '../services/pushService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取推送设置
|
||||||
|
router.get('/settings/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchPushSettings(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取推送设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存推送设置
|
||||||
|
router.post('/settings/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await savePushSettings(symbol, req.body);
|
||||||
|
res.status(200).json({ success: true, message: '设置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存推送设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 测试推送
|
||||||
|
router.post('/test', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { method, content } = req.body;
|
||||||
|
const data = await testPush(method, content);
|
||||||
|
res.status(200).json({ success: true, message: '测试推送成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '测试推送失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取推送历史
|
||||||
|
router.get('/history', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchPushHistory();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取推送历史失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchStopLossAdvice, fetchPositionAdvice, fetchRolloverAlerts, fetchRiskAssessment } from '../services/riskService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取止损建议
|
||||||
|
router.get('/stoploss/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchStopLossAdvice(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取止损建议失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取仓位建议
|
||||||
|
router.post('/position', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { capital, risk_tolerance, symbols } = req.body;
|
||||||
|
const data = await fetchPositionAdvice(capital, risk_tolerance, symbols);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取仓位建议失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取换月预警
|
||||||
|
router.get('/rollover', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchRolloverAlerts();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取换月预警失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取风险评估
|
||||||
|
router.get('/assessment/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await fetchRiskAssessment(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取风险评估失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存风控设置
|
||||||
|
router.post('/settings', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { stop_loss_strategy, risk_tolerance, max_position } = req.body;
|
||||||
|
// 模拟保存操作
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
res.status(200).json({ success: true, message: '设置保存成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '保存风控设置失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import { fetchWatchlist, addToWatchlist, removeFromWatchlist, checkWatchlistStatus } from '../services/watchlistService';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 获取自选列表
|
||||||
|
router.get('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await fetchWatchlist();
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '获取自选列表失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加自选
|
||||||
|
router.post('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol, name } = req.body;
|
||||||
|
const data = await addToWatchlist(symbol, name);
|
||||||
|
res.status(200).json({ success: true, message: '添加成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '添加自选失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除自选
|
||||||
|
router.delete('/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await removeFromWatchlist(symbol);
|
||||||
|
res.status(200).json({ success: true, message: '删除成功' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '删除自选失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查自选状态
|
||||||
|
router.get('/status/:symbol', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { symbol } = req.params;
|
||||||
|
const data = await checkWatchlistStatus(symbol);
|
||||||
|
res.status(200).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: '检查自选状态失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import cors from 'cors';
|
||||||
|
import helmet from 'helmet';
|
||||||
|
import morgan from 'morgan';
|
||||||
|
import rateLimit from 'express-rate-limit';
|
||||||
|
import { config } from './config';
|
||||||
|
import marketRoutes from './api/market';
|
||||||
|
import analysisRoutes from './api/analysis';
|
||||||
|
import riskRoutes from './api/risk';
|
||||||
|
import configRoutes from './api/config';
|
||||||
|
import watchlistRoutes from './api/watchlist';
|
||||||
|
import pushRoutes from './api/push';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
// 中间件配置
|
||||||
|
app.use(helmet());
|
||||||
|
app.use(cors(config.cors));
|
||||||
|
app.use(morgan('combined'));
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// 速率限制
|
||||||
|
app.use(rateLimit({
|
||||||
|
windowMs: config.rateLimit.windowMs,
|
||||||
|
max: config.rateLimit.max,
|
||||||
|
message: {
|
||||||
|
success: false,
|
||||||
|
message: '请求过于频繁,请稍后再试'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 健康检查
|
||||||
|
app.get('/health', (req, res) => {
|
||||||
|
res.status(200).json({ success: true, message: '服务运行正常' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// API路由注册
|
||||||
|
app.use('/api/market', marketRoutes);
|
||||||
|
app.use('/api/analysis', analysisRoutes);
|
||||||
|
app.use('/api/risk', riskRoutes);
|
||||||
|
app.use('/api/config', configRoutes);
|
||||||
|
app.use('/api/watchlist', watchlistRoutes);
|
||||||
|
app.use('/api/push', pushRoutes);
|
||||||
|
|
||||||
|
// 404处理
|
||||||
|
app.use((req, res) => {
|
||||||
|
res.status(404).json({ success: false, message: '接口不存在' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
console.error(err.stack);
|
||||||
|
res.status(500).json({ success: false, message: '服务器内部错误' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 启动服务器
|
||||||
|
app.listen(config.port, () => {
|
||||||
|
console.log(`服务器运行在 http://localhost:${config.port}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default app;
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
port: process.env.PORT || 3005,
|
||||||
|
jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
|
||||||
|
database: {
|
||||||
|
mongo: {
|
||||||
|
url: process.env.MONGO_URL || 'mongodb://localhost:27017/alpha-futures'
|
||||||
|
},
|
||||||
|
postgres: {
|
||||||
|
host: process.env.PG_HOST || 'localhost',
|
||||||
|
port: parseInt(process.env.PG_PORT || '5432'),
|
||||||
|
user: process.env.PG_USER || 'postgres',
|
||||||
|
password: process.env.PG_PASSWORD || 'password',
|
||||||
|
database: process.env.PG_DATABASE || 'alpha-futures'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
url: process.env.REDIS_URL || 'redis://localhost:6379'
|
||||||
|
},
|
||||||
|
rateLimit: {
|
||||||
|
windowMs: 60 * 1000, // 1分钟
|
||||||
|
max: 120 // 每分钟120次请求
|
||||||
|
},
|
||||||
|
cors: {
|
||||||
|
origin: '*', // 在生产环境中应该设置具体的域名
|
||||||
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||||
|
allowedHeaders: ['Content-Type', 'Authorization']
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
// 分析服务
|
||||||
|
import { generateFutureData, futuresList } from '../utils/mockData';
|
||||||
|
|
||||||
|
// 获取AI分析
|
||||||
|
export const fetchAIAnalysis = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
const future = futuresList.find(item => item.code === symbol);
|
||||||
|
if (!future) {
|
||||||
|
throw new Error('品种不存在');
|
||||||
|
}
|
||||||
|
const data = generateFutureData(symbol, future.name);
|
||||||
|
|
||||||
|
return {
|
||||||
|
symbol,
|
||||||
|
technical: {
|
||||||
|
trend: data.overallView,
|
||||||
|
indicators: data.indicators,
|
||||||
|
strength: data.adx > 40 ? '强' : data.adx > 20 ? '弱' : '无'
|
||||||
|
},
|
||||||
|
fundamental: {
|
||||||
|
industry: future.type,
|
||||||
|
supplyDemand: ['平衡', '供过于求', '供不应求'][Math.floor(Math.random() * 3)],
|
||||||
|
policyImpact: ['中性', '利好', '利空'][Math.floor(Math.random() * 3)]
|
||||||
|
},
|
||||||
|
sentiment: {
|
||||||
|
marketSentiment: ['中性', '乐观', '悲观'][Math.floor(Math.random() * 3)],
|
||||||
|
positioning: ['多头', '空头', '平衡'][Math.floor(Math.random() * 3)],
|
||||||
|
volumeAnalysis: '正常'
|
||||||
|
},
|
||||||
|
prediction: {
|
||||||
|
trend: ['上涨', '下跌', '震荡'][Math.floor(Math.random() * 3)],
|
||||||
|
winRate: data.winRate,
|
||||||
|
expectedReturn: +(Math.random() * 10 - 2).toFixed(2),
|
||||||
|
timeHorizon: '1-3天'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取多维度分析
|
||||||
|
export const fetchMultiDimensionAnalysis = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 400));
|
||||||
|
|
||||||
|
return {
|
||||||
|
technical: {
|
||||||
|
trend: ['多头', '空头', '震荡'][Math.floor(Math.random() * 3)],
|
||||||
|
support: +(Math.random() * 500 + 1500).toFixed(2),
|
||||||
|
resistance: +(Math.random() * 500 + 2500).toFixed(2),
|
||||||
|
indicators: {
|
||||||
|
macd: ['金叉', '死叉', '走平'][Math.floor(Math.random() * 3)],
|
||||||
|
rsi: Math.floor(Math.random() * 40) + 30,
|
||||||
|
kdj: ['金叉', '死叉', '走平'][Math.floor(Math.random() * 3)]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
capital: {
|
||||||
|
fundFlow: ['流入', '流出', '平衡'][Math.floor(Math.random() * 3)],
|
||||||
|
openInterest: Math.floor(Math.random() * 100000) + 50000,
|
||||||
|
volume: Math.floor(Math.random() * 1000000) + 100000,
|
||||||
|
largePositions: Math.floor(Math.random() * 50) + 20
|
||||||
|
},
|
||||||
|
policy: {
|
||||||
|
industryPolicy: ['中性', '利好', '利空'][Math.floor(Math.random() * 3)],
|
||||||
|
macroEconomy: ['稳定', '向好', '向坏'][Math.floor(Math.random() * 3)],
|
||||||
|
internationalFactors: ['稳定', '有利', '不利'][Math.floor(Math.random() * 3)]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取趋势预测
|
||||||
|
export const fetchTrendPrediction = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
return {
|
||||||
|
short_term: {
|
||||||
|
trend: ['上涨', '下跌', '震荡'][Math.floor(Math.random() * 3)],
|
||||||
|
confidence: Math.floor(Math.random() * 30) + 60,
|
||||||
|
timeHorizon: '1-3天'
|
||||||
|
},
|
||||||
|
medium_term: {
|
||||||
|
trend: ['上涨', '下跌', '震荡'][Math.floor(Math.random() * 3)],
|
||||||
|
confidence: Math.floor(Math.random() * 25) + 55,
|
||||||
|
timeHorizon: '1-2周'
|
||||||
|
},
|
||||||
|
long_term: {
|
||||||
|
trend: ['上涨', '下跌', '震荡'][Math.floor(Math.random() * 3)],
|
||||||
|
confidence: Math.floor(Math.random() * 20) + 50,
|
||||||
|
timeHorizon: '1-3月'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取胜率评估
|
||||||
|
export const fetchWinRateAssessment = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
const winRate = Math.floor(Math.random() * 30) + 40;
|
||||||
|
|
||||||
|
return {
|
||||||
|
win_rate: winRate,
|
||||||
|
risk_reward: +(Math.random() * 2 + 0.5).toFixed(2),
|
||||||
|
backtest_results: {
|
||||||
|
period: '过去3个月',
|
||||||
|
total_trades: Math.floor(Math.random() * 50) + 50,
|
||||||
|
win_trades: Math.floor(winRate / 100 * 100),
|
||||||
|
loss_trades: Math.floor((100 - winRate) / 100 * 100),
|
||||||
|
profit_factor: +(Math.random() * 2 + 0.5).toFixed(2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取技术指标
|
||||||
|
export const fetchTechnicalIndicators = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
return {
|
||||||
|
macd: {
|
||||||
|
value: +(Math.random() * 2 - 1).toFixed(2),
|
||||||
|
signal: +(Math.random() * 2 - 1).toFixed(2),
|
||||||
|
histogram: +(Math.random() * 1 - 0.5).toFixed(2),
|
||||||
|
status: ['金叉', '死叉', '走平'][Math.floor(Math.random() * 3)]
|
||||||
|
},
|
||||||
|
rsi: {
|
||||||
|
value: Math.floor(Math.random() * 40) + 30,
|
||||||
|
status: ['超买', '超卖', '正常'][Math.floor(Math.random() * 3)]
|
||||||
|
},
|
||||||
|
kdj: {
|
||||||
|
k: +(Math.random() * 100).toFixed(2),
|
||||||
|
d: +(Math.random() * 100).toFixed(2),
|
||||||
|
j: +(Math.random() * 100).toFixed(2),
|
||||||
|
status: ['金叉', '死叉', '走平'][Math.floor(Math.random() * 3)]
|
||||||
|
},
|
||||||
|
bollinger: {
|
||||||
|
upper: +(Math.random() * 500 + 2500).toFixed(2),
|
||||||
|
middle: +(Math.random() * 500 + 2000).toFixed(2),
|
||||||
|
lower: +(Math.random() * 500 + 1500).toFixed(2),
|
||||||
|
status: ['突破上轨', '突破下轨', '通道内'][Math.floor(Math.random() * 3)]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
// 配置服务
|
||||||
|
|
||||||
|
// 获取数据源列表
|
||||||
|
export const fetchDataSources = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ id: 1, name: 'Wind', status: 'online', priority: 1, enabled: true },
|
||||||
|
{ id: 2, name: '同花顺', status: 'online', priority: 2, enabled: true },
|
||||||
|
{ id: 3, name: '东方财富', status: 'online', priority: 3, enabled: true },
|
||||||
|
{ id: 4, name: '新浪财经', status: 'offline', priority: 4, enabled: false },
|
||||||
|
{ id: 5, name: 'TQSDK', status: 'online', priority: 5, enabled: true },
|
||||||
|
{ id: 6, name: 'RQData', status: 'online', priority: 6, enabled: true }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存数据源配置
|
||||||
|
export const saveDataSource = async (data: any) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
console.log('保存数据源配置:', data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取AI模型列表
|
||||||
|
export const fetchAIModels = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ id: 1, name: 'DeepSeek', accuracy: '85%', responseTime: '250ms', enabled: true },
|
||||||
|
{ id: 2, name: 'GPT-4', accuracy: '88%', responseTime: '350ms', enabled: false },
|
||||||
|
{ id: 3, name: 'Claude', accuracy: '82%', responseTime: '200ms', enabled: false },
|
||||||
|
{ id: 4, name: '自定义模型', accuracy: '78%', responseTime: '150ms', enabled: false }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存AI模型配置
|
||||||
|
export const saveAIModel = async (data: any) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
console.log('保存AI模型配置:', data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取系统设置
|
||||||
|
export const fetchSystemSettings = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
return {
|
||||||
|
refresh_interval: 30,
|
||||||
|
alert_threshold: 70,
|
||||||
|
backtest_days: 90
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存系统设置
|
||||||
|
export const saveSystemSettings = async (data: any) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
console.log('保存系统设置:', data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
// 推送服务
|
||||||
|
|
||||||
|
// 模拟推送设置存储
|
||||||
|
const pushSettings: Record<string, any> = {
|
||||||
|
'AU': {
|
||||||
|
methods: ['email', 'wechat'],
|
||||||
|
timing: 'realTime',
|
||||||
|
content: ['price', 'trend', 'risk'],
|
||||||
|
price_level: 300
|
||||||
|
},
|
||||||
|
'AG': {
|
||||||
|
methods: ['email'],
|
||||||
|
timing: 'realTime',
|
||||||
|
content: ['price', 'trend'],
|
||||||
|
price_level: 50
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟推送历史存储
|
||||||
|
const pushHistory: any[] = [
|
||||||
|
{ id: 1, timestamp: new Date().toISOString(), method: 'email', content: 'AU价格突破3000', status: 'success' },
|
||||||
|
{ id: 2, timestamp: new Date().toISOString(), method: 'wechat', content: 'AG趋势改变', status: 'success' },
|
||||||
|
{ id: 3, timestamp: new Date().toISOString(), method: 'email', content: 'CU风险预警', status: 'failed' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取推送设置
|
||||||
|
export const fetchPushSettings = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
return pushSettings[symbol] || {
|
||||||
|
methods: ['email'],
|
||||||
|
timing: 'realTime',
|
||||||
|
content: ['price']
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存推送设置
|
||||||
|
export const savePushSettings = async (symbol: string, settings: any) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
pushSettings[symbol] = settings;
|
||||||
|
console.log('保存推送设置:', symbol, settings);
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 测试推送
|
||||||
|
export const testPush = async (method: string, content: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
|
||||||
|
console.log('测试推送:', method, content);
|
||||||
|
|
||||||
|
// 模拟推送成功
|
||||||
|
return { success: true, message: '测试推送成功' };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取推送历史
|
||||||
|
export const fetchPushHistory = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
return pushHistory;
|
||||||
|
};
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
// 风控服务
|
||||||
|
import { generateFutureData, futuresList } from '../utils/mockData';
|
||||||
|
|
||||||
|
// 获取止损建议
|
||||||
|
export const fetchStopLossAdvice = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
const future = futuresList.find(item => item.code === symbol);
|
||||||
|
if (!future) {
|
||||||
|
throw new Error('品种不存在');
|
||||||
|
}
|
||||||
|
const data = generateFutureData(symbol, future.name);
|
||||||
|
|
||||||
|
return {
|
||||||
|
stop_loss_price: data.tradingAdvice.stopLoss,
|
||||||
|
strategy: ['固定止损', '移动止损', '波动率止损'][Math.floor(Math.random() * 3)],
|
||||||
|
reasoning: `基于${data.volatility}波动率和${data.riskLevel}风险等级,建议设置止损位在${data.tradingAdvice.stopLoss.toFixed(2)}`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取仓位建议
|
||||||
|
export const fetchPositionAdvice = async (capital: number, risk_tolerance: string, symbols: string[]) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 400));
|
||||||
|
|
||||||
|
// 根据风险承受能力计算仓位比例
|
||||||
|
const riskMultiplier = risk_tolerance === 'high' ? 0.05 : risk_tolerance === 'medium' ? 0.03 : 0.01;
|
||||||
|
|
||||||
|
const positions = symbols.map(symbol => {
|
||||||
|
const future = futuresList.find(item => item.code === symbol);
|
||||||
|
if (!future) return null;
|
||||||
|
|
||||||
|
const positionPercentage = +(Math.random() * 20 + 5).toFixed(2);
|
||||||
|
const positionAmount = capital * positionPercentage / 100;
|
||||||
|
|
||||||
|
return {
|
||||||
|
symbol,
|
||||||
|
percentage: positionPercentage,
|
||||||
|
amount: positionAmount,
|
||||||
|
reasoning: `基于${risk_tolerance}风险承受能力,建议配置${positionPercentage}%的仓位`
|
||||||
|
};
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
return { positions };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取换月预警
|
||||||
|
export const fetchRolloverAlerts = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
const alerts = [
|
||||||
|
{ symbol: 'RB', expiration_date: '2026-05-15', days_left: 15, recommendation: '建议开始移仓' },
|
||||||
|
{ symbol: 'SC', expiration_date: '2026-06-20', days_left: 30, recommendation: '关注换月' },
|
||||||
|
{ symbol: 'CU', expiration_date: '2026-04-20', days_left: 5, recommendation: '紧急移仓' },
|
||||||
|
{ symbol: 'MA', expiration_date: '2026-05-10', days_left: 10, recommendation: '建议移仓' }
|
||||||
|
];
|
||||||
|
|
||||||
|
return alerts;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取风险评估
|
||||||
|
export const fetchRiskAssessment = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
const future = futuresList.find(item => item.code === symbol);
|
||||||
|
if (!future) {
|
||||||
|
throw new Error('品种不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
const riskLevel = ['低', '中等', '高'][Math.floor(Math.random() * 3)];
|
||||||
|
const volatility = +(Math.random() * 10 + 5).toFixed(2);
|
||||||
|
const liquidity = +(Math.random() * 50 + 50).toFixed(2);
|
||||||
|
|
||||||
|
return {
|
||||||
|
risk_level: riskLevel,
|
||||||
|
volatility: volatility,
|
||||||
|
liquidity: liquidity,
|
||||||
|
reasoning: `该品种风险等级为${riskLevel},波动率为${volatility}%,流动性良好,适合${riskLevel === '高' ? '激进' : riskLevel === '中等' ? '稳健' : '保守'}型投资者`
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// 自选服务
|
||||||
|
import { generateFutureData, futuresList } from '../utils/mockData';
|
||||||
|
|
||||||
|
// 模拟自选列表存储
|
||||||
|
let watchlist: string[] = ['AU', 'AG', 'CU'];
|
||||||
|
|
||||||
|
// 获取自选列表
|
||||||
|
export const fetchWatchlist = async () => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
const watchlistData = watchlist.map(symbol => {
|
||||||
|
const future = futuresList.find(item => item.code === symbol);
|
||||||
|
if (!future) return null;
|
||||||
|
const data = generateFutureData(symbol, future.name);
|
||||||
|
return {
|
||||||
|
symbol: data.code,
|
||||||
|
name: data.name,
|
||||||
|
price: data.currentPrice,
|
||||||
|
change: data.changePercent
|
||||||
|
};
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
return watchlistData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加自选
|
||||||
|
export const addToWatchlist = async (symbol: string, name: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
if (!watchlist.includes(symbol)) {
|
||||||
|
watchlist.push(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { symbol, name };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除自选
|
||||||
|
export const removeFromWatchlist = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
watchlist = watchlist.filter(item => item !== symbol);
|
||||||
|
|
||||||
|
return { symbol };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查自选状态
|
||||||
|
export const checkWatchlistStatus = async (symbol: string) => {
|
||||||
|
// 模拟API请求延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
return {
|
||||||
|
is_in_watchlist: watchlist.includes(symbol)
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,223 @@
|
|||||||
|
// 模拟数据
|
||||||
|
|
||||||
|
// 期货品种列表
|
||||||
|
export const futuresList = [
|
||||||
|
// 金属类
|
||||||
|
{ code: 'AU', name: '金', type: '金属' },
|
||||||
|
{ code: 'AG', name: '银', type: '金属' },
|
||||||
|
{ code: 'CU', name: '铜', type: '金属' },
|
||||||
|
{ code: 'NI', name: '镍', type: '金属' },
|
||||||
|
{ code: 'SN', name: '锡', type: '金属' },
|
||||||
|
{ code: 'AL', name: '铝', type: '金属' },
|
||||||
|
{ code: 'ZN', name: '锌', type: '金属' },
|
||||||
|
|
||||||
|
// 建材类
|
||||||
|
{ code: 'FG', name: '玻璃', type: '建材' },
|
||||||
|
{ code: 'SJS', name: '烧碱', type: '建材' },
|
||||||
|
{ code: 'SCA', name: '纯碱', type: '建材' },
|
||||||
|
{ code: 'JM', name: '焦煤', type: '建材' },
|
||||||
|
{ code: 'RB', name: '螺纹钢', type: '建材' },
|
||||||
|
{ code: 'ALO', name: '氧化铝', type: '建材' },
|
||||||
|
|
||||||
|
// 能源化工类
|
||||||
|
{ code: 'MA', name: '甲醇', type: '能源化工' },
|
||||||
|
{ code: 'PVC', name: 'PVC', type: '能源化工' },
|
||||||
|
{ code: 'FU', name: '燃油', type: '能源化工' },
|
||||||
|
{ code: 'SC', name: '原油', type: '能源化工' },
|
||||||
|
{ code: 'L', name: '橡胶', type: '能源化工' },
|
||||||
|
{ code: 'NR', name: '20号胶', type: '能源化工' },
|
||||||
|
{ code: 'BU', name: '沥青', type: '能源化工' },
|
||||||
|
{ code: 'LU', name: '低硫燃油', type: '能源化工' },
|
||||||
|
|
||||||
|
// 农产品类
|
||||||
|
{ code: 'P', name: '棕榈油', type: '农产品' },
|
||||||
|
|
||||||
|
// 新能源类
|
||||||
|
{ code: 'LC', name: '碳酸锂', type: '新能源' },
|
||||||
|
{ code: 'SI', name: '工业硅', type: '新能源' },
|
||||||
|
{ code: 'PGS', name: '多晶硅', type: '新能源' },
|
||||||
|
|
||||||
|
// 金融类
|
||||||
|
{ code: 'IC', name: '中证500', type: '金融' },
|
||||||
|
{ code: 'IM', name: '中证1000', type: '金融' },
|
||||||
|
{ code: 'IH', name: '上证50', type: '金融' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 生成随机数据的工具函数
|
||||||
|
const generateRandomPrice = (base: number, volatility: number) => {
|
||||||
|
return +(base + (Math.random() - 0.5) * 2 * volatility).toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomChange = () => {
|
||||||
|
return +(Math.random() * 10 - 5).toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomWinRate = () => {
|
||||||
|
return Math.floor(Math.random() * 50) + 30;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomATR = () => {
|
||||||
|
return +(Math.random() * 5 + 0.5).toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomADX = () => {
|
||||||
|
return Math.floor(Math.random() * 60) + 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getADXStatus = (adx: number) => {
|
||||||
|
if (adx < 20) return '无趋势/震荡';
|
||||||
|
if (adx < 40) return '弱趋势';
|
||||||
|
return '强趋势';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTrendDirection = () => {
|
||||||
|
const directions = ['看多', '看空', '观望'];
|
||||||
|
return directions[Math.floor(Math.random() * directions.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTrendStatus = (direction: string) => {
|
||||||
|
if (direction === '看多') return '多头趋势';
|
||||||
|
if (direction === '看空') return '空头趋势';
|
||||||
|
return '震荡';
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomRSI = () => {
|
||||||
|
return Math.floor(Math.random() * 80) + 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成品种详细数据
|
||||||
|
export const generateFutureData = (code: string, name: string) => {
|
||||||
|
const currentPrice = generateRandomPrice(2000, 500);
|
||||||
|
const changePercent = generateRandomChange();
|
||||||
|
const atr = generateRandomATR();
|
||||||
|
const adx = generateRandomADX();
|
||||||
|
const winRate = generateRandomWinRate();
|
||||||
|
|
||||||
|
const trends = {
|
||||||
|
'5MIN': {
|
||||||
|
direction: getTrendDirection(),
|
||||||
|
status: getTrendStatus(getTrendDirection()),
|
||||||
|
rsi: generateRandomRSI()
|
||||||
|
},
|
||||||
|
'30MIN': {
|
||||||
|
direction: getTrendDirection(),
|
||||||
|
status: getTrendStatus(getTrendDirection()),
|
||||||
|
rsi: generateRandomRSI()
|
||||||
|
},
|
||||||
|
'1HOUR': {
|
||||||
|
direction: getTrendDirection(),
|
||||||
|
status: getTrendStatus(getTrendDirection()),
|
||||||
|
rsi: generateRandomRSI()
|
||||||
|
},
|
||||||
|
'1DAY': {
|
||||||
|
direction: getTrendDirection(),
|
||||||
|
status: getTrendStatus(getTrendDirection()),
|
||||||
|
rsi: generateRandomRSI()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const indicators = {
|
||||||
|
macd: ['金叉向上', '死叉向下', '走平'][Math.floor(Math.random() * 3)],
|
||||||
|
rsi: `${generateRandomRSI()}(中性)`,
|
||||||
|
bollinger: ['触及上轨', '触及下轨', '中轨附近'][Math.floor(Math.random() * 3)],
|
||||||
|
kdj: ['金叉向上', '死叉向下', '走平'][Math.floor(Math.random() * 3)]
|
||||||
|
};
|
||||||
|
|
||||||
|
const entry = currentPrice;
|
||||||
|
const stopLoss = entry * (1 - 0.02 * (Math.random() + 0.5));
|
||||||
|
const target = entry * (1 + 0.03 * (Math.random() + 0.5));
|
||||||
|
const resistance = entry * (1 + 0.05 * (Math.random() + 0.5));
|
||||||
|
const support = entry * (1 - 0.05 * (Math.random() + 0.5));
|
||||||
|
|
||||||
|
const overallViews = ['观望', '中线', '多头排列', '空头排列', '震荡'];
|
||||||
|
const overallView = overallViews[Math.floor(Math.random() * overallViews.length)];
|
||||||
|
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
fullName: `${name}-${code}605`,
|
||||||
|
currentPrice,
|
||||||
|
changePercent,
|
||||||
|
winRate,
|
||||||
|
atr,
|
||||||
|
adx,
|
||||||
|
adxStatus: getADXStatus(adx),
|
||||||
|
trends,
|
||||||
|
indicators,
|
||||||
|
tradingAdvice: {
|
||||||
|
entry: +entry.toFixed(2),
|
||||||
|
stopLoss: +stopLoss.toFixed(2),
|
||||||
|
target: +target.toFixed(2),
|
||||||
|
resistance: +resistance.toFixed(2),
|
||||||
|
support: +support.toFixed(2)
|
||||||
|
},
|
||||||
|
riskLevel: ['低', '中等', '高'][Math.floor(Math.random() * 3)],
|
||||||
|
volatility: ['低', '中等', '高'][Math.floor(Math.random() * 3)],
|
||||||
|
overallView,
|
||||||
|
aiAnalysis: `MACD:${indicators.macd} | RSI:${indicators.rsi} | 布林带:${indicators.bollinger}`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成多个品种的概览数据
|
||||||
|
export const generateFuturesOverview = () => {
|
||||||
|
return futuresList.map(item => {
|
||||||
|
const data = generateFutureData(item.code, item.name);
|
||||||
|
return {
|
||||||
|
code: data.code,
|
||||||
|
name: data.name,
|
||||||
|
currentPrice: data.currentPrice,
|
||||||
|
changePercent: data.changePercent,
|
||||||
|
winRate: data.winRate,
|
||||||
|
atr: data.atr,
|
||||||
|
adx: data.adx,
|
||||||
|
adxStatus: data.adxStatus,
|
||||||
|
trends: data.trends,
|
||||||
|
tradingAdvice: data.tradingAdvice,
|
||||||
|
overallView: data.overallView,
|
||||||
|
aiAnalysis: data.aiAnalysis
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 风险预警数据
|
||||||
|
export const riskAlerts = [
|
||||||
|
{ id: 1, title: '原油波动加剧', level: '高', message: '原油价格近期波动较大,建议控制仓位' },
|
||||||
|
{ id: 2, title: '螺纹钢换月提醒', level: '中等', message: '螺纹钢主力合约即将换月,请注意移仓' },
|
||||||
|
{ id: 3, title: '市场情绪偏空', level: '中等', message: '多数品种技术指标显示空头信号,建议谨慎操作' },
|
||||||
|
{ id: 4, title: '铜库存下降', level: '低', message: '铜库存持续下降,可能影响价格走势' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// K线图模拟数据
|
||||||
|
export const generateKlineData = (days: number) => {
|
||||||
|
const data = [];
|
||||||
|
let price = 2000;
|
||||||
|
|
||||||
|
for (let i = 0; i < days; i++) {
|
||||||
|
const open = price;
|
||||||
|
const high = open + Math.random() * 50;
|
||||||
|
const low = open - Math.random() * 50;
|
||||||
|
const close = low + Math.random() * (high - low);
|
||||||
|
const volume = Math.floor(Math.random() * 100000) + 10000;
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
time: new Date(Date.now() - (days - i) * 24 * 60 * 60 * 1000).getTime() / 1000,
|
||||||
|
open: +open.toFixed(2),
|
||||||
|
high: +high.toFixed(2),
|
||||||
|
low: +low.toFixed(2),
|
||||||
|
close: +close.toFixed(2),
|
||||||
|
volume
|
||||||
|
});
|
||||||
|
|
||||||
|
price = close;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// AI市场研判
|
||||||
|
export const aiMarketAnalysis = {
|
||||||
|
overallTrend: '震荡偏弱',
|
||||||
|
keyFactors: ['原油价格波动', '宏观经济数据', '政策面变化'],
|
||||||
|
recommendations: ['控制仓位', '关注原油走势', '做好止损'],
|
||||||
|
confidence: 75
|
||||||
|
};
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in new issue