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