@dshtrading/api 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1,11 +1,21 @@
1
- import { CRON_MAX, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, ExecutionRecord, NewTaskInput, PIN_MAX, PROMPT_MAX, ScheduleRule, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, TaskPermission, TaskRecord, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, hasOpenExecution, isTaskPermission, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions } from "./tasks-protocol.js";
1
+ import { CRON_MAX, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, ExecutionRecord, NewTaskInput, PIN_MAX, PROMPT_MAX, ScheduleRule, ScheduleSkipRecord, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, TaskPermission, TaskRecord, TaskSkipReason, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, countOpenExecutions, hasOpenExecution, isTaskPermission, isTaskSkipReason, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions } from "./tasks-protocol.js";
2
2
  import { CronSchedule, isValidCron, nextRunAtMs, parseCron } from "./tasks-schedule.js";
3
3
  import { SWAP_SYMBOL_SUFFIX, instrumentFormOf } from "./instrument-form.js";
4
4
  import { Context as CordisContext } from "@deepseek-ai/cordis";
5
5
  //#region src/index.d.ts
6
6
  /** K线周期(Binance 现货/合约 interval 词汇)。 */
7
7
  type Interval = '1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '6h' | '8h' | '12h' | '1d' | '3d' | '1w' | '1M';
8
- /** 最新行情快照(公共数据,无需凭证)。 */
8
+ /**
9
+ * 最新行情快照(公共数据,无需凭证)。
10
+ *
11
+ * **降级派生(2026-10-14)**:数据源的首选取价路径不可用时,连接器可用**同源序列**派生快照
12
+ * (connector-eastmoney 即用当日分钟序列的末根收盘价 + 该序列自带的昨收与名称;2026-10-14
13
+ * 实测其派生价与同刻腾讯报价逐位一致)。此时 `price` 是「最近一根分钟 bar 的收盘」而非逐笔
14
+ * 最新价,滞后以该源的降级策略为界。派生值必须自洽——涨跌幅由同一对 `price`/`prevClose` 推出,
15
+ * 名称与昨收取自同一响应;**拿不到的量宁可缺省**(`volume` 本就可选),不得用窗口合计之类的
16
+ * 近似值冒充当日累计。降级不得掩盖「该标的确实不存在」:`TRADING_SYMBOL_NOT_FOUND` /
17
+ * `TRADING_UNSUPPORTED_SYMBOL` 照实上报,消费方无需区分快照来自直取还是派生。
18
+ */
9
19
  interface Ticker {
10
20
  /** 交易对符号,**市场规范词汇**(docs/symbol-vocabulary.md:crypto=BTCUSDT,us=AAPL,cn=600519.SH,hk=00700.HK)。 */
11
21
  readonly symbol: string;
@@ -466,6 +476,23 @@ interface OrderRequest {
466
476
  readonly marginMode?: MarginMode;
467
477
  /** 缺省/true 时仅模拟,不触碰交易所。实盘还受 @dshtrading/authority 的人工签署授权与 approval 约束 [S4]。 */
468
478
  readonly dryRun?: boolean;
479
+ /**
480
+ * Stable caller-assigned idempotency id for this order intent.
481
+ *
482
+ * Required for live submissions (`dryRun: false`); a dry-run receipt may omit it.
483
+ * Reusing the id with the same normalized request (same venue payload, provider,
484
+ * environment and account) returns the recorded venue receipt instead of
485
+ * submitting a second order; reusing it with a different payload, provider,
486
+ * environment or account is rejected as a conflict and the request is never
487
+ * silently re-parameterised. Only a venue receipt carrying a real non-empty
488
+ * order id is recorded as confirmed — a timeout, storage failure or crash leaves
489
+ * the intent unresolved and nothing is resubmitted automatically.
490
+ *
491
+ * The venue-facing client order key (`clOrdId` / `client_order_id` / `cOID` /
492
+ * `remark` / `user_mark`) is derived from this id inside the connector and is
493
+ * never surfaced: this id is the only handle callers pass in and read back.
494
+ */
495
+ readonly intentId?: string;
469
496
  }
470
497
  /** 订单回执/状态。 */
471
498
  interface Order {
@@ -549,6 +576,77 @@ interface InstrumentRef {
549
576
  readonly assetClass?: InstrumentAssetClass;
550
577
  readonly contract?: InstrumentContract;
551
578
  }
579
+ /** 港股通单日持股快照(东财 RPT_MUTUAL_STOCK_HOLDRANKS 口径)。 */
580
+ interface SouthboundHoldingPoint {
581
+ /** 交易日(UTC 当日 00:00 的 epoch ms;与日 K 的 openTime 同口径便于对齐)。 */
582
+ readonly date: number;
583
+ /** 持股比例(百分比数值,如 11.9 表示 11.9%)。来源字段 HOLD_SHARES_RATIO(占港股已发行股本)。 */
584
+ readonly holdRatio: number;
585
+ /** 持股数量(股)。 */
586
+ readonly holdShares: number;
587
+ /** 持股市值(HKD)。 */
588
+ readonly holdMarketCap: number;
589
+ }
590
+ /** 港股通持股历史(按交易日升序,旧→新,已按日去重)。 */
591
+ interface SouthboundHoldingHistory {
592
+ /** 市场规范词汇 symbol(如 00700.HK)。 */
593
+ readonly symbol: string;
594
+ /** 序列升序;同一交易日至多一条。标的不在港股通范围时为空数组(不是抛错)。 */
595
+ readonly points: readonly SouthboundHoldingPoint[];
596
+ }
597
+ /**
598
+ * 当日累计主动买盘快照(cn 行情行盘口推断口径,2026-10-13)。
599
+ *
600
+ * **口径**:`outerLots`/`innerLots` 是行情源按「成交价对盘口的主动方向」推断的当日累计
601
+ * 外盘/内盘(外盘 = 主动买、内盘 = 主动卖),**不是交易所官方逐笔方向**;涨跌停一字板与
602
+ * 对倒(自成交)交易日读数会系统性失真。占比一律按「÷当日总量」口径。
603
+ * `totalLots` 与 `outerLots + innerLots` 存在残差(未归向成交:集合竞价与价间成交计入总量
604
+ * 但不计入外/内盘),实测 2026-10-13 为 002714 12/121808 手(0.0099%)、600519
605
+ * 45/7154 手(0.629%)——残差**不是**固定量级,且**不据它修正读数**,源读数原样返回。
606
+ */
607
+ interface ActiveBuySnapshot {
608
+ /** 市场规范词汇 symbol(如 002714.SZ)。 */
609
+ readonly symbol: string;
610
+ /** 快照所属交易日 `YYYY-MM-DD`(源字段 30,交易所本地墙钟)。 */
611
+ readonly date: string;
612
+ /** 快照时刻 `HH:MM:SS`(源字段 30,交易所本地墙钟)。 */
613
+ readonly time: string;
614
+ /** 当日累计总量(手)。 */
615
+ readonly totalLots: number;
616
+ /** 当日累计外盘 = 主动买(手)。 */
617
+ readonly outerLots: number;
618
+ /** 当日累计内盘 = 主动卖(手)。 */
619
+ readonly innerLots: number;
620
+ /** 主动买占比 `outer/total*100`(2 位小数)。 */
621
+ readonly buySharePct: number;
622
+ /** 净主动买占比 `(outer-inner)/total*100`(2 位小数,负值 = 净主动卖)。 */
623
+ readonly netSharePct: number;
624
+ /** 涨停价(源字段 47;指数/ETF 等无涨跌停的标的不带此字段)。 */
625
+ readonly limitUp?: number;
626
+ /** 跌停价(源字段 48;同上缺省)。 */
627
+ readonly limitDown?: number;
628
+ /** 数据源标识(如 'qt.gtimg.cn')。 */
629
+ readonly source: string;
630
+ /** 取数时刻,ISO 8601 带偏移(交易所本地墙钟,如 2026-10-13T09:53:12+08:00)。 */
631
+ readonly fetchedAt: string;
632
+ }
633
+ /**
634
+ * 连接器自我申报的 K 线能力(2026-10-15 跨源 K 线路由):对自己**能诚实服务**的
635
+ * (周期, 请求深度) 的声明。深度必须来自本连接器自己的实证,不借别家的数字。
636
+ *
637
+ * `maxBars` 是该周期能承接的 `limit` 上限,**不是返回根数保证**:
638
+ * - `limit <= maxBars`:请求在本源自己的语义下已被诚实服务——返回根数以本源自己的
639
+ * 取数窗口/上游上限为界(如窗口型源的 5 个交易日),但不得因为请求更大而静默降级
640
+ * 到更小的窗口或更浅的历史;
641
+ * - `limit > maxBars`:本源结构性不足——上游会静默截到更少根数、忽略该参数,
642
+ * 或根本没有该周期的通道。
643
+ *
644
+ * 方法缺席 = **未声明**,不是「不支持」:消费方照旧可直接调用,错误码才是判据。
645
+ */
646
+ interface KlineCapability {
647
+ readonly interval: Interval;
648
+ readonly maxBars: number;
649
+ }
552
650
  /**
553
651
  * 行情服务契约:由市场连接器实现,注册到按市场命名空间的 ctx 键(如 ctx.tradingCrypto)。
554
652
  * 符号词汇(2026-08-31 规范,docs/guides/symbol-vocabulary.md):入参接受市场规范形与连接器原生形,
@@ -557,7 +655,29 @@ interface InstrumentRef {
557
655
  interface MarketDataService {
558
656
  getTicker(symbol: string): Promise<Ticker>;
559
657
  getKlines(symbol: string, interval: Interval, limit?: number): Promise<Kline[]>;
658
+ /**
659
+ * K 线能力声明(可选,2026-10-15 跨源 K 线路由;语义见 KlineCapability):本源能诚实
660
+ * 服务的 (周期, 请求深度) 清单。桥据它做跨源解析——active 覆盖请求就用 active,只有
661
+ * active 结构性不足时才换同市场其它已注册源——并把同市场全部注册项的并集上报客户端。
662
+ * 可选方法:未声明的连接器缺席,桥退回「按 TRADING_UNSUPPORTED_INTERVAL 错误码兜底」
663
+ * 路径(行为与不声明前一致)。
664
+ */
665
+ klineCapabilities?(): readonly KlineCapability[];
560
666
  subscribeTicker(symbol: string, cb: (ticker: Ticker) => void): Disposable;
667
+ /**
668
+ * 批量最新报价(GUI 自选/盘中列表每拍取价用,2026-10-14):一次请求取多只标的,
669
+ * 免掉「N 只标的 N 次请求」。键**必须是入参里的原字符串**(调用方按它一一对应),
670
+ * 值为该标的的行情快照(`Ticker.symbol` 仍是市场规范形)。
671
+ *
672
+ * 语义约定(调用方与实现共同遵守):
673
+ * - 只返回**确实拿到**的标的:未收录/无法解析的符号不出现在结果里,由调用方回落
674
+ * 到 `getTicker` 单取(保住各符号自己的错误码),故实现**不得**为凑齐入参造假行;
675
+ * - 整批取数失败(网络/上游故障)**应抛出**,调用方按整批失败上报,不做 N 次重试;
676
+ * - 单次请求的标的数由调用方裁剪(桥侧 MAX_SYMBOLS),实现无需自行分片。
677
+ *
678
+ * 可选方法:数据源无原生批量端点的市场不实现,调用方自动回落逐只 `getTicker`。
679
+ */
680
+ getTickers?(symbols: string[]): Promise<Record<string, Ticker>>;
561
681
  /**
562
682
  * 查询本市场/交易所支持的全部标的名册(动态全集,Issue #15)。
563
683
  * 输出 `symbol` 一律市场规范词汇(docs/guides/symbol-vocabulary.md),形态由符号后缀承载
@@ -599,6 +719,24 @@ interface MarketDataService {
599
719
  * 可选方法:无公共逐笔端点的数据源(腾讯沪深行情行)不实现。
600
720
  */
601
721
  getRecentTrades?(symbol: string, limit?: number): Promise<TradeTick[]>;
722
+ /**
723
+ * 港股通持股历史(GUI「港股通持股比例」副图用,2026-10-13):日频序列,
724
+ * 升序、按交易日去重。可选方法:无该数据端点的数据源不实现(当前仅
725
+ * connector-eastmoney 的 hk 实例实现);标的不在港股通范围时返回空 points
726
+ * (**空 ≠ 0**,消费方隐藏副图而非画零线),上游失败则抛错。
727
+ * 入参接受规范形与连接器原生形,输出 `symbol` 一律市场规范词汇。
728
+ */
729
+ getSouthboundHoldings?(symbol: string): Promise<SouthboundHoldingHistory>;
730
+ /**
731
+ * 当日累计主动买盘快照(外盘/内盘/买占比/净买占比,cn 专用,2026-10-13)。
732
+ * 可选方法:仅 cn 数据源实现(腾讯行情行的盘口推断口径,**非交易所官方逐笔方向**);
733
+ * 涨跌停一字板与对倒交易日读数失真。hk 等无该字段的市场**方法缺席**——消费方据此
734
+ * 降级(隐藏该面板),**不回退成 0**:缺席表示「无此读数」,不是「主动买为 0」。
735
+ * 读数非法(总量 <= 0、外盘/内盘字段缺失或非有限)时抛 TRADING_EXCHANGE_ERROR,
736
+ * 绝不补 0、绝不返回 NaN。
737
+ * 入参接受规范形与连接器原生形,输出 `symbol` 一律市场规范词汇。
738
+ */
739
+ getActiveBuySnapshot?(symbol: string): Promise<ActiveBuySnapshot>;
602
740
  }
603
741
  /**
604
742
  * 杠杆设置请求(合约交易语义,P7;仅 `form=perp` 的标的可传)。
@@ -681,6 +819,15 @@ type TradingErrorCode =
681
819
  'TRADING_NO_TRADE_SERVICE' |
682
820
  /** 该市场注册了交易连接器,但路由选中的数据 provider 没有交易面(需设 tradeProvider;≠ 未安装)。 */
683
821
  'TRADING_TRADE_PROVIDER_NOT_ROUTED' | 'TRADING_UNSUPPORTED_SYMBOL' | 'TRADING_UNSUPPORTED_INTERVAL' |
822
+ /**
823
+ * 请求到达了上游、上游答了,但没有这个标的(HTTP 404、400 + `label` 以 `INVALID_` 开头,
824
+ * 或 200 但没有任何可用行)——与 `TRADING_UNSUPPORTED_SYMBOL`(本地就判定这个形态不支持、
825
+ * 零请求)区分:这里是「上游说查不到」,消费方不该当基础设施抖动去重试。
826
+ * 8 个连接器已按此语义实际使用该码(akshare / eastmoney / finnhub / fmp / longbridge /
827
+ * polygon / tushare / ccxt 的行级判空与 404 映射),此前只是漏进了本词汇表(类型层缺口,
828
+ * 与 `TRADING_UPSTREAM_ERROR` 曾经的缺口同形)。
829
+ */
830
+ 'TRADING_SYMBOL_NOT_FOUND' |
684
831
  /** 凭证缺失或无效(ctx.credentials 引用解析失败 [S4])。 */
685
832
  'TRADING_CREDENTIALS_MISSING' | 'TRADING_AUTH_FAILED' | 'TRADING_RATE_LIMITED' | 'TRADING_NETWORK' |
686
833
  /**
@@ -701,7 +848,18 @@ type TradingErrorCode =
701
848
  /** approval 被拒/无应答(headless fail-closed [S4])。 */
702
849
  'TRADING_APPROVAL_DENIED' |
703
850
  /** 本次为 dry-run 模拟结果(非故障语义)。 */
704
- 'TRADING_DRY_RUN' | 'TRADING_EXCHANGE_ERROR' | 'TRADING_UNKNOWN';
851
+ 'TRADING_DRY_RUN' |
852
+ /** Order intents(实盘幂等台账):实盘请求缺稳定 `intentId`(dry-run 可缺省)。 */
853
+ 'TRADING_INTENT_REQUIRED' |
854
+ /** Order intents:同一 `intentId` 已被不同规范载荷/provider/环境/账户占用——拒绝,不自动改参数。 */
855
+ 'TRADING_INTENT_CONFLICT' |
856
+ /**
857
+ * Order intents:该 `intentId` 已有持久记录(已提交或结局未知)而**尚无** venue 回执。
858
+ * 明确告知「未知/在飞」,绝不自动重发;推进只能靠人工或读对账。
859
+ */
860
+ 'TRADING_INTENT_UNKNOWN' |
861
+ /** Order intents:台账写盘失败——本次不调用 venue(宁可不发,也不发一笔没有持久记录的实盘单)。 */
862
+ 'TRADING_INTENT_STORE_FAILED' | 'TRADING_EXCHANGE_ERROR' | 'TRADING_UNKNOWN';
705
863
  /** 结构化错误载体(实现方在 Error 上附加该形状,或直接以 code 抛出)。 */
706
864
  interface TradingError {
707
865
  readonly code: TradingErrorCode;
@@ -762,6 +920,8 @@ declare module '@deepseek-ai/cordis' {
762
920
  tradingFlashFeed: FlashFeedService;
763
921
  /** 宏观/利率源(@dshtrading/connector-jin10 提供;缺席 = 未安装金十连接器)。 */
764
922
  tradingMacroFeed: MacroFeedService;
923
+ /** 预测市场源(@dshtrading/connector-polymarket 提供;缺席 = 未安装预测市场连接器)。 */
924
+ tradingPredictionFeed: PredictionFeedService;
765
925
  }
766
926
  }
767
927
  /**
@@ -932,6 +1092,93 @@ interface MacroFeedService {
932
1092
  /** 央行最新利率(全量,客户端按地区过滤)。 */
933
1093
  listRates(): Promise<readonly MacroRateEntry[]>;
934
1094
  }
