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:
+45
-16
@@ -13,11 +13,14 @@
|
||||
* 设计约束:技术约束-001/003、产品约束-001/002/003
|
||||
*/
|
||||
|
||||
import { QmtBridgeRestDataSource } from './data-source/qmt-bridge-rest.js';
|
||||
import { registerSettings } from './settings.js';
|
||||
import { AllocationStorage } from './storage.js';
|
||||
import { PositionManager } from './position/manager.js';
|
||||
import { registerApi } from './api.js';
|
||||
import { QmtBridgeRestDataSource } from './component/QmtBridgeRestDataSource.js';
|
||||
import { registerSettings, resolveStartupConnection } from './settings.js';
|
||||
import { DataStore } from './component/DataStore.js';
|
||||
import { PositionManager } from './component/PositionManager.js';
|
||||
import { registerApi } from './api/index.js';
|
||||
import { MarketDataHub } from './component/MarketDataHub.js';
|
||||
import { MarketFeed } from './component/MarketFeed.js';
|
||||
import { QmtHealthMonitor } from './component/QmtHealthMonitor.js';
|
||||
|
||||
const name = 'one-divine-lot';
|
||||
|
||||
@@ -27,25 +30,49 @@ const inject = ['settings', 'webServer'];
|
||||
async function apply(ctx, config) {
|
||||
const logger = ctx.logger;
|
||||
|
||||
// S2: 数据源(REST 直连 QMT Bridge)
|
||||
const dataSource = new QmtBridgeRestDataSource({
|
||||
baseUrl: config?.qmtBaseUrl,
|
||||
timeoutMs: config?.qmtTimeoutMs,
|
||||
});
|
||||
|
||||
// S3: 设置管理(策略=标签 + 显示开关)
|
||||
// S3: 设置管理(策略=标签 + 显示开关 + QMT 连接配置)
|
||||
const settings = registerSettings(ctx, config);
|
||||
|
||||
// S4: 分仓数据本地存储
|
||||
const storage = new AllocationStorage({
|
||||
// S2: 数据源(REST 直连 QMT Bridge)
|
||||
// R-004(技术约束-008):启动激活地址 = 默认配置 → 上次激活 → 第一条;列表为空回退 cordis qmtBaseUrl(Q4 不迁移)
|
||||
const settingsScope = settings;
|
||||
let startup;
|
||||
try {
|
||||
startup = await resolveStartupConnection(settingsScope, config);
|
||||
} catch (e) {
|
||||
logger.warn('[one-divine-lot] 启动连接解析失败,回退 cordis qmtBaseUrl: ' + e.message);
|
||||
startup = { connection: null, baseUrl: config?.qmtBaseUrl ?? null, source: 'cordis-fallback' };
|
||||
}
|
||||
const dataSource = new QmtBridgeRestDataSource({
|
||||
baseUrl: startup.baseUrl ?? config?.qmtBaseUrl,
|
||||
timeoutMs: config?.qmtTimeoutMs,
|
||||
});
|
||||
logger.info(
|
||||
'[one-divine-lot] QMT 连接激活: ' + (startup.connection ? startup.connection.name + ' (' + startup.connection.baseUrl + ')' : String(startup.baseUrl ?? '(未配置)')) +
|
||||
' [来源: ' + startup.source + ']'
|
||||
);
|
||||
|
||||
// S4: 分仓数据本地存储(R-006:JSON data store,策略为中心)
|
||||
const storage = new DataStore({
|
||||
dataDir: config?.dataDir,
|
||||
});
|
||||
|
||||
// R-005:行情数据(MarketDataHub 缓存 + MarketFeed 获取,页面轮询读取)
|
||||
const marketHub = new MarketDataHub({ logger, dataStore: storage });
|
||||
// 启动时从磁盘加载行情缓存(首屏快速展示,不依赖实盘订阅)
|
||||
marketHub.warmup().catch((e) => logger.warn('[one-divine-lot] 行情预热失败: ' + e.message));
|
||||
const marketFeed = new MarketFeed({ hub: marketHub, runtime: { settings, dataSource }, logger });
|
||||
marketFeed.start(startup.baseUrl ?? config?.qmtBaseUrl);
|
||||
|
||||
// QMT 连接健康检查(服务端定时探测 + 缓存,2026-09-01)
|
||||
const qmtHealthMonitor = new QmtHealthMonitor({ runtime: { settings, dataSource }, logger });
|
||||
qmtHealthMonitor.start();
|
||||
|
||||
// S5: 分仓逻辑(份额分配/查询)
|
||||
const manager = new PositionManager({ dataSource, storage });
|
||||
|
||||
// S6: 服务端 HTTP API
|
||||
registerApi(ctx, { manager, settings });
|
||||
// S6: 服务端 HTTP API(R-004:注入 dataSource 以编排激活热切换)
|
||||
registerApi(ctx, { manager, settings, dataSource, marketHub, marketFeed, qmtHealthMonitor });
|
||||
|
||||
// 启动时可用性检查(日志,不阻塞)
|
||||
dataSource.isAvailable().then((ok) => {
|
||||
@@ -57,6 +84,8 @@ async function apply(ctx, config) {
|
||||
ctx.effect(() => {
|
||||
logger.info('[one-divine-lot] 插件已加载(S1-S6 就绪)');
|
||||
return () => {
|
||||
marketFeed.stop();
|
||||
qmtHealthMonitor.stop();
|
||||
logger.info('[one-divine-lot] 插件已释放');
|
||||
};
|
||||
}, 'one-divine-lot.dispose');
|
||||
|
||||
Reference in New Issue
Block a user