feat: 迭代03-05 交易记录接入、行情实时、QMT连接配置、data store 标准化

- R-004 QMT连接配置:多配置管理 + 会话头部快捷切换(03-QMT连接配置)
- R-005 WS盘中价格实时更新:服务端中转+缓存+前端轮询(04-WS盘中价格实时更新)
- R-006 策略数据 JSON data store 标准化(store.json/market.json/schema.json)
- R-007 交易记录接入:当日订单+成交单表合并(委托主行+展开成交明细)、时间段查询(今日/本周/本月+手动起止)、费用计算(佣金费率万m_dCommission+最低5元、印花税卖出万5、过户费双向万0.1)
- 架构治理:api 按领域拆分、component 目录、QmtHealthMonitor
This commit is contained in:
2026-09-01 13:21:49 +08:00
parent 5a723d514e
commit bb3f8bd28d
57 changed files with 5244 additions and 397 deletions
+58
View File
@@ -0,0 +1,58 @@
/**
* 服务端 API:行情域(2026-08-31 拆分;2026-09-01 精简)
*
* 端点:
* market-snapshot → 按 code 查询行情缓存(miss 自动补拉在 MarketDataHub 内部,此处只做编排)
* qmt-health → QMT 连接健康检查(读服务端缓存;refresh=true 触发即时探测)
*
* 2026-09-01QMT health 改为「服务端定时探测(5 分钟)+ 缓存」机制(QmtHealthMonitor),
* 前端打开读缓存秒回,点击/悬停传 refresh=true 触发即时探测。
*/
import { resolveActiveBaseUrl } from './common.js';
/** 行情端点方法表 */
export const MARKET_METHODS = new Set([
'market-snapshot',
'qmt-health',
'market-stats', // 临时诊断:WS/REST 通道统计
]);
/**
* 处理行情端点
* @param {string} method
* @param {object} args
* @param {object} runtime { settings, dataSource, marketHub, marketFeed, qmtHealthMonitor }
*/
export async function handleMarket(method, args, { ctx, settings, dataSource, marketHub, marketFeed, qmtHealthMonitor }) {
switch (method) {
case 'market-snapshot': {
const codes = Array.isArray(args.codes) ? args.codes : [];
if (!marketHub) return {};
return await marketHub.getByCodes(codes, { settings, dataSource });
}
case 'qmt-health': {
// QMT 连接健康检查(服务端缓存 + 即时探测,2026-09-01
if (!qmtHealthMonitor) {
return { healthy: null, baseUrl: resolveActiveBaseUrl(settings, dataSource), fromCache: false };
}
if (args.refresh) {
// 前端点击/悬停触发即时探测(刷新缓存)
return await qmtHealthMonitor.probe();
}
// 默认读缓存(秒回)
return qmtHealthMonitor.getStatus();
}
case 'market-stats': {
// 临时诊断:WS 推送 vs REST 拉取 计数(确认 WS 是否生效)
return {
stats: marketHub?.stats ?? null,
cacheSize: marketHub?.size ?? 0,
watchSize: marketHub?.watchCodes?.size ?? 0,
serverTime: Date.now(),
};
}
default:
throw Object.assign(new Error('unknown market method: ' + method), { code: 'not-found' });
}
}