1095
+ /**
1096
+ * 预测市场档位条目(2026-10-11 Polymarket 接入)。
1097
+ *
1098
+ * 标签与概率均来自上游 `groupItemTitle` / `outcomePrices[0]`;`key` 是归一化后的
1099
+ * 稳定档位标识(上游标签在大小写与 `+` 上会漂移——实测 `No change` / `No Change`、
1100
+ * `50+ bps decrease` / `50 bps decrease` 并存,按原文匹配会随会议换 slug 静默失效)。
1101
+ */
1102
+ interface PredictionOutcomeBucket {
1103
+ /** 稳定档位键(如 `no_change` / `inc_25` / `dec_50plus`;未识别形态 = `raw:<原文>`)。 */
1104
+ readonly key: string;
1105
+ /** 上游档位标签原文(展示用,不做改写)。 */
1106
+ readonly label: string;
1107
+ /** 对应利率变动(bps;降息为负)。未识别形态 = undefined(不猜)。 */
1108
+ readonly changeBps?: number | undefined;
1109
+ /** 隐含概率 = 上游 `outcomePrices[0]`(gamma 与 CLOB midpoint 实测 15/15 完全相等)。 */
1110
+ readonly probability: number;
1111
+ /** 最优买价(结算后上游为 null → 缺省)。 */
1112
+ readonly bestBid?: number | undefined;
1113
+ /** 最优卖价。 */
1114
+ readonly bestAsk?: number | undefined;
1115
+ /** 价差(bestAsk − bestBid;任一端缺失则缺省)。 */
1116
+ readonly spread?: number | undefined;
1117
+ /** 盘口深度(上游 `liquidityNum`,美元)。 */
1118
+ readonly liquidity?: number | undefined;
1119
+ /** 累计成交额(上游 `volumeNum`,美元)。 */
1120
+ readonly volume?: number | undefined;
1121
+ /** 24 小时成交额(上游 `volume24hr`,美元)。 */
1122
+ readonly volume24h?: number | undefined;
1123
+ /** 最小报价粒度(上游 `orderPriceMinTickSize`)。 */
1124
+ readonly tickSize?: number | undefined;
1125
+ /**
1126
+ * 是否仍可下单(上游 market 级 `acceptingOrders`)。**不用 `active` 判断**:
1127
+ * 实测结算后 `active` 仍为 true,只有 `closed`/`acceptingOrders` 会翻转。
1128
+ */
1129
+ readonly acceptingOrders: boolean;
1130
+ /** 该档位市场是否已结算(上游 market 级 `closed`)。 */
1131
+ readonly closed: boolean;
1132
+ /** 与最近一条本地快照的差值(无快照/首次采样 = undefined,绝不填 0 冒充无变动)。 */
1133
+ readonly changeSincePrevious?: number | undefined;
1134
+ }
1135
+ /** 一场 FOMC 决议会议(会议时间 + 档位集合 + 健康标记)。 */
1136
+ interface PredictionMeeting {
1137
+ /** 上游 event id(去重键;slug 带随机后缀,不可作标识)。 */
1138
+ readonly id: string;
1139
+ readonly slug: string;
1140
+ readonly title: string;
1141
+ /** 决议结果窗口结束(上游 event `endDate`,ISO 8601 UTC)。 */
1142
+ readonly endDate: string;
1143
+ /** FOMC 会议日程(从上游 description 解析,如 `October 27-28, 2026`;未解析到 = 缺省)。 */
1144
+ readonly meetingWindow?: string | undefined;
1145
+ readonly closed: boolean;
1146
+ /** 档位集合,按利率变动从低到高排序(未知形态排末位)。 */
1147
+ readonly buckets: readonly PredictionOutcomeBucket[];
1148
+ /** 各档概率之和(健康检查;实测正常区间约 [0.98, 1.03],不假设严格等于 1)。 */
1149
+ readonly probabilitySum: number;
1150
+ /**
1151
+ * 数据质量提示(空 = 全部健康)。桥与面板只做展示,不据此改写概率。
1152
+ * 例:`probability-sum-out-of-band`、`probability-out-of-range`、`bucket-quote-missing`、
1153
+ * `bucket-unrecognized-label`。
1154
+ */
1155
+ readonly degraded: readonly string[];
1156
+ }
1157
+ /**
1158
+ * 预测市场快照(一次取数的完整结果)。
1159
+ *
1160
+ * `fetchedAt` 是**本进程的取数时刻**——上游只给 `updatedAt` 级别的事件时间,
1161
+ * 没有响应级时间戳,所以数据时间戳由取数侧记录(单调可信)。
1162
+ */
1163
+ interface PredictionFeed {
1164
+ /** 取数时刻(ISO 8601 UTC;数据时间戳的唯一来源)。 */
1165
+ readonly fetchedAt: string;
1166
+ readonly meetings: readonly PredictionMeeting[];
1167
+ }
1168
+ /**
1169
+ * 预测市场源契约(2026-10-11 Polymarket 接入,v1 只覆盖 FOMC 决议路径):
1170
+ * host 平面由 connector-polymarket provide `tradingPredictionFeed`,GUI 面板经桥
1171
+ * `/dshtrading/api/prediction/*` 消费;服务缺席 = 未安装/未启用该数据源 →
1172
+ * 消费方报 TRADING_NOT_IMPLEMENTED,绝不把「没有数据源」伪装成「没有数据」。
1173
+ *
1174
+ * 发现规则与概率口径以 spikes/impl-polymarket/EVIDENCE.md 为唯一判据:
1175
+ * `GET /events?series_id=35` → 系列校验 → 标题正则 → 形状 → 噪声排除 → 去重/排序;
1176
+ * 概率取 gamma `outcomePrices[0]`(与 CLOB midpoint 数值等价,单请求可取全量)。
1177
+ */
1178
+ interface PredictionFeedService {
1179
+ /** 当前 FOMC 决议路径全部会议(含已结算;按 endDate 升序)。 */
1180
+ listFomcMeetings(): Promise<PredictionFeed>;
1181
+ }
935
1182
  /** 新闻聚合器注册表契约(Issue #37,router 插件提供)。 */
