/** * 服务端 API:持仓域(从 api.js 拆分,2026-08-31) * * 端点: * positions → 全量持仓 * positions/orphan-hints → R-018 漏关联软提示:账本活动行 ∩ QMT 快照缺失的 code(只读,不动账本) */ /** 持仓端点方法表 */ export const POSITION_METHODS = new Set([ 'positions', 'positions/orphan-hints', ]); /** * 处理持仓端点 * @param {string} method * @param {object} args * @param {object} runtime { manager, storage, positionSync } */ export async function handlePosition(method, args, { manager, storage, positionSync }) { switch (method) { case 'positions': return await manager.getAllPositions(); case 'positions/orphan-hints': { // R-018 T3:漏关联软提示。账本有活动行(closed/void 双空)但 QMT 快照无此 code → 提示去关联/移出。 // 只读不写(同步机制与账本分界:软提示不自动改账本)。 const snapshot = positionSync && Array.isArray(positionSync.getSnapshot()) ? positionSync.getSnapshot() : null; if (!storage) return []; const holdings = await storage.getCurrentHoldings(); // 全策略当前活动持仓 if (!snapshot) return []; // 快照不可用(从未同步/未注入)→ 不提示(避免误报) const snapshotCodes = new Set(snapshot.map((p) => p.code).filter(Boolean)); return holdings .filter((h) => !snapshotCodes.has(h.code)) .map((h) => ({ holdingId: h.holdingId, strategyId: h.strategyId, code: h.code, shares: h.shares, })); } default: throw Object.assign(new Error('unknown position method: ' + method), { code: 'not-found' }); } }