@dshtrading/kit-crypto 0.4.1 → 0.6.0
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/assets/skills/crypto-instrument-analysis.md +4 -0
- package/assets/skills/crypto-risk-checklist.md +32 -1
- package/assets/skills/indicator-authoring.md +4 -0
- package/assets/skills/knowledge-curation.md +1 -0
- package/lib/api/lib/index.d.ts +113 -20
- package/lib/api/lib/instrument-form.d.ts +1 -0
- package/lib/derivatives.d.ts +5 -1
- package/lib/derivatives.js +19 -3
- package/lib/index.d.ts +20 -4
- package/lib/index.js +70 -37
- package/package.json +6 -6
|
@@ -13,6 +13,10 @@ description: 加密标的定性分析框架:趋势结构→量价→波动率
|
|
|
13
13
|
- symbol 一律市场规范词汇(如 `BTCUSDT`),不要用交易所方言。
|
|
14
14
|
- **知识库召回**:进入工具取数前先调 `knowledge_search`(按 symbol、赛道与主题标签,需要全文用 `detail: "full"`);命中的知识卡片只作线索证据(转述≠背书,不替代工具实测数据),纳入依据清单时标注卡片 id;未命中也如实说明「知识库无相关沉淀」。主题宽泛时先 `knowledge_graph` 看主体分布,再按 `cluster` 钻取。
|
|
15
15
|
|
|
16
|
+
- **形态定位(先于一切判读)**:`-SWAP` 后缀 = 永续合约(`BTCUSDT-SWAP`),无后缀 = 现货(`BTCUSDT`);两者是同一 base 的两个不同标的,价格可以长期背离(靠资金费率锚定),取数与判读不得混用。形态由符号后缀裁决,不要各写一套判据。
|
|
17
|
+
- **TradFi 合约不是股票/指数本身**:`TSLAUSDT-SWAP`、`US500-USDT-SWAP`、`XAUUSDT-SWAP` 是交易所合成合约——无股息与股东权利、可被 ADL、24/7 报价而标的现货有闭市时段;资产类别只信交易所元数据(OKX 上 `SPX-USDT-SWAP` 是迷因币 SPX6900,标普 500 叫 `US500-USDT-SWAP`),禁止按符号猜。
|
|
18
|
+
- **只读边界**:本轮加密永续与 TradFi 永续只提供行情与衍生品指标;合约下单未落地,涉及交易一律按铁律 #3(dry-run 起步 + 显式开关 + 审批)。
|
|
19
|
+
|
|
16
20
|
## 第一步:趋势结构(多周期一致法)
|
|
17
21
|
|
|
18
22
|
1. `crypto_get_klines` 取 1d(看方向)→ 4h(看结构)→ 1h(看时机);根数默认 300 足够。
|
|
@@ -12,7 +12,7 @@ description: 加密合约交易风控检查清单:开仓前逐项核对杠杆
|
|
|
12
12
|
1. **杠杆**:名义杠杆是否在计划上限内(默认 ≤3x);波动率放大时段(重大数据公布、周末薄流动性)是否降杠杆。
|
|
13
13
|
2. **仓位**:单笔风险是否 ≤ 账户权益的既定百分比;同一标的的多笔仓位是否合并计算了净敞口。
|
|
14
14
|
3. **资金费率**:当前 funding rate 与下一次结算时间;跨期/现货对冲时,费率方向是否与持仓方向一致(套利而非付费)。
|
|
15
|
-
4.
|
|
15
|
+
4. **强平价**:读持仓回传的强平价(`crypto_get_positions.liquidationPrice`,交易所口径,缺席即未知),核对它与标记价的距离是否留出 ≥ 计划止损距离的 2 倍缓冲;本地不倒算强平价。
|
|
16
16
|
5. **止损**:入场前是否已确定止损位与触发方式(交易所条件单优先于「心里有数」)。
|
|
17
17
|
6. **流动性**:盘口深度是否足以按限价离场;小市值/新上线合约是否降低仓位上限。
|
|
18
18
|
7. **对手侧情景**:价格反向运行到止损位后,是否接受该笔亏损并继续执行原计划(不允许临时放大杠杆摊平)。
|
|
@@ -21,6 +21,37 @@ description: 加密合约交易风控检查清单:开仓前逐项核对杠杆
|
|
|
21
21
|
- 达到目标位或止损位按计划执行;移动止损只朝有利方向。
|
|
22
22
|
- 资金费率在持仓期间显著反向恶化时,重新评估持有成本,而不是无视。
|
|
23
23
|
|
|
24
|
+
## TradFi 合约(股票/指数/大宗永续,交易所合成产品)
|
|
25
|
+
|
|
26
|
+
标的形如 `TSLAUSDT-SWAP`、`XAUUSDT-SWAP`、`US500-USDT-SWAP`(`-SWAP` = 永续,不是股票/现货本身)。
|
|
27
|
+
上面 1–7 条与退出纪律同样适用,另加合约专有项:
|
|
28
|
+
|
|
29
|
+
1. **合成产品与对手方风险**:这类合约由交易所合成报价与结算,持仓对手方是交易所及其清算机制,不是上市公司——没有股息、没有投票权,也不适用证券投资者保护;交易所停机、标记价格异常、自动减仓(ADL)都直接落在仓位上。
|
|
30
|
+
2. **现货闭市、合约照常报价**:标的现货休市(夜间、周末、节假日)时永续仍 24/7 报价,此时盘口薄、跳价快,成交量不代表真实股票流动性;按现货收盘位(前收/开盘)设的止损在闭市段没有参照物。
|
|
31
|
+
3. **隔夜与跳空**:现货闭市期间的财报、公司行动、指数期货与宏观事件会在合约上一次性反映;缺口可直接跳过止损价,条件单不保证按设定价成交。重仓隔夜前按「缺口 = 已被跳过」估算最大损失,并相应降低名义仓位。
|
|
32
|
+
4. **资金费率锚定成本**:合成合约没有到期日,靠资金费率锚定现货;费率长期单向时持有成本持续侵蚀方向收益(指数与贵金属合约尤其明显),跨期对冲要确认收的是费率而不是付的。
|
|
33
|
+
5. **资产类别只信交易所元数据**:符号字面不能推断归属——OKX 上 `SPX-USDT-SWAP` 是迷因币 SPX6900(`instCategory=1`),标普 500 的合约叫 `US500-USDT-SWAP`;不确定时按交易所元数据核对,禁止按符号猜。
|
|
34
|
+
6. **下单接线与闸门(P7 起)**:OKX 路由下合约可下单——`crypto_place_order` 的 quantity 恒为 **base 币数**,连接器按 ctVal 折算张数并按 lotSz **向下**取整;缺省全仓(cross),逐仓(isolated)须先用 `crypto_set_leverage` 设好该标的的逐仓杠杆。**dry-run 是缺省**:只有 `dryRun=false` + 人工签署的实盘授权 + 审批放行才触达交易所(`env=demo` 打模拟盘、`env=live` 才是真钱)。Binance 路由下合约**只有行情**:`-SWAP` 下单被显式拒绝(TRADING_UNSUPPORTED_SYMBOL),不会回落成现货单。
|
|
35
|
+
7. **强平与保证金口径**:强平价与维持保证金率读 `crypto_get_positions` 回传的交易所字段(`liquidationPrice` / `marginRatio` / `marginMode` / `notionalUsd`);字段缺席即交易所未提供,**不得用本地公式倒算强平价**充数,也不得把 `0` 当读数(0 与「没有」是两回事)。
|
|
36
|
+
|
|
37
|
+
## 杠杆与保证金模式(开仓前核对,OKX 词汇)
|
|
38
|
+
|
|
39
|
+
1. **模式先定、再谈倍数**:全仓(cross)与逐仓(isolated)风险归属不同——逐仓亏损上限是该仓保证金,全仓会把账户余额一起拖进强平。改模式/倍数走 `crypto_set_leverage`(`marginMode` + `leverage`,双向持仓模式还要 `posSide`),它和下单同一门槛:dry-run 缺省,实盘需人工签署授权 + 审批。
|
|
40
|
+
2. **上限是交易所定的**:请求倍数超过该标的规格 `lever` 会被拒绝,**不会静默截断**;不要用「先设 100x 看看」试探。
|
|
41
|
+
3. **isolated 的顺序**:先 `crypto_set_leverage`(该 instId + isolated),再在 `crypto_place_order` 传 `marginMode: 'isolated'`;不先设杠杆,交易所会按参数错误拒单。
|
|
42
|
+
4. **倍数与强平距离一起看**:强平价只信持仓回传值;杠杆每翻一倍,同样的价格波动对保证金的占比也翻倍——按「止损距离 × 2 倍缓冲」核对强平距离(见上节第 4 条)。
|
|
43
|
+
5. **现货不适用**:现货订单传 `marginMode` 会被结构化拒绝(现货杠杆是另一个未接线产品面),不要把它当「现货也能逐仓」。
|
|
44
|
+
|
|
45
|
+
## 清单归属(避免两份清单互相顶替)
|
|
46
|
+
|
|
47
|
+
| 交易的是什么 | 用哪份清单 |
|
|
48
|
+
|---|---|
|
|
49
|
+
| 加密永续与 TradFi 永续(OKX 路由,含 `TSLAUSDT-SWAP` 这类交易所合成合约) | **本清单**(crypto-risk-checklist) |
|
|
50
|
+
| 国内商品/金融期货(同花顺期货数据面 `futures` 市场,无交易面) | `futures-risk-checklist`(期货清单) |
|
|
51
|
+
| 现货贵金属/外汇/海外指数(jin10 `global` 市场,纯数据) | global-risk-checklist |
|
|
52
|
+
|
|
53
|
+
两条边界:OKX 的 `XAU-USDT-SWAP` 是**交易所合成永续**,与 jin10 的 `XAUUSD` 现货报价是两个产品,不互相映射;国内期货的保证金/涨跌停/移仓换月规则不适用于交易所合成永续。
|
|
54
|
+
|
|
24
55
|
## OKX 模拟盘(demo)使用法(connector-okx)
|
|
25
56
|
|
|
26
57
|
OKX 连接器启用后(`enabled: true`,与 binance 行互斥),**第一默认目标是 demo 模拟盘**:
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: indicator-authoring
|
|
3
|
+
description: 自定义技术指标创作指南:根据用户自然语言需求生成符合契约的指标代码(TD9/SuperTrend/OBV+MA等),并通过 indicator_author 工具验证与落库。
|
|
4
|
+
---
|
|
1
5
|
# 指标创作指南(Indicator Authoring Guide)
|
|
2
6
|
|
|
3
7
|
当用户在会话列中用自然语言提出编写或添加技术指标的需求时(例如:"帮我写一个 TD9 指标"、"帮我写一个 SuperTrend 指标"、"给 OBV 加一个 34 天均线"),请遵循本指南生成符合 `@dshtrading/indicators` 契约规范的 JavaScript 纯函数代码,并调用 `indicator_author` 工具进行沙箱校验与落库。
|
|
@@ -41,6 +41,7 @@ description: 财经观点沉淀与知识库策展指南:基于 Content Insight
|
|
|
41
41
|
- `title`:卡片主题(精炼概括核心逻辑,如「高股息资产在低利率环境下的防御逻辑」);
|
|
42
42
|
- `summary`:合并 2-4 条核心论点的一句话概述(图谱 hover 提示文案);
|
|
43
43
|
- `source`:`type`(bilibili / wechat / manual)、`url`、`author`、`publishedAt`;
|
|
44
|
+
- `author` **只写主体名**(B站 UP 名 / 公众号名 / 机构名),平台、角色(转播/提炼/核查)、发言人名单、备注一律写进卡片正文——同一主体的不同平台写法由 `packages/knowledge/src/authors.ts` 的别名表在入库时自动归一,命中时 `knowledge_ingest` 回报会回显「作者已归一:旧 → 规范名」。注意别名表是**精确匹配**:未登记的写法不会告警、只会安静地多出作者下拉的一行——入库前请先比对规范名册(工作区 `reports/knowledge_taxonomy.md` §作者字段规范),发现新写法时登记 `AUTHOR_ALIASES` 并补 `test/authors.test.ts` 用例,不要手改 `cards.json`;
|
|
44
45
|
- `credibility`:`high` / `medium` / `low`;
|
|
45
46
|
- `coreClaims`:核心论点列表(保留原作者的推理链条,避免断章取义);
|
|
46
47
|
- `factCheck`:`{ verified: [...], discrepancies: [...], unverifiable: [...] }`;
|
package/lib/api/lib/index.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
+
import "./instrument-form.js";
|
|
2
|
+
import "@deepseek-ai/cordis";
|
|
1
3
|
//#region ../api/lib/index.d.ts
|
|
2
4
|
//#region src/index.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* @dshtrading/api — 纯类型契约包(crypto-slice-plan §关键接口草案)。
|
|
5
|
-
*
|
|
6
|
-
* 零运行时、零依赖:服务契约由连接器实现(ctx 键按市场命名空间,如 ctx.tradingCrypto),
|
|
7
|
-
* 消费方只依赖这里的类型。交易安全闸门(铁律 #3)在类型层面体现为
|
|
8
|
-
* OrderRequest.dryRun 默认 true、错误词汇含 LIVE_TRADING_DISABLED / APPROVAL_DENIED。
|
|
9
|
-
*
|
|
10
|
-
* @module @dshtrading/api
|
|
11
|
-
*/
|
|
12
5
|
/** K线周期(Binance 现货/合约 interval 词汇)。 */
|
|
13
6
|
type Interval = '1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '6h' | '8h' | '12h' | '1d' | '3d' | '1w' | '1M';
|
|
14
7
|
/** 最新行情快照(公共数据,无需凭证)。 */
|
|
@@ -423,16 +416,32 @@ interface FundamentalsPackage {
|
|
|
423
416
|
readonly dragonTiger?: DragonTigerItem;
|
|
424
417
|
}
|
|
425
418
|
type PositionSide = 'long' | 'short';
|
|
419
|
+
/**
|
|
420
|
+
* 保证金模式(合约交易语义,P7):`cross` = 全仓、`isolated` = 逐仓。
|
|
421
|
+
* 现货(cash)不使用该字段——缺席即「非保证金/未设置」。
|
|
422
|
+
*/
|
|
423
|
+
type MarginMode = 'cross' | 'isolated';
|
|
426
424
|
/** 持仓快照。 */
|
|
427
425
|
interface Position {
|
|
428
426
|
readonly symbol: string;
|
|
429
427
|
readonly side: PositionSide;
|
|
430
|
-
/** 仓位数量(正数;方向由 side
|
|
428
|
+
/** 仓位数量(正数;方向由 side 表达)。合约仓位是 **base 币数**(连接器已按合约乘数 ctVal 由张换算)。 */
|
|
431
429
|
readonly size: number;
|
|
432
430
|
readonly entryPrice: number;
|
|
433
431
|
readonly markPrice?: number;
|
|
434
432
|
readonly unrealizedPnl?: number;
|
|
435
433
|
readonly leverage?: number;
|
|
434
|
+
/**
|
|
435
|
+
* 强平价(交易所回传原样透传;交易所未提供或不适用时缺席,绝不本地推算强平价——
|
|
436
|
+
* 强平口径与保证金模式、账户级保证金、维持保证金率有关,本地公式会给出错误的安全感)。
|
|
437
|
+
*/
|
|
438
|
+
readonly liquidationPrice?: number;
|
|
439
|
+
/** 维持保证金率(OKX `mgnRatio`;口径由交易所定义,原样透传,不在本地换算或反推)。 */
|
|
440
|
+
readonly marginRatio?: number;
|
|
441
|
+
/** 该仓位的保证金模式;现货持仓与交易所未提供时缺席。 */
|
|
442
|
+
readonly marginMode?: MarginMode;
|
|
443
|
+
/** 名义价值(USD,交易所口径;用于敞口核对,不参与本地风控公式)。 */
|
|
444
|
+
readonly notionalUsd?: number;
|
|
436
445
|
readonly timestamp: number;
|
|
437
446
|
}
|
|
438
447
|
type OrderSide = 'buy' | 'sell';
|
|
@@ -443,10 +452,18 @@ interface OrderRequest {
|
|
|
443
452
|
readonly symbol: string;
|
|
444
453
|
readonly side: OrderSide;
|
|
445
454
|
readonly type: OrderType;
|
|
455
|
+
/** **base 币数量**:合约(永续)由连接器按合约乘数换算成张,消费方恒用币数语义。 */
|
|
446
456
|
readonly quantity: number;
|
|
447
457
|
/** limit 单必填。 */
|
|
448
458
|
readonly price?: number;
|
|
449
|
-
/**
|
|
459
|
+
/**
|
|
460
|
+
* 合约订单的保证金模式(缺省 `cross`)。仅对永续(`-SWAP`)有效:
|
|
461
|
+
* 现货订单只允许 cash 语义,传该字段由连接器结构化拒绝
|
|
462
|
+
* (现货逐仓/杠杆是另一个产品面,本仓未接线)。
|
|
463
|
+
* `isolated` 需先在交易所侧设好该标的的逐仓杠杆(OKX `setLeverage`)。
|
|
464
|
+
*/
|
|
465
|
+
readonly marginMode?: MarginMode;
|
|
466
|
+
/** 缺省/true 时仅模拟,不触碰交易所。实盘还受 @dshtrading/authority 的人工签署授权与 approval 约束 [S4]。 */
|
|
450
467
|
readonly dryRun?: boolean;
|
|
451
468
|
}
|
|
452
469
|
/** 订单回执/状态。 */
|
|
@@ -486,9 +503,49 @@ interface TradeFill {
|
|
|
486
503
|
interface Disposable {
|
|
487
504
|
dispose(): void;
|
|
488
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* 标的形态轴(2026-10-08 加密永续与 TradFi 永续落地):与 `market` 正交,**不新增市场键**。
|
|
508
|
+
* 缺省 = `spot`——已存自选、localStorage 与 iOS 冻结契约因此零迁移。
|
|
509
|
+
*
|
|
510
|
+
* 形态由规范符号后缀承载(`-SWAP` = 永续),见 docs/guides/symbol-vocabulary.md;
|
|
511
|
+
* `form` 只出现在名册/检索/wire 元数据里,行情方法不新增 form 形参。
|
|
512
|
+
*/
|
|
513
|
+
type InstrumentForm = 'spot' | 'perp';
|
|
514
|
+
/**
|
|
515
|
+
* 标的资产类别标签(仅展示与检索排序用,不承载交易语义)。
|
|
516
|
+
* **只信交易所元数据**(OKX `instCategory`、Binance `underlyingType`+`underlyingSubType`);
|
|
517
|
+
* 取不到时留空,禁止按符号字面猜(`SPX` 在 OKX 是迷因币 SPX6900,标普 500 是 `US500`)。
|
|
518
|
+
*/
|
|
519
|
+
type InstrumentAssetClass = 'crypto' | 'equity' | 'commodity' | 'index';
|
|
520
|
+
/** 合约专有元数据(仅 `form=perp` 有值):交易所元数据原样透传,不本地推断。 */
|
|
521
|
+
interface InstrumentContract {
|
|
522
|
+
/** 合约乘数(OKX ctVal / Binance contractSize)。 */
|
|
523
|
+
readonly multiplier?: number;
|
|
524
|
+
/** 最小价格变动。 */
|
|
525
|
+
readonly tickSize?: number;
|
|
526
|
+
/** 最小下单量/张数步长。 */
|
|
527
|
+
readonly lotSize?: number;
|
|
528
|
+
/** 交易所允许的最大杠杆。 */
|
|
529
|
+
readonly maxLeverage?: number;
|
|
530
|
+
/** 结算币种(如 USDT)。 */
|
|
531
|
+
readonly settleCcy?: string;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* 标的检索结果的最小元数据(名册/搜索/wire 共用)。
|
|
535
|
+
* 元素形状对既有 `{ symbol, name? }` 实现向后兼容:`form`/`assetClass`/`contract` 全可选。
|
|
536
|
+
*/
|
|
537
|
+
interface InstrumentRef {
|
|
538
|
+
/** 市场规范词汇符号(docs/guides/symbol-vocabulary.md)。 */
|
|
539
|
+
readonly symbol: string;
|
|
540
|
+
readonly name?: string;
|
|
541
|
+
/** 缺省 = spot(老数据零迁移)。 */
|
|
542
|
+
readonly form?: InstrumentForm;
|
|
543
|
+
readonly assetClass?: InstrumentAssetClass;
|
|
544
|
+
readonly contract?: InstrumentContract;
|
|
545
|
+
}
|
|
489
546
|
/**
|
|
490
547
|
* 行情服务契约:由市场连接器实现,注册到按市场命名空间的 ctx 键(如 ctx.tradingCrypto)。
|
|
491
|
-
* 符号词汇(2026-08-31 规范,docs/symbol-vocabulary.md):入参接受市场规范形与连接器原生形,
|
|
548
|
+
* 符号词汇(2026-08-31 规范,docs/guides/symbol-vocabulary.md):入参接受市场规范形与连接器原生形,
|
|
492
549
|
* 输出 `symbol` 一律市场规范形——消费方(GUI/Agent/工作流)与数据源方言解耦。
|
|
493
550
|
*/
|
|
494
551
|
interface MarketDataService {
|
|
@@ -497,13 +554,12 @@ interface MarketDataService {
|
|
|
497
554
|
subscribeTicker(symbol: string, cb: (ticker: Ticker) => void): Disposable;
|
|
498
555
|
/**
|
|
499
556
|
* 查询本市场/交易所支持的全部标的名册(动态全集,Issue #15)。
|
|
500
|
-
* 输出 `symbol` 一律市场规范词汇(docs/symbol-vocabulary.md
|
|
557
|
+
* 输出 `symbol` 一律市场规范词汇(docs/guides/symbol-vocabulary.md),形态由符号后缀承载
|
|
558
|
+
* (`-SWAP` = 永续,`instrumentFormOf` 是唯一裁决实现);每行可带
|
|
559
|
+
* `form`/`assetClass`/`contract` 元数据(InstrumentRef),缺省 = 现货。
|
|
501
560
|
* 可选方法:无公开全集端点的数据源(如 tencent/yahoo/stooq)可缺省或由桥/前端回退。
|
|
502
561
|
*/
|
|
503
|
-
listInstruments?(): Promise<
|
|
504
|
-
symbol: string;
|
|
505
|
-
name?: string;
|
|
506
|
-
}>>;
|
|
562
|
+
listInstruments?(): Promise<InstrumentRef[]>;
|
|
507
563
|
/**
|
|
508
564
|
* 标的基本面与估值快照(GUI「基本面」页签用,2026-09-02)。
|
|
509
565
|
* 可选方法:仅当数据源在同一公共端点里携带基本面字段时实现
|
|
@@ -539,11 +595,41 @@ interface MarketDataService {
|
|
|
539
595
|
getRecentTrades?(symbol: string, limit?: number): Promise<TradeTick[]>;
|
|
540
596
|
}
|
|
541
597
|
/**
|
|
542
|
-
*
|
|
598
|
+
* 杠杆设置请求(合约交易语义,P7;仅 `form=perp` 的标的可传)。
|
|
599
|
+
* dryRun 缺省视为 true:只回本地模拟回执,不触碰交易所(与 placeOrder 同语义)。
|
|
600
|
+
*/
|
|
601
|
+
interface SetLeverageRequest {
|
|
602
|
+
readonly symbol: string;
|
|
603
|
+
/** 目标杠杆倍数(> 0;上限以交易所规格 `InstrumentContract.maxLeverage` 为准,超出即结构化拒绝)。 */
|
|
604
|
+
readonly leverage: number;
|
|
605
|
+
readonly marginMode: MarginMode;
|
|
606
|
+
/** 双向持仓模式下的方向(OKX `posSide`);净持仓模式下缺席。 */
|
|
607
|
+
readonly posSide?: 'long' | 'short';
|
|
608
|
+
/** 全仓模式下按币种设置杠杆时的保证金币(OKX `ccy`);逐仓与净持仓模式缺席。 */
|
|
609
|
+
readonly ccy?: string;
|
|
610
|
+
/** 缺省/true 时仅模拟。实盘还受 @dshtrading/authority 的人工签署授权与 approval 约束 [S4]。 */
|
|
611
|
+
readonly dryRun?: boolean;
|
|
612
|
+
}
|
|
613
|
+
/** 杠杆设置回执(dryRun=true 时是本地模拟回执,不触网)。 */
|
|
614
|
+
interface LeverageSetting {
|
|
615
|
+
readonly symbol: string;
|
|
616
|
+
readonly leverage: number;
|
|
617
|
+
readonly marginMode: MarginMode;
|
|
618
|
+
readonly posSide?: 'long' | 'short';
|
|
619
|
+
readonly ccy?: string;
|
|
620
|
+
/** 本次是否为模拟回执(回执必须显式回带,防 dry-run 语义丢失)。 */
|
|
621
|
+
readonly dryRun: boolean;
|
|
622
|
+
readonly timestamp: number;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* 交易服务契约:placeOrder 默认 dry-run;实盘前必须过 @dshtrading/authority 的人工签署授权与
|
|
543
626
|
* ctx.approval.request(交互形态;headless 下 ask=deny,fail-closed [S4])。
|
|
544
627
|
*
|
|
545
628
|
* R3(okx 切片 2026-08-29)修订:cancelOrder 增加可选 symbol、新增 getOrder——
|
|
546
629
|
* OKX 按 (instId, ordId) 双键定位订单,单参 id 形态不够;无其他实现方,扩展向后兼容。
|
|
630
|
+
*
|
|
631
|
+
* P7(合约交易 Tier 2,2026-10-08)修订:新增可选 `setLeverage`——杠杆/保证金模式变更
|
|
632
|
+
* 是实盘动作,必须与下单同门槛(服务缝三态闸门 + base 审批闸门 + 人工签署授权)。
|
|
547
633
|
*/
|
|
548
634
|
interface TradeService {
|
|
549
635
|
placeOrder(req: OrderRequest): Promise<Order>;
|
|
@@ -568,6 +654,13 @@ interface TradeService {
|
|
|
568
654
|
* 可选方法:时间升序(旧→新),最多 limit 条(缺省 ≤50)。
|
|
569
655
|
*/
|
|
570
656
|
listTradeFills?(symbol?: string, limit?: number): Promise<TradeFill[]>;
|
|
657
|
+
/**
|
|
658
|
+
* 设置合约杠杆与保证金模式(P7 合约交易 Tier 2;仅支持合约的交易所实现)。
|
|
659
|
+
* 可选方法:不实现的连接器缺席即可,消费方按 TRADING_NOT_IMPLEMENTED 语义处理。
|
|
660
|
+
* 这是会改变账户真实风险参数的实盘动作:dryRun 缺省 true(只回本地模拟回执),
|
|
661
|
+
* dryRun=false 必须同时具备人工签署的实盘授权,并经 base 审批闸门。
|
|
662
|
+
*/
|
|
663
|
+
setLeverage?(req: SetLeverageRequest): Promise<LeverageSetting>;
|
|
571
664
|
}
|
|
572
665
|
/**
|
|
573
666
|
* Cordis Context 服务键(能力三角色之「声明」):市场命名空间键由契约包统一声明,
|
|
@@ -598,7 +691,7 @@ declare module '@deepseek-ai/cordis' {
|
|
|
598
691
|
* 交易服务注册表(issue #40 GUI 交易台,@dshtrading/api 类型声明):
|
|
599
692
|
* 与 tradingMarketDataRegistry 同构的宿主平面注册面——交易连接器 host 面数据行
|
|
600
693
|
* 注册,GUI 桥按路由当前值惰性解析。**注册不改变安全语义**:placeOrder 的
|
|
601
|
-
* 服务缝闸门(dryRun 缺省 true +
|
|
694
|
+
* 服务缝闸门(dryRun 缺省 true + @dshtrading/authority 人工签署授权)随服务实例生效;
|
|
602
695
|
* GUI 桥只放行 dry-run 下单与只读查询,实盘路径仍走 Agent 工具的 base 审批闸门。
|
|
603
696
|
*/
|
|
604
697
|
tradingTradeRegistry: TradeRegistry;
|
|
@@ -799,4 +892,4 @@ interface TradingNewsRegistry {
|
|
|
799
892
|
markets(): string[];
|
|
800
893
|
}
|
|
801
894
|
//#endregion
|
|
802
|
-
export { AccountBalance, AggregateNewsOptions, AggregateNewsResult, AuctionSnapshot, BuybackItem, CompanyProfile, CryptoFundamentals, DerivativesData, DerivativesHistory, DerivativesPoint, Disposable, DividendItem, DragonTigerItem, FinancialCell, FinancialIndicatorRow, FinancialReportGroup, FinancialReportMatrix, FlashFeedService, ForecastSummary, FundamentalsPackage, HolderNumSummary, InsiderTradeItem, InstitutionalHoldingItem, Interval, Kline, LimitUpPoolItem, MacroCalendarEntry, MacroFeedService, MacroRateEntry, MainOperationSegment, MarketDataRegistration, MarketDataRegistry, MarketDataService, MarketRouterService, NewsAggregator, NewsItem, OperatingEfficiency, Order, OrderRequest, OrderSide, OrderStatus, OrderType, Orderbook, OrderbookLevel, Position, PositionSide, ResearchReportItem, ShareholderItem, SplitItem, StockFundamentals, Ticker, TradeFill, TradeRegistration, TradeRegistry, TradeService, TradeTick, TradingNewsRegistry };
|
|
895
|
+
export { AccountBalance, AggregateNewsOptions, AggregateNewsResult, AuctionSnapshot, BuybackItem, CompanyProfile, CryptoFundamentals, DerivativesData, DerivativesHistory, DerivativesPoint, Disposable, DividendItem, DragonTigerItem, FinancialCell, FinancialIndicatorRow, FinancialReportGroup, FinancialReportMatrix, FlashFeedService, ForecastSummary, FundamentalsPackage, HolderNumSummary, InsiderTradeItem, InstitutionalHoldingItem, InstrumentAssetClass, InstrumentContract, InstrumentForm, InstrumentRef, Interval, Kline, LeverageSetting, LimitUpPoolItem, MacroCalendarEntry, MacroFeedService, MacroRateEntry, MainOperationSegment, MarginMode, MarketDataRegistration, MarketDataRegistry, MarketDataService, MarketRouterService, NewsAggregator, NewsItem, OperatingEfficiency, Order, OrderRequest, OrderSide, OrderStatus, OrderType, Orderbook, OrderbookLevel, Position, PositionSide, ResearchReportItem, SetLeverageRequest, ShareholderItem, SplitItem, StockFundamentals, Ticker, TradeFill, TradeRegistration, TradeRegistry, TradeService, TradeTick, TradingNewsRegistry };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./index.js";
|
package/lib/derivatives.d.ts
CHANGED
|
@@ -7,7 +7,11 @@ interface DerivativesFetchOptions {
|
|
|
7
7
|
interface DerivativesResult {
|
|
8
8
|
data?: DerivativesData;
|
|
9
9
|
unavailable?: string[];
|
|
10
|
+
/** 注册表路径实际供数的 provider(直连回退路径缺省,不回显假 provider)。 */
|
|
11
|
+
provider?: string;
|
|
10
12
|
}
|
|
13
|
+
/** provider 取数失败时的降级结果(fail-soft:与直连路径同一契约,报错不抛裸异常)。 */
|
|
14
|
+
declare function derivativesFailure(provider: string, error: unknown): DerivativesResult;
|
|
11
15
|
/** 将输入 symbol 规范化为 Binance USDT-M 合约 symbol(如 BTCUSDT)。 */
|
|
12
16
|
declare function normalizeBinanceFuturesSymbol(raw: string): string;
|
|
13
17
|
/** 提取 base 资产名称(如 BTCUSDT → BTC)。 */
|
|
@@ -15,4 +19,4 @@ declare function extractBaseAsset(symbol: string): string;
|
|
|
15
19
|
declare function fetchCryptoDerivatives(options: DerivativesFetchOptions): Promise<DerivativesResult>;
|
|
16
20
|
declare function renderDerivativesData(result: DerivativesResult, requestedSymbol: string): string;
|
|
17
21
|
//#endregion
|
|
18
|
-
export { DerivativesFetchOptions, DerivativesResult, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData };
|
|
22
|
+
export { DerivativesFetchOptions, DerivativesResult, derivativesFailure, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData };
|
package/lib/derivatives.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
//#region src/derivatives.ts
|
|
2
|
+
/** provider 取数失败时的降级结果(fail-soft:与直连路径同一契约,报错不抛裸异常)。 */
|
|
3
|
+
function derivativesFailure(provider, error) {
|
|
4
|
+
return {
|
|
5
|
+
provider,
|
|
6
|
+
unavailable: [`${provider}-getDerivatives: ${typeof error?.code === "string" ? `${error.code}: ` : ""}${error instanceof Error ? error.message : String(error)}`]
|
|
7
|
+
};
|
|
8
|
+
}
|
|
2
9
|
const BINANCE_FAPI_BASE = "https://fapi.binance.com";
|
|
3
10
|
const BINANCE_FUTURES_DATA_BASE = "https://fapi.binance.com/futures/data";
|
|
4
11
|
/** 将输入 symbol 规范化为 Binance USDT-M 合约 symbol(如 BTCUSDT)。 */
|
|
@@ -92,14 +99,23 @@ async function fetchCryptoDerivatives(options) {
|
|
|
92
99
|
return { unavailable };
|
|
93
100
|
}
|
|
94
101
|
function renderDerivativesData(result, requestedSymbol) {
|
|
95
|
-
const { data, unavailable = [] } = result;
|
|
102
|
+
const { data, unavailable = [], provider } = result;
|
|
96
103
|
if (!data) return `crypto_get_derivatives ${requestedSymbol}: no derivative data available.${unavailable.length > 0 ? ` (errors: ${unavailable.join("; ")})` : ""}`;
|
|
97
|
-
const
|
|
104
|
+
const origin = provider === void 0 ? `source: ${data.source}` : `provider: ${provider}, source: ${data.source}`;
|
|
105
|
+
const lines = [`crypto_get_derivatives ${data.symbol} (${origin}, updated: ${new Date(data.timestamp).toISOString()}):`];
|
|
98
106
|
if (data.openInterest !== void 0) lines.push(`- Open Interest (OI): ${data.openInterest.toLocaleString()} base-coins`);
|
|
107
|
+
if (data.openInterestValue !== void 0) lines.push(`- Open Interest Value: ${data.openInterestValue.toLocaleString()} quote`);
|
|
99
108
|
if (data.fundingRate !== void 0) {
|
|
100
109
|
const pct = (data.fundingRate * 100).toFixed(4);
|
|
101
110
|
lines.push(`- Latest Funding Rate: ${data.fundingRate} (${pct}%)`);
|
|
102
111
|
}
|
|
112
|
+
if (data.nextFundingRate !== void 0) {
|
|
113
|
+
const pct = (data.nextFundingRate * 100).toFixed(4);
|
|
114
|
+
lines.push(`- Next Funding Rate: ${data.nextFundingRate} (${pct}%)`);
|
|
115
|
+
}
|
|
116
|
+
if (data.nextFundingTime !== void 0) lines.push(`- Next Funding Time: ${new Date(data.nextFundingTime).toISOString()}`);
|
|
117
|
+
if (data.markPrice !== void 0) lines.push(`- Mark Price: ${data.markPrice}`);
|
|
118
|
+
if (data.indexPrice !== void 0) lines.push(`- Index Price: ${data.indexPrice}`);
|
|
103
119
|
if (data.longShortRatio !== void 0) lines.push(`- Global Long/Short Account Ratio: ${data.longShortRatio.toFixed(2)} (Accounts)`);
|
|
104
120
|
if (data.topTraderLongShortRatio !== void 0) lines.push(`- Top Trader Position L/S Ratio: ${data.topTraderLongShortRatio.toFixed(2)} (Whale Positions)`);
|
|
105
121
|
if (data.takerBuySellRatio !== void 0) lines.push(`- Taker Buy/Sell Volume Ratio: ${data.takerBuySellRatio.toFixed(2)} (Market taker aggressiveness)`);
|
|
@@ -107,4 +123,4 @@ function renderDerivativesData(result, requestedSymbol) {
|
|
|
107
123
|
return lines.join("\n");
|
|
108
124
|
}
|
|
109
125
|
//#endregion
|
|
110
|
-
export { extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData };
|
|
126
|
+
export { derivativesFailure, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData };
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MarketDataService } from "./api/lib/index.js";
|
|
2
2
|
import { CryptoFundamentalsOptions, CryptoFundamentalsResult, fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, renderCryptoFundamentals } from "./fundamentals.js";
|
|
3
|
-
import { DerivativesFetchOptions, DerivativesResult, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData } from "./derivatives.js";
|
|
3
|
+
import { DerivativesFetchOptions, DerivativesResult, derivativesFailure, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData } from "./derivatives.js";
|
|
4
4
|
import { AggregateNewsOptions, AggregateNewsResult, NewsItem, NewsSource, aggregateNews, deriveSymbolTokens, parseCryptoPanic, parseRss2 } from "./news.js";
|
|
5
5
|
import Schema from "@deepseek-ai/schemastery";
|
|
6
6
|
import { SkillProvider } from "@deepseek-ai/dsh-skill";
|
|
@@ -16,11 +16,27 @@ interface Config {
|
|
|
16
16
|
declare const Config: Schema<Config>;
|
|
17
17
|
declare const inject: string[];
|
|
18
18
|
declare const name = "dsh-trading-crypto-kit";
|
|
19
|
+
/**
|
|
20
|
+
* 资金费率工具工厂(只读)。调用期用注册表之外的直连 Binance fapi 公共端点;
|
|
21
|
+
* fetch 可注入(与 `createGetDerivativesTool` 同款契约化 fake 口径,测试不出网)。
|
|
22
|
+
*/
|
|
23
|
+
declare function createFundingRateTool(options?: {
|
|
24
|
+
fetch?: typeof globalThis.fetch;
|
|
25
|
+
}): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
19
26
|
/** 白名单视图:未知名 fail-fast 不静默缩面;白名单外的 get 拒绝分发。 */
|
|
20
27
|
declare function providerForSkills(allowed?: readonly string[] | null): SkillProvider;
|
|
21
28
|
declare function apply(ctx: Context, config: Config): void;
|
|
29
|
+
/**
|
|
30
|
+
* 衍生品指标快照工具(只读)。registry-first:数据源是路由选中的 crypto 行情服务
|
|
31
|
+
* (与 crypto_get_derivatives_history 同源,settings 切换 provider 即刻生效);注册表
|
|
32
|
+
* 服务缺席(老部署 / 无 router)时才回退直连 Binance USDT-M 公共端点。
|
|
33
|
+
* 路由到的 provider 未实现 getDerivatives → TRADING_NOT_IMPLEMENTED(不回退 Binance
|
|
34
|
+
* 冒充路由源,也不返回空读数);provider 取数失败 → fail-soft 报错文本(与直连路径
|
|
35
|
+
* 同一输出契约)。
|
|
36
|
+
*/
|
|
22
37
|
declare function createGetDerivativesTool(options?: {
|
|
23
38
|
fetch?: typeof globalThis.fetch;
|
|
39
|
+
getRegistry?: () => CryptoMarketDataRegistry | undefined;
|
|
24
40
|
}): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
25
41
|
/** 行情注册表最小形状(与 @dshtrading/router 的 MarketDataRegistryLike 同构)。 */
|
|
26
42
|
interface CryptoMarketDataRegistry {
|
|
@@ -30,8 +46,8 @@ interface CryptoMarketDataRegistry {
|
|
|
30
46
|
} | undefined;
|
|
31
47
|
}
|
|
32
48
|
/**
|
|
33
|
-
* 衍生品历史序列工具(只读)。数据源恒为路由选中的 crypto
|
|
34
|
-
*
|
|
49
|
+
* 衍生品历史序列工具(只读)。数据源恒为路由选中的 crypto 行情服务,不直连交易所;
|
|
50
|
+
* crypto_get_derivatives 自 P6(2026-10-08)起同源(registry-first),两者不再分叉。
|
|
35
51
|
*/
|
|
36
52
|
declare function createGetDerivativesHistoryTool(options: {
|
|
37
53
|
getRegistry: () => CryptoMarketDataRegistry | undefined;
|
|
@@ -44,4 +60,4 @@ declare function createGetNewsTool(toolOptions?: {
|
|
|
44
60
|
getSources?: () => readonly string[] | undefined;
|
|
45
61
|
}): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
46
62
|
//#endregion
|
|
47
|
-
export { AggregateNewsOptions, AggregateNewsResult, Config, CryptoFundamentalsOptions, CryptoFundamentalsResult, DerivativesFetchOptions, DerivativesResult, NewsItem, NewsSource, aggregateNews, apply, createGetDerivativesHistoryTool, createGetDerivativesTool, createGetFundamentalsTool, createGetNewsTool, deriveSymbolTokens, extractBaseAsset, fetchCryptoDerivatives, fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, inject, name, normalizeBinanceFuturesSymbol, parseCryptoPanic, parseRss2, provider, providerForSkills, renderCryptoFundamentals, renderDerivativesData };
|
|
63
|
+
export { AggregateNewsOptions, AggregateNewsResult, Config, CryptoFundamentalsOptions, CryptoFundamentalsResult, DerivativesFetchOptions, DerivativesResult, NewsItem, NewsSource, aggregateNews, apply, createFundingRateTool, createGetDerivativesHistoryTool, createGetDerivativesTool, createGetFundamentalsTool, createGetNewsTool, derivativesFailure, deriveSymbolTokens, extractBaseAsset, fetchCryptoDerivatives, fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, inject, name, normalizeBinanceFuturesSymbol, parseCryptoPanic, parseRss2, provider, providerForSkills, renderCryptoFundamentals, renderDerivativesData };
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { aggregateNews, deriveSymbolTokens, parseCryptoPanic, parseRss2 } from "./news.js";
|
|
2
|
-
import { extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData } from "./derivatives.js";
|
|
2
|
+
import { derivativesFailure, extractBaseAsset, fetchCryptoDerivatives, normalizeBinanceFuturesSymbol, renderDerivativesData } from "./derivatives.js";
|
|
3
3
|
import { fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, renderCryptoFundamentals } from "./fundamentals.js";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -139,11 +139,11 @@ const FUNDING_RATE_URL = "https://fapi.binance.com/fapi/v1/fundingRate";
|
|
|
139
139
|
const SYMBOL_PATTERN = /^[A-Z0-9]{4,20}$/;
|
|
140
140
|
const DEFAULT_FUNDING_LIMIT = 3;
|
|
141
141
|
const MAX_FUNDING_LIMIT = 1e3;
|
|
142
|
-
async function fetchFundingRates(symbol, limit) {
|
|
142
|
+
async function fetchFundingRates(symbol, limit, fetchImpl) {
|
|
143
143
|
const url = new URL(FUNDING_RATE_URL);
|
|
144
144
|
url.searchParams.set("symbol", symbol);
|
|
145
145
|
url.searchParams.set("limit", String(limit));
|
|
146
|
-
const response = await
|
|
146
|
+
const response = await fetchImpl(url, { headers: { accept: "application/json" } });
|
|
147
147
|
if (!response.ok) {
|
|
148
148
|
const body = await response.text().catch(() => "");
|
|
149
149
|
throw new Error(`Binance futures API error: HTTP ${response.status}${body ? ` — ${body.slice(0, 200)}` : ""}`);
|
|
@@ -162,31 +162,19 @@ function renderFundingRates(symbol, records) {
|
|
|
162
162
|
});
|
|
163
163
|
return [`crypto_funding_rate ${symbol} — last ${records.length} funding event(s):`, ...lines].join("\n");
|
|
164
164
|
}
|
|
165
|
-
/**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
name: provider.name,
|
|
173
|
-
list: () => Promise.resolve(active),
|
|
174
|
-
async get(candidate, options) {
|
|
175
|
-
if (!active.some((c) => c.name === candidate.name)) throw new Error(`[${PROVIDER_NAME}] skill not in whitelist: ${candidate.name}`);
|
|
176
|
-
return provider.get(candidate, options);
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
function apply(ctx, config) {
|
|
181
|
-
ctx.skills.registerProvider(() => providerForSkills(config.skills));
|
|
182
|
-
const fundingTool = defineTool({
|
|
165
|
+
/**
|
|
166
|
+
* 资金费率工具工厂(只读)。调用期用注册表之外的直连 Binance fapi 公共端点;
|
|
167
|
+
* fetch 可注入(与 `createGetDerivativesTool` 同款契约化 fake 口径,测试不出网)。
|
|
168
|
+
*/
|
|
169
|
+
function createFundingRateTool(options = {}) {
|
|
170
|
+
return defineTool({
|
|
183
171
|
name: "crypto_funding_rate",
|
|
184
|
-
description: "Get recent funding rate history for a Binance USDⓈ-M perpetual
|
|
172
|
+
description: "Get recent funding rate history for a Binance USDⓈ-M perpetual contract (public endpoint, no credentials). The symbol is market-canonical perpetual form, e.g. BTCUSDT-SWAP; the native spot-shaped BTCUSDT is accepted too. Returns the most recent funding events with rate and mark price.",
|
|
185
173
|
parameters: {
|
|
186
174
|
symbol: {
|
|
187
175
|
type: "string",
|
|
188
176
|
required: true,
|
|
189
|
-
description: "Perpetual
|
|
177
|
+
description: "Perpetual contract symbol, market-canonical form, e.g. BTCUSDT-SWAP"
|
|
190
178
|
},
|
|
191
179
|
limit: {
|
|
192
180
|
type: "number",
|
|
@@ -203,12 +191,32 @@ function apply(ctx, config) {
|
|
|
203
191
|
},
|
|
204
192
|
async execute(raw) {
|
|
205
193
|
const args = raw ?? {};
|
|
206
|
-
const
|
|
207
|
-
|
|
194
|
+
const requestedSymbol = typeof args.symbol === "string" ? args.symbol.trim() : "";
|
|
195
|
+
const symbol = normalizeBinanceFuturesSymbol(requestedSymbol);
|
|
196
|
+
if (!SYMBOL_PATTERN.test(symbol)) throw new Error(`crypto_funding_rate: invalid symbol ${JSON.stringify(args.symbol)} — expected a perpetual symbol, market-canonical form e.g. BTCUSDT-SWAP (native BTCUSDT is also accepted)`);
|
|
208
197
|
const requested = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.trunc(args.limit) : DEFAULT_FUNDING_LIMIT;
|
|
209
|
-
|
|
198
|
+
const records = await fetchFundingRates(symbol, Math.min(Math.max(requested, 1), MAX_FUNDING_LIMIT), options.fetch ?? globalThis.fetch);
|
|
199
|
+
return renderFundingRates(`${symbol}-SWAP`, records);
|
|
210
200
|
}
|
|
211
201
|
});
|
|
202
|
+
}
|
|
203
|
+
/** 白名单视图:未知名 fail-fast 不静默缩面;白名单外的 get 拒绝分发。 */
|
|
204
|
+
function providerForSkills(allowed) {
|
|
205
|
+
if (!allowed) return provider;
|
|
206
|
+
const unknown = allowed.filter((name) => !SKILL_CANDIDATES.some((c) => c.name === name));
|
|
207
|
+
if (unknown.length > 0) throw new Error(`[${PROVIDER_NAME}] unknown skills in whitelist: ${unknown.join(", ")}`);
|
|
208
|
+
const active = SKILL_CANDIDATES.filter((c) => allowed.includes(c.name));
|
|
209
|
+
return {
|
|
210
|
+
name: provider.name,
|
|
211
|
+
list: () => Promise.resolve(active),
|
|
212
|
+
async get(candidate, options) {
|
|
213
|
+
if (!active.some((c) => c.name === candidate.name)) throw new Error(`[${PROVIDER_NAME}] skill not in whitelist: ${candidate.name}`);
|
|
214
|
+
return provider.get(candidate, options);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function apply(ctx, config) {
|
|
219
|
+
ctx.skills.registerProvider(() => providerForSkills(config.skills));
|
|
212
220
|
const tools = ctx.tools;
|
|
213
221
|
const registerOnce = (tool) => {
|
|
214
222
|
if (tools.get(tool.name) !== void 0) {
|
|
@@ -217,7 +225,7 @@ function apply(ctx, config) {
|
|
|
217
225
|
}
|
|
218
226
|
tools.register(tool);
|
|
219
227
|
};
|
|
220
|
-
registerOnce(
|
|
228
|
+
registerOnce(createFundingRateTool());
|
|
221
229
|
const router = ctx.get?.("tradingMarketRouter", false);
|
|
222
230
|
const routerCtx = ctx;
|
|
223
231
|
const readNewsSources = () => (routerCtx.get?.("tradingMarketRouter", false))?.newsSources?.("crypto");
|
|
@@ -225,7 +233,7 @@ function apply(ctx, config) {
|
|
|
225
233
|
cryptoPanicKey: router?.newsKey?.(),
|
|
226
234
|
getSources: readNewsSources
|
|
227
235
|
}));
|
|
228
|
-
registerOnce(createGetDerivativesTool());
|
|
236
|
+
registerOnce(createGetDerivativesTool({ getRegistry: () => resolveCryptoMarketDataRegistry(ctx) }));
|
|
229
237
|
registerOnce(createGetFundamentalsTool());
|
|
230
238
|
registerOnce(createGetDerivativesHistoryTool({ getRegistry: () => resolveCryptoMarketDataRegistry(ctx) }));
|
|
231
239
|
const lifecycle = ctx;
|
|
@@ -234,14 +242,22 @@ function apply(ctx, config) {
|
|
|
234
242
|
if (registry && typeof registry.register === "function") lifecycle.effect?.(() => registry.register("crypto", aggregateNews), "kit-crypto news registration");
|
|
235
243
|
});
|
|
236
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* 衍生品指标快照工具(只读)。registry-first:数据源是路由选中的 crypto 行情服务
|
|
247
|
+
* (与 crypto_get_derivatives_history 同源,settings 切换 provider 即刻生效);注册表
|
|
248
|
+
* 服务缺席(老部署 / 无 router)时才回退直连 Binance USDT-M 公共端点。
|
|
249
|
+
* 路由到的 provider 未实现 getDerivatives → TRADING_NOT_IMPLEMENTED(不回退 Binance
|
|
250
|
+
* 冒充路由源,也不返回空读数);provider 取数失败 → fail-soft 报错文本(与直连路径
|
|
251
|
+
* 同一输出契约)。
|
|
252
|
+
*/
|
|
237
253
|
function createGetDerivativesTool(options = {}) {
|
|
238
254
|
return defineTool({
|
|
239
255
|
name: "crypto_get_derivatives",
|
|
240
|
-
description: "
|
|
256
|
+
description: "Read-only derivatives snapshot for a crypto perpetual, symbol in market-canonical form, e.g. BTCUSDT-SWAP: open interest, long/short account ratio, top-trader position ratio, taker buy/sell volume ratio, funding rate, mark and index price. Source: the crypto provider chosen by market routing (same as crypto_get_derivatives_history). With no router service it falls back to Binance public endpoints; a routed provider without getDerivatives fails with TRADING_NOT_IMPLEMENTED.",
|
|
241
257
|
parameters: { symbol: {
|
|
242
258
|
type: "string",
|
|
243
259
|
required: true,
|
|
244
|
-
description: "Perpetual contract symbol, market-canonical
|
|
260
|
+
description: "Perpetual contract symbol, market-canonical form, e.g. BTCUSDT-SWAP"
|
|
245
261
|
} },
|
|
246
262
|
output: {
|
|
247
263
|
schema: { type: "string" },
|
|
@@ -253,7 +269,24 @@ function createGetDerivativesTool(options = {}) {
|
|
|
253
269
|
async execute(raw) {
|
|
254
270
|
const args = raw ?? {};
|
|
255
271
|
const symbol = typeof args.symbol === "string" ? args.symbol.trim() : "";
|
|
256
|
-
if (!symbol) throw new Error("crypto_get_derivatives: symbol parameter is required (e.g. BTCUSDT
|
|
272
|
+
if (!symbol) throw new Error("crypto_get_derivatives: symbol parameter is required (e.g. BTCUSDT-SWAP)");
|
|
273
|
+
const entry = options.getRegistry?.()?.active("crypto");
|
|
274
|
+
if (entry !== void 0) {
|
|
275
|
+
const getDerivatives = entry.service.getDerivatives;
|
|
276
|
+
if (typeof getDerivatives !== "function") throw new Error(`crypto_get_derivatives: TRADING_NOT_IMPLEMENTED — provider ${entry.provider} does not implement getDerivatives (this is not "no data")`);
|
|
277
|
+
let returned;
|
|
278
|
+
try {
|
|
279
|
+
returned = await getDerivatives.call(entry.service, symbol);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return renderDerivativesData(derivativesFailure(entry.provider, error), symbol);
|
|
282
|
+
}
|
|
283
|
+
const data = returned;
|
|
284
|
+
if (data === null || typeof data !== "object" || typeof data.symbol !== "string" || data.symbol === "") throw new Error(`crypto_get_derivatives: provider ${entry.provider} returned an invalid derivatives payload`);
|
|
285
|
+
return renderDerivativesData({
|
|
286
|
+
data,
|
|
287
|
+
provider: entry.provider
|
|
288
|
+
}, symbol);
|
|
289
|
+
}
|
|
257
290
|
const result = await fetchCryptoDerivatives({
|
|
258
291
|
symbol,
|
|
259
292
|
fetch: options.fetch
|
|
@@ -276,18 +309,18 @@ function parseDerivativesHistoryLimit(raw) {
|
|
|
276
309
|
return limit;
|
|
277
310
|
}
|
|
278
311
|
/**
|
|
279
|
-
* 衍生品历史序列工具(只读)。数据源恒为路由选中的 crypto
|
|
280
|
-
*
|
|
312
|
+
* 衍生品历史序列工具(只读)。数据源恒为路由选中的 crypto 行情服务,不直连交易所;
|
|
313
|
+
* crypto_get_derivatives 自 P6(2026-10-08)起同源(registry-first),两者不再分叉。
|
|
281
314
|
*/
|
|
282
315
|
function createGetDerivativesHistoryTool(options) {
|
|
283
316
|
return defineTool({
|
|
284
317
|
name: "crypto_get_derivatives_history",
|
|
285
|
-
description:
|
|
318
|
+
description: "Read-only derivatives history for a crypto perpetual: funding-rate and open-interest series, time-ascending, from the currently routed crypto provider (registry-first, never a hardcoded exchange). The returned symbol is market-canonical; optional limit keeps the most recent N points per series. An unimplemented getDerivativesHistory fails with TRADING_NOT_IMPLEMENTED (never an empty series); no crypto provider routed fails with TRADING_NO_PROVIDER.",
|
|
286
319
|
parameters: {
|
|
287
320
|
symbol: {
|
|
288
321
|
type: "string",
|
|
289
322
|
required: true,
|
|
290
|
-
description: "Perpetual contract symbol, market-canonical
|
|
323
|
+
description: "Perpetual contract symbol, market-canonical form, e.g. BTCUSDT-SWAP"
|
|
291
324
|
},
|
|
292
325
|
limit: {
|
|
293
326
|
type: "number",
|
|
@@ -369,7 +402,7 @@ function renderNewsItem(item) {
|
|
|
369
402
|
return `[${item.source}] ${item.publishedAt} ${item.title}\n ${item.url}`;
|
|
370
403
|
}
|
|
371
404
|
function createGetNewsTool(toolOptions = {}) {
|
|
372
|
-
const description = "Get recent crypto news from public no-key sources (Binance
|
|
405
|
+
const description = "Get recent crypto news from public no-key sources (Binance/OKX announcements, CoinDesk & The Block RSS), newest-first with source, time and link per item. " + (toolOptions.cryptoPanicKey ? "CryptoPanic key set — its free tier is queried too and degrades gracefully on failure. " : "") + "Optional symbol filter matches item titles; headlines often use asset names not tickers. Source failures are reported, not fatal. No credentials required. Cite announcements (listing, delisting, regulatory) separately from media opinion.";
|
|
373
406
|
return defineTool({
|
|
374
407
|
name: "crypto_get_news",
|
|
375
408
|
description,
|
|
@@ -416,4 +449,4 @@ function createGetNewsTool(toolOptions = {}) {
|
|
|
416
449
|
});
|
|
417
450
|
}
|
|
418
451
|
//#endregion
|
|
419
|
-
export { Config, aggregateNews, apply, createGetDerivativesHistoryTool, createGetDerivativesTool, createGetFundamentalsTool, createGetNewsTool, deriveSymbolTokens, extractBaseAsset, fetchCryptoDerivatives, fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, inject, name, normalizeBinanceFuturesSymbol, parseCryptoPanic, parseRss2, provider, providerForSkills, renderCryptoFundamentals, renderDerivativesData };
|
|
452
|
+
export { Config, aggregateNews, apply, createFundingRateTool, createGetDerivativesHistoryTool, createGetDerivativesTool, createGetFundamentalsTool, createGetNewsTool, derivativesFailure, deriveSymbolTokens, extractBaseAsset, fetchCryptoDerivatives, fetchCryptoFundamentals, fetchCryptoFundamentalsPackage, inject, name, normalizeBinanceFuturesSymbol, parseCryptoPanic, parseRss2, provider, providerForSkills, renderCryptoFundamentals, renderDerivativesData };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dshtrading/kit-crypto",
|
|
3
3
|
"description": "Crypto toolkit plugin for dsh-trading: market-specific tools and bundled trading skills (skill provider); runs as a crypto-trader preset row (session-scoped)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
],
|
|
19
19
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@dshtrading/indicators": "0.
|
|
22
|
-
"@dshtrading/knowledge": "0.
|
|
21
|
+
"@dshtrading/indicators": "0.6.0",
|
|
22
|
+
"@dshtrading/knowledge": "0.6.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"@deepseek-ai/cordis": ">=4.0.0",
|
|
26
|
-
"@deepseek-ai/dsh-skill": ">=0.
|
|
27
|
-
"@deepseek-ai/dsh-tools": ">=0.
|
|
26
|
+
"@deepseek-ai/dsh-skill": ">=0.2.0-rc.2",
|
|
27
|
+
"@deepseek-ai/dsh-tools": ">=0.2.0-rc.2",
|
|
28
28
|
"@deepseek-ai/schemastery": ">=3.18.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"tsdown": "^0.22.0",
|
|
32
32
|
"vitest": "^3.0.0",
|
|
33
|
-
"@dshtrading/api": "0.
|
|
33
|
+
"@dshtrading/api": "0.6.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsdown",
|