936
1183
  interface TradingNewsRegistry {
937
1184
  register(market: string, aggregator: NewsAggregator): () => void;
@@ -939,4 +1186,4 @@ interface TradingNewsRegistry {
939
1186
  markets(): string[];
940
1187
  }
941
1188
  //#endregion
942
- export { AccountBalance, AggregateNewsOptions, AggregateNewsResult, AuctionSnapshot, BuybackItem, CRON_MAX, CompanyProfile, type CordisContext, CronSchedule, CryptoFundamentals, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, DerivativesData, DerivativesHistory, DerivativesPoint, Disposable, DividendItem, DragonTigerItem, EXECUTION_HISTORY_LIMIT, ExecutionRecord, FinancialCell, FinancialIndicatorRow, FinancialReportGroup, FinancialReportMatrix, FlashFeedService, ForecastSummary, FundamentalsPackage, HolderNumSummary, IAccount, InsiderTradeItem, InstitutionalHoldingItem, InstrumentAssetClass, InstrumentContract, InstrumentForm, InstrumentRef, Interval, Kline, LeverageSetting, LimitUpPoolItem, MacroCalendarEntry, MacroFeedService, MacroRateEntry, MainOperationSegment, MarginMode, MarketDataRegistration, MarketDataRegistry, MarketDataService, MarketRouterService, NewTaskInput, NewsAggregator, NewsItem, OperatingEfficiency, Order, OrderRequest, OrderSide, OrderStatus, OrderType, Orderbook, OrderbookLevel, PIN_MAX, PROMPT_MAX, Position, PositionSide, ResearchReportItem, SWAP_SYMBOL_SUFFIX, ScheduleRule, SetLeverageRequest, ShareholderItem, SplitItem, StockFundamentals, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, TaskPermission, TaskRecord, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, Ticker, TradeFill, TradeRegistration, TradeRegistry, TradeService, TradeTick, TradingError, TradingErrorCode, TradingNewsRegistry, hasOpenExecution, instrumentFormOf, isTaskPermission, isValidCron, nextRunAtMs, parseCron, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
1189
+ export { AccountBalance, ActiveBuySnapshot, AggregateNewsOptions, AggregateNewsResult, AuctionSnapshot, BuybackItem, CRON_MAX, CompanyProfile, type CordisContext, CronSchedule, CryptoFundamentals, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, DerivativesData, DerivativesHistory, DerivativesPoint, Disposable, DividendItem, DragonTigerItem, EXECUTION_HISTORY_LIMIT, ExecutionRecord, FinancialCell, FinancialIndicatorRow, FinancialReportGroup, FinancialReportMatrix, FlashFeedService, ForecastSummary, FundamentalsPackage, HolderNumSummary, IAccount, InsiderTradeItem, InstitutionalHoldingItem, InstrumentAssetClass, InstrumentContract, InstrumentForm, InstrumentRef, Interval, Kline, KlineCapability, LeverageSetting, LimitUpPoolItem, MacroCalendarEntry, MacroFeedService, MacroRateEntry, MainOperationSegment, MarginMode, MarketDataRegistration, MarketDataRegistry, MarketDataService, MarketRouterService, NewTaskInput, NewsAggregator, NewsItem, OperatingEfficiency, Order, OrderRequest, OrderSide, OrderStatus, OrderType, Orderbook, OrderbookLevel, PIN_MAX, PROMPT_MAX, Position, PositionSide, PredictionFeed, PredictionFeedService, PredictionMeeting, PredictionOutcomeBucket, ResearchReportItem, SWAP_SYMBOL_SUFFIX, ScheduleRule, ScheduleSkipRecord, SetLeverageRequest, ShareholderItem, SouthboundHoldingHistory, SouthboundHoldingPoint, SplitItem, StockFundamentals, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, TaskPermission, TaskRecord, TaskSkipReason, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, Ticker, TradeFill, TradeRegistration, TradeRegistry, TradeService, TradeTick, TradingError, TradingErrorCode, TradingNewsRegistry, countOpenExecutions, hasOpenExecution, instrumentFormOf, isTaskPermission, isTaskSkipReason, isValidCron, nextRunAtMs, parseCron, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { CRON_MAX, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, hasOpenExecution, isTaskPermission, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions } from "./tasks-protocol.js";
1
+ import { CRON_MAX, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, countOpenExecutions, hasOpenExecution, isTaskPermission, isTaskSkipReason, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions } from "./tasks-protocol.js";
2
2
  import { isValidCron, nextRunAtMs, parseCron } from "./tasks-schedule.js";
3
3
  import { SWAP_SYMBOL_SUFFIX, instrumentFormOf } from "./instrument-form.js";
4
- export { CRON_MAX, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, SWAP_SYMBOL_SUFFIX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, hasOpenExecution, instrumentFormOf, isTaskPermission, isValidCron, nextRunAtMs, parseCron, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
4
+ export { CRON_MAX, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, SWAP_SYMBOL_SUFFIX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, countOpenExecutions, hasOpenExecution, instrumentFormOf, isTaskPermission, isTaskSkipReason, isValidCron, nextRunAtMs, parseCron, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
@@ -33,6 +33,12 @@ declare const DEFAULT_TASK_AGENT_PRESET: "master";
33
33
  * 执行 /permission——缺省会话回退宿主默认(read-only),拿不到写入。
34
34
  */
35
35
  declare const DEFAULT_TASK_PERMISSION: TaskPermission;
36
+ /**
37
+ * 全局在飞执行容量上限的保守缺省:同一时刻最多几条真实 dsh 会话在跑。
38
+ * 每个在飞执行都是一条消耗 API 额度的真实会话,无上限时 cron 同时到点会无界扇出;
39
+ * 4 允许少量日常任务并行,又不给宿主放大出容量压力(服务 opts 可覆盖)。
40
+ */
41
+ declare const DEFAULT_MAX_INFLIGHT_EXECUTIONS = 4;
36
42
  /** 权限等级比较:高于会话默认的钉住权限必须经人工确认才能运行。 */
37
43
  declare function permissionRank(permission: TaskPermission): number;
38
44
  /** 是否为已知权限预设 id。 */
@@ -53,6 +59,12 @@ interface ExecutionRecord {
53
59
  error: string | undefined;
54
60
  /** 本次执行的触发来源。 */
55
61
  trigger: 'cron' | 'manual';
62
+ /**
63
+ * 未结算期间的侦查诊断:为什么这条执行还开着(会话读取失败、会话空闲且历史
64
+ * 无 turn/end、等待收敛窗口等)。只在内容变化时落盘,避免每轮轮询写放大;
65
+ * 结算时清空。它让「读取异常导致长期 pending」在快照上留痕而不是静默。
66
+ */
67
+ note?: string;
56
68
  }
57
69
  /**
58
70
  * 每任务保留的执行历史上限:新执行开始时裁掉最旧的已结算记录,账本体积与
@@ -64,6 +76,28 @@ declare const EXECUTION_HISTORY_LIMIT = 20;
64
76
  * 未结算(运行中)的执行永不裁剪:Host 监视与重启恢复都依赖活跃记录。
65
77
  */
66
78
  declare function retainRecentExecutions(executions: readonly ExecutionRecord[]): ExecutionRecord[];
79
+ /**
80
+ * 定时触发点被跳过的结构化原因(cron 跳过不补跑,但要说明为什么)。
81
+ *
82
+ * `registry-unavailable` / `gateway-unavailable` 是补偿用尽原因(2026-10-14
83
+ * 停机补跑修复):宿主开机窗口内(workspace 域 `rebuildEntities()` 未跑完、
84
+ * 名册 `list()` 抛错)或网关目标服务未激活完时,起跑失败不消费触发点,由后续
85
+ * tick 有界重试;重试用尽才消费触发点并以此二值说明「这个触发点为什么最终没跑」。
86
+ */
87
+ declare const TASK_SKIP_REASONS: readonly ["permission-pending", "capacity", "already-running", "registry-unavailable", "gateway-unavailable"];
88
+ /** 单个跳过原因。 */
89
+ type TaskSkipReason = (typeof TASK_SKIP_REASONS)[number];
90
+ /** 是否为已知跳过原因(磁盘归一化用)。 */
91
+ declare function isTaskSkipReason(value: unknown): value is TaskSkipReason;
92
+ /** 一次被跳过的定时触发点:到点没跑、以及为什么。 */
93
+ interface ScheduleSkipRecord {
94
+ /** 记录时刻(ms epoch)。 */
95
+ at: number;
96
+ /** 被跳过的那个触发点(原 nextRunAt,ms epoch)。 */
97
+ triggerPoint: number;
98
+ /** 结构化原因。 */
99
+ reason: TaskSkipReason;
100
+ }
67
101
  /** 挂在任务上的定时规则;Host 调度器在 nextRunAt 到期时触发。 */
68
102
  interface ScheduleRule {
69
103
  /** 是否已启用。 */
@@ -74,6 +108,11 @@ interface ScheduleRule {
74
108
  nextRunAt: number | undefined;
75
109
  /** 最近一次定时触发点的时刻(ms epoch)。 */
76
110
  lastTriggeredAt: number | undefined;
111
+ /**
112
+ * 最近一次被跳过的触发点(权限门/容量/已有执行/补偿用尽);正常起跑不覆盖
113
+ * 历史记录。补偿用尽的触发点已推进排期,不滞留。
114
+ */
115
+ lastSkip?: ScheduleSkipRecord;
77
116
  }
78
117
  /** 一条定时任务。 */
79
118
  interface TaskRecord {
@@ -129,6 +168,8 @@ interface TaskUpdatePatch {
129
168
  declare function permissionPending(task: TaskRecord, sessionDefaultPermission: TaskPermission): boolean;
130
169
  /** 任务是否还有未结算的执行(同一任务不并发执行)。 */
131
170
  declare function hasOpenExecution(task: TaskRecord): boolean;
171
+ /** 全部任务上未结算执行的总数(全局在飞容量的判据)。 */
172
+ declare function countOpenExecutions(tasks: readonly TaskRecord[]): number;
132
173
  /** 调度器快照(Host 独占字段,浏览器只读)。 */
133
174
  interface TasksSchedulerSnapshot {
134
175
  timeZone: string;
@@ -194,4 +235,4 @@ declare function parseTasksAction(value: unknown): TasksAction | undefined;
194
235
  /** 校验动作信封;非法返回 undefined。 */
195
236
  declare function parseTasksEnvelope(value: unknown): TasksActionEnvelope | undefined;
196
237
  //#endregion
197
- export { CRON_MAX, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, ExecutionRecord, NewTaskInput, PIN_MAX, PROMPT_MAX, ScheduleRule, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, TaskPermission, TaskRecord, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, hasOpenExecution, isTaskPermission, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
238
+ export { CRON_MAX, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, ExecutionRecord, NewTaskInput, PIN_MAX, PROMPT_MAX, ScheduleRule, ScheduleSkipRecord, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, TaskPermission, TaskRecord, TaskSkipReason, TaskUpdatePatch, TasksAction, TasksActionEnvelope, TasksSchedulerSnapshot, TasksSnapshot, countOpenExecutions, hasOpenExecution, isTaskPermission, isTaskSkipReason, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
@@ -35,6 +35,12 @@ const DEFAULT_TASK_AGENT_PRESET = "master";
35
35
  * 执行 /permission——缺省会话回退宿主默认(read-only),拿不到写入。
36
36
  */
37
37
  const DEFAULT_TASK_PERMISSION = "workspace-write";
38
+ /**
39
+ * 全局在飞执行容量上限的保守缺省:同一时刻最多几条真实 dsh 会话在跑。
40
+ * 每个在飞执行都是一条消耗 API 额度的真实会话,无上限时 cron 同时到点会无界扇出;
41
+ * 4 允许少量日常任务并行,又不给宿主放大出容量压力(服务 opts 可覆盖)。
42
+ */
43
+ const DEFAULT_MAX_INFLIGHT_EXECUTIONS = 4;
38
44
  /** 权限等级比较:高于会话默认的钉住权限必须经人工确认才能运行。 */
39
45
  function permissionRank(permission) {
40
46
  return TASK_PERMISSIONS.indexOf(permission);
@@ -59,6 +65,25 @@ function retainRecentExecutions(executions) {
59
65
  const keepSettled = Math.max(20 - open.length, 0);
60
66
  return [...settled.slice(Math.max(settled.length - keepSettled, 0)), ...open];
61
67
  }
68
+ /**
69
+ * 定时触发点被跳过的结构化原因(cron 跳过不补跑,但要说明为什么)。
70
+ *
71
+ * `registry-unavailable` / `gateway-unavailable` 是补偿用尽原因(2026-10-14
72
+ * 停机补跑修复):宿主开机窗口内(workspace 域 `rebuildEntities()` 未跑完、
73
+ * 名册 `list()` 抛错)或网关目标服务未激活完时,起跑失败不消费触发点,由后续
74
+ * tick 有界重试;重试用尽才消费触发点并以此二值说明「这个触发点为什么最终没跑」。
75
+ */
76
+ const TASK_SKIP_REASONS = [
77
+ "permission-pending",
78
+ "capacity",
79
+ "already-running",
80
+ "registry-unavailable",
81
+ "gateway-unavailable"
82
+ ];
83
+ /** 是否为已知跳过原因(磁盘归一化用)。 */
84
+ function isTaskSkipReason(value) {
85
+ return typeof value === "string" && TASK_SKIP_REASONS.includes(value);
86
+ }
62
87
  /** 任务是否处于权限确认门待确认状态(定时与手动运行都拒绝)。 */
63
88
  function permissionPending(task, sessionDefaultPermission) {
64
89
  return permissionRank(task.permission ?? sessionDefaultPermission) > permissionRank(sessionDefaultPermission) && task.permissionConfirmedAt === void 0;
@@ -67,6 +92,12 @@ function permissionPending(task, sessionDefaultPermission) {
67
92
  function hasOpenExecution(task) {
68
93
  return task.executions.some((execution) => execution.endedAt === void 0);
69
94
  }
95
+ /** 全部任务上未结算执行的总数(全局在飞容量的判据)。 */
96
+ function countOpenExecutions(tasks) {
97
+ let open = 0;
98
+ for (const task of tasks) for (const execution of task.executions) if (execution.endedAt === void 0) open += 1;
99
+ return open;
100
+ }
70
101
  const TITLE_MAX = 200;
71
102
  const PROMPT_MAX = 65536;
72
103
  const PIN_MAX = 200;
@@ -252,4 +283,4 @@ function parseTasksEnvelope(value) {
252
283
  };
253
284
  }
254
285
  //#endregion
255
- export { CRON_MAX, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TITLE_MAX, hasOpenExecution, isTaskPermission, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
286
+ export { CRON_MAX, DEFAULT_MAX_INFLIGHT_EXECUTIONS, DEFAULT_SESSION_PERMISSION, DEFAULT_TASK_AGENT_PRESET, DEFAULT_TASK_PERMISSION, EXECUTION_HISTORY_LIMIT, PIN_MAX, PROMPT_MAX, TASKS_ACTION_BYTES_LIMIT, TASKS_API_SUBPATH, TASKS_SCHEMA_VERSION, TASK_PERMISSIONS, TASK_SKIP_REASONS, TITLE_MAX, countOpenExecutions, hasOpenExecution, isTaskPermission, isTaskSkipReason, parseNewTaskInput, parseTaskUpdatePatch, parseTasksAction, parseTasksEnvelope, permissionPending, permissionRank, retainRecentExecutions };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dshtrading/api",
3
3
  "description": "Pure TypeScript contracts for dsh-trading: market-data/trade service interfaces, domain types, and the shared error vocabulary",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "./lib/index.d.ts",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "license": "PolyForm-Noncommercial-1.0.0",
19
19
  "devDependencies": {
20
- "@deepseek-ai/cordis": "^4.0.4",
20
+ "@deepseek-ai/cordis": "^4.0.5",
21
21
  "tsdown": "^0.22.0",
22
22
  "vitest": "^3.0.0"
23
23
  },