desic-okx-agent 0.2.0 → 0.3.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.
Files changed (237) hide show
  1. package/README.en.md +353 -0
  2. package/README.md +194 -190
  3. package/dist/account/private-websocket.js +4 -4
  4. package/dist/account/private-websocket.js.map +1 -1
  5. package/dist/account/service.d.ts +12 -1
  6. package/dist/account/service.js +18 -0
  7. package/dist/account/service.js.map +1 -1
  8. package/dist/bars/rate-limiter.d.ts +18 -0
  9. package/dist/bars/rate-limiter.js +84 -0
  10. package/dist/bars/rate-limiter.js.map +1 -0
  11. package/dist/bars/schema.d.ts +36 -0
  12. package/dist/bars/schema.js +134 -0
  13. package/dist/bars/schema.js.map +1 -0
  14. package/dist/bars/service.d.ts +60 -0
  15. package/dist/bars/service.js +120 -0
  16. package/dist/bars/service.js.map +1 -0
  17. package/dist/bars/store.d.ts +105 -0
  18. package/dist/bars/store.js +415 -0
  19. package/dist/bars/store.js.map +1 -0
  20. package/dist/bars/timeframe.d.ts +40 -0
  21. package/dist/bars/timeframe.js +146 -0
  22. package/dist/bars/timeframe.js.map +1 -0
  23. package/dist/bars/types.d.ts +68 -0
  24. package/dist/bars/types.js +13 -0
  25. package/dist/bars/types.js.map +1 -0
  26. package/dist/cli/data-render.d.ts +37 -0
  27. package/dist/cli/data-render.js +143 -0
  28. package/dist/cli/data-render.js.map +1 -0
  29. package/dist/cli/doctor.js +7 -3
  30. package/dist/cli/doctor.js.map +1 -1
  31. package/dist/cli/index.js +758 -27
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/cli/live-render.d.ts +24 -0
  34. package/dist/cli/live-render.js +85 -0
  35. package/dist/cli/live-render.js.map +1 -0
  36. package/dist/cli/range.d.ts +28 -0
  37. package/dist/cli/range.js +63 -0
  38. package/dist/cli/range.js.map +1 -0
  39. package/dist/cli/render.js +3 -0
  40. package/dist/cli/render.js.map +1 -1
  41. package/dist/cli/strategy-render.d.ts +36 -0
  42. package/dist/cli/strategy-render.js +391 -0
  43. package/dist/cli/strategy-render.js.map +1 -0
  44. package/dist/cli/width.d.ts +18 -0
  45. package/dist/cli/width.js +71 -0
  46. package/dist/cli/width.js.map +1 -0
  47. package/dist/config/loader.js +1 -1
  48. package/dist/config/schema.d.ts +7 -0
  49. package/dist/config/schema.js +24 -0
  50. package/dist/config/schema.js.map +1 -1
  51. package/dist/core/okx-client.d.ts +9 -1
  52. package/dist/core/okx-client.js +14 -5
  53. package/dist/core/okx-client.js.map +1 -1
  54. package/dist/i18n/locale.d.ts +24 -0
  55. package/dist/i18n/locale.js +65 -0
  56. package/dist/i18n/locale.js.map +1 -0
  57. package/dist/i18n/messages.d.ts +333 -0
  58. package/dist/i18n/messages.js +660 -0
  59. package/dist/i18n/messages.js.map +1 -0
  60. package/dist/live/account-snapshot.d.ts +30 -0
  61. package/dist/live/account-snapshot.js +130 -0
  62. package/dist/live/account-snapshot.js.map +1 -0
  63. package/dist/live/cutoff-queue.d.ts +42 -0
  64. package/dist/live/cutoff-queue.js +69 -0
  65. package/dist/live/cutoff-queue.js.map +1 -0
  66. package/dist/live/execution-key.d.ts +23 -0
  67. package/dist/live/execution-key.js +31 -0
  68. package/dist/live/execution-key.js.map +1 -0
  69. package/dist/live/failures.d.ts +37 -0
  70. package/dist/live/failures.js +57 -0
  71. package/dist/live/failures.js.map +1 -0
  72. package/dist/live/gates.d.ts +65 -0
  73. package/dist/live/gates.js +136 -0
  74. package/dist/live/gates.js.map +1 -0
  75. package/dist/live/loop.d.ts +56 -0
  76. package/dist/live/loop.js +197 -0
  77. package/dist/live/loop.js.map +1 -0
  78. package/dist/live/preconditions.d.ts +48 -0
  79. package/dist/live/preconditions.js +69 -0
  80. package/dist/live/preconditions.js.map +1 -0
  81. package/dist/live/reconcile.d.ts +46 -0
  82. package/dist/live/reconcile.js +104 -0
  83. package/dist/live/reconcile.js.map +1 -0
  84. package/dist/live/runner.d.ts +57 -0
  85. package/dist/live/runner.js +160 -0
  86. package/dist/live/runner.js.map +1 -0
  87. package/dist/live/schema.d.ts +18 -0
  88. package/dist/live/schema.js +91 -0
  89. package/dist/live/schema.js.map +1 -0
  90. package/dist/live/service.d.ts +144 -0
  91. package/dist/live/service.js +303 -0
  92. package/dist/live/service.js.map +1 -0
  93. package/dist/live/session.d.ts +85 -0
  94. package/dist/live/session.js +234 -0
  95. package/dist/live/session.js.map +1 -0
  96. package/dist/live/sizing.d.ts +62 -0
  97. package/dist/live/sizing.js +79 -0
  98. package/dist/live/sizing.js.map +1 -0
  99. package/dist/live/store.d.ts +123 -0
  100. package/dist/live/store.js +350 -0
  101. package/dist/live/store.js.map +1 -0
  102. package/dist/live/types.d.ts +82 -0
  103. package/dist/live/types.js +2 -0
  104. package/dist/live/types.js.map +1 -0
  105. package/dist/market/websocket.d.ts +16 -1
  106. package/dist/market/websocket.js +60 -5
  107. package/dist/market/websocket.js.map +1 -1
  108. package/dist/mcp/server.d.ts +1 -0
  109. package/dist/mcp/server.js +15 -1
  110. package/dist/mcp/server.js.map +1 -1
  111. package/dist/network/connectivity.d.ts +9 -1
  112. package/dist/network/connectivity.js +28 -1
  113. package/dist/network/connectivity.js.map +1 -1
  114. package/dist/report/chart-script.d.ts +12 -0
  115. package/dist/report/chart-script.js +146 -0
  116. package/dist/report/chart-script.js.map +1 -0
  117. package/dist/report/compare-html.d.ts +8 -0
  118. package/dist/report/compare-html.js +254 -0
  119. package/dist/report/compare-html.js.map +1 -0
  120. package/dist/report/compare-script.d.ts +12 -0
  121. package/dist/report/compare-script.js +109 -0
  122. package/dist/report/compare-script.js.map +1 -0
  123. package/dist/report/compare.d.ts +61 -0
  124. package/dist/report/compare.js +205 -0
  125. package/dist/report/compare.js.map +1 -0
  126. package/dist/report/fetch.d.ts +20 -0
  127. package/dist/report/fetch.js +56 -0
  128. package/dist/report/fetch.js.map +1 -0
  129. package/dist/report/html.d.ts +54 -0
  130. package/dist/report/html.js +641 -0
  131. package/dist/report/html.js.map +1 -0
  132. package/dist/report/open.d.ts +42 -0
  133. package/dist/report/open.js +114 -0
  134. package/dist/report/open.js.map +1 -0
  135. package/dist/runtime/server.d.ts +16 -1
  136. package/dist/runtime/server.js +112 -9
  137. package/dist/runtime/server.js.map +1 -1
  138. package/dist/setup/installer.d.ts +1 -0
  139. package/dist/setup/installer.js +8 -0
  140. package/dist/setup/installer.js.map +1 -1
  141. package/dist/setup/wizard.d.ts +3 -0
  142. package/dist/setup/wizard.js +131 -6
  143. package/dist/setup/wizard.js.map +1 -1
  144. package/dist/strategy/constants.d.ts +23 -0
  145. package/dist/strategy/constants.js +24 -0
  146. package/dist/strategy/constants.js.map +1 -0
  147. package/dist/strategy/environment.d.ts +52 -0
  148. package/dist/strategy/environment.js +187 -0
  149. package/dist/strategy/environment.js.map +1 -0
  150. package/dist/strategy/instrument.d.ts +29 -0
  151. package/dist/strategy/instrument.js +39 -0
  152. package/dist/strategy/instrument.js.map +1 -0
  153. package/dist/strategy/optimize.d.ts +73 -0
  154. package/dist/strategy/optimize.js +113 -0
  155. package/dist/strategy/optimize.js.map +1 -0
  156. package/dist/strategy/parameter-space.d.ts +59 -0
  157. package/dist/strategy/parameter-space.js +221 -0
  158. package/dist/strategy/parameter-space.js.map +1 -0
  159. package/dist/strategy/python-bridge.d.ts +24 -0
  160. package/dist/strategy/python-bridge.js +114 -0
  161. package/dist/strategy/python-bridge.js.map +1 -0
  162. package/dist/strategy/schema.d.ts +9 -0
  163. package/dist/strategy/schema.js +91 -0
  164. package/dist/strategy/schema.js.map +1 -0
  165. package/dist/strategy/service.d.ts +138 -0
  166. package/dist/strategy/service.js +745 -0
  167. package/dist/strategy/service.js.map +1 -0
  168. package/dist/strategy/settings.d.ts +162 -0
  169. package/dist/strategy/settings.js +243 -0
  170. package/dist/strategy/settings.js.map +1 -0
  171. package/dist/strategy/store.d.ts +96 -0
  172. package/dist/strategy/store.js +367 -0
  173. package/dist/strategy/store.js.map +1 -0
  174. package/dist/strategy/templates.d.ts +11 -0
  175. package/dist/strategy/templates.js +134 -0
  176. package/dist/strategy/templates.js.map +1 -0
  177. package/dist/strategy/types.d.ts +111 -0
  178. package/dist/strategy/types.js +2 -0
  179. package/dist/strategy/types.js.map +1 -0
  180. package/dist/tools/catalog.d.ts +16 -0
  181. package/dist/tools/catalog.js +118 -17
  182. package/dist/tools/catalog.js.map +1 -1
  183. package/dist/trade/service.d.ts +12 -0
  184. package/dist/trade/service.js +24 -7
  185. package/dist/trade/service.js.map +1 -1
  186. package/dist/tui/app.d.ts +23 -0
  187. package/dist/tui/app.js +322 -0
  188. package/dist/tui/app.js.map +1 -0
  189. package/dist/tui/commands.d.ts +70 -0
  190. package/dist/tui/commands.js +313 -0
  191. package/dist/tui/commands.js.map +1 -0
  192. package/dist/tui/entries.d.ts +17 -0
  193. package/dist/tui/entries.js +24 -0
  194. package/dist/tui/entries.js.map +1 -0
  195. package/dist/tui/execute.d.ts +26 -0
  196. package/dist/tui/execute.js +664 -0
  197. package/dist/tui/execute.js.map +1 -0
  198. package/dist/tui/history.d.ts +17 -0
  199. package/dist/tui/history.js +48 -0
  200. package/dist/tui/history.js.map +1 -0
  201. package/dist/tui/index.d.ts +8 -0
  202. package/dist/tui/index.js +48 -0
  203. package/dist/tui/index.js.map +1 -0
  204. package/dist/tui/line-editor.d.ts +44 -0
  205. package/dist/tui/line-editor.js +98 -0
  206. package/dist/tui/line-editor.js.map +1 -0
  207. package/dist/tui/progress.d.ts +23 -0
  208. package/dist/tui/progress.js +46 -0
  209. package/dist/tui/progress.js.map +1 -0
  210. package/dist/tui/settings-editor.d.ts +18 -0
  211. package/dist/tui/settings-editor.js +115 -0
  212. package/dist/tui/settings-editor.js.map +1 -0
  213. package/docs/live-trading.md +455 -0
  214. package/docs/strategy-research.md +597 -0
  215. package/package.json +11 -1
  216. package/python/desic_strategy/__init__.py +34 -0
  217. package/python/desic_strategy/actions.py +158 -0
  218. package/python/desic_strategy/context.py +164 -0
  219. package/python/desic_strategy/engine.py +614 -0
  220. package/python/desic_strategy/indicators.py +159 -0
  221. package/python/desic_strategy/live.py +253 -0
  222. package/python/desic_strategy/policy.py +193 -0
  223. package/python/desic_strategy/portfolio.py +152 -0
  224. package/python/desic_strategy/report.py +319 -0
  225. package/python/desic_strategy/runner.py +574 -0
  226. package/python/desic_strategy/timeframe.py +150 -0
  227. package/python/main.py +18 -0
  228. package/skills/okx-live-trading/SKILL.md +117 -0
  229. package/skills/okx-live-trading/agents/openai.yaml +9 -0
  230. package/skills/okx-live-trading/references/lifecycle.md +128 -0
  231. package/skills/okx-strategy-research/SKILL.md +113 -0
  232. package/skills/okx-strategy-research/agents/openai.yaml +9 -0
  233. package/skills/okx-strategy-research/references/execution-semantics.md +107 -0
  234. package/skills/okx-strategy-research/references/field-traps.md +142 -0
  235. package/skills/okx-strategy-research/references/python-api.md +121 -0
  236. package/skills/okx-strategy-research/references/tools-and-data.md +192 -0
  237. package/skills/okx-trading/SKILL.md +11 -10
@@ -0,0 +1,455 @@
1
+ # 实盘执行使用指南
2
+
3
+ 把已验证的策略接到真实账户,每根 1 分钟收线自动执行。
4
+
5
+ > **这部分会用真钱下单。**
6
+ >
7
+ > 下面每一处约束都是为了让"错误可见且可停",不是为了让功能看起来完整。请先读[必须知道的限制](#必须知道的限制)。
8
+
9
+ **强烈建议先在模拟盘跑够信号历史**,确认幂等、恢复、风控都按预期工作,再考虑实盘。
10
+
11
+ 这是整条链的最后一段。上游是[策略研究](strategy-research.md) —— 写策略、回测、调参;启用实盘的硬性前置条件就是上游产出的回测记录。两条路径(你自己做 / 交给 AI)走的是同一条链,区别见[给 AI agent 用](#给-ai-agent-用)。
12
+
13
+ ---
14
+
15
+ ## 目录
16
+
17
+ - [十分钟跑通模拟盘](#十分钟跑通模拟盘)
18
+ - [三个概念](#三个概念)
19
+ - [启用前置条件](#启用前置条件)
20
+ - [风控闸门](#风控闸门)
21
+ - [读信号历史](#读信号历史)
22
+ - [自动停用](#自动停用)
23
+ - [崩溃恢复](#崩溃恢复)
24
+ - [切换到实盘](#切换到实盘)
25
+ - [命令参考](#命令参考)
26
+ - [给 AI agent 用](#给-ai-agent-用)
27
+ - [常见问题](#常见问题)
28
+ - [必须知道的限制](#必须知道的限制)
29
+
30
+ ---
31
+
32
+ ## 十分钟跑通模拟盘
33
+
34
+ ```bash
35
+ # 1. 行情切到模拟盘,重启生效
36
+ desic-okx market env demo
37
+ desic-okx stop
38
+
39
+ # 2. 补数据(模拟盘与实盘是两套独立行情,需各自下载)
40
+ desic-okx data download --inst BTC-USDT-SWAP --days 2
41
+
42
+ # 3. 回测一次 —— 这是启用的硬性前置条件
43
+ desic-okx strategy backtest --file ema.py --inst BTC-USDT-SWAP --days 1 --follow
44
+
45
+ # 4. 创建 Profile(创建绝不会开始交易)
46
+ desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account demo \
47
+ --environment demo --entry-budget 100 --side-budget 200 --daily-loss 500
48
+
49
+ # 5. 看还差什么
50
+ desic-okx live readiness --id lp_xxxx
51
+
52
+ # 6. 启用 —— 从这一刻起,每根收线都会真实执行
53
+ desic-okx live start --id lp_xxxx
54
+
55
+ # 7. 观察
56
+ desic-okx live signals --id lp_xxxx
57
+
58
+ # 8. 停止
59
+ desic-okx live stop --id lp_xxxx
60
+ ```
61
+
62
+ 第 6 步之后就会真实下单。第 4 步的 `--entry-budget 100` 配 10 倍杠杆约合 1,000 USDT 名义敞口 —— **闸门按 Profile 预算限制,不按账户余额**,所以账户里有多少钱不影响单笔规模。第 6 步还会把这个 10 倍[写到交易所](#启用会改动交易所的杠杆设置),否则预算数字不成立。
63
+
64
+ ---
65
+
66
+ ## 三个概念
67
+
68
+ **Profile** —— 策略 + 合约 + 账户 + 风控预算的绑定。它存的是**策略源码快照**,不是文件路径:文件会被改,而 Profile 必须继续交易"启用时被审阅过的那一版",否则保存一次文件就悄悄改变了运行中的实盘行为。
69
+
70
+ 一个账户 + 一个环境 + 一个合约只能有一个 Profile。两个会各自基于对方开出的仓位算规模。
71
+
72
+ **Signal(信号)** —— 每根收线一条记录。`UNIQUE(profile, cutoff)` 是幂等的根基:无论 K 线被重复投递多少次、运行时重启多少次,**一根收线最多产生一个订单**。
73
+
74
+ **闸门(Gate)** —— 策略意图与订单之间的一串检查。**每一道都是拒绝,没有一个是修正。**
75
+
76
+ 最后这点值得展开。假设单笔预算 50 USDT,策略意图按当前权益需要 80:
77
+
78
+ - **修正**(不采用):砍到 50 下单。你看到一笔成交,不知道规模被改过。
79
+ - **拒绝**(采用):不下单,记一条 `blocked` 信号,写明"超过单笔预算"。
80
+
81
+ 修正会让风控变得**不可见** —— 你以为策略在按设计运行,实际主机一直在悄悄改写它。
82
+
83
+ ---
84
+
85
+ ## 启用前置条件
86
+
87
+ 启用时一次性检查,**全部不满足项一起报出**(不是每次暴露一个)。
88
+
89
+ | 条件 | 为什么 |
90
+ |---|---|
91
+ | 该源码 + 该合约**已完成回测** | 否则没有任何证据说明它可行 |
92
+ | Python 环境就绪 | 否则第一根收线就失败 |
93
+ | 账户凭证被交易所接受 | |
94
+ | API key 有交易权限 | 否则每笔订单都被拒 |
95
+ | 合约规格可读 | 张数换算的依据 |
96
+ | Profile 环境 == 行情环境 | 见下 |
97
+
98
+ 每一项都是**可验证的系统事实**。"该不该投真钱"不在这个清单里 —— 那不是系统能验证的事实,而是你的判断。
99
+
100
+ ### 启用会改动交易所的杠杆设置
101
+
102
+ 前置条件全部通过后,启用会在写库之前把 Profile 的 `--leverage` **写到交易所**(`set-leverage`,按 Profile 的 `instId` + `marginMode`)。写失败则拒绝启用。
103
+
104
+ **这一步是必须的,因为预算的含义依赖它。** 张数由 `预算 × 杠杆 ÷ 价格` 算出,交易所则按它自己记录的杠杆收保证金。两个数不一致时,预算说的和实际占用的就不是一回事:
105
+
106
+ > 实测(模拟盘):Profile 配 10 倍、账户实际留在 3 倍,`--entry-budget 60` 开出 0.77 张,交易所按 3 倍收了约 **198 USDT** 保证金 —— 预算被突破 3.3 倍。写入杠杆后同样的配置,交易所报 `imr: 59.60`,与 60 USDT 预算吻合。
107
+
108
+ 代价要知道:**这会改动该账户在这个合约 + 保证金模式上的共享杠杆设置**,包括你手动开的仓位。这也是为什么它发生在启用这一步,而不是每根收线偷偷改。
109
+
110
+ 执行键由意图派生(`live-leverage:<profileId>:<杠杆>:<模式>`),所以重复启用不会写第二条执行记录。
111
+
112
+ ### 一条是刻意的摩擦
113
+
114
+ **"已完成回测"**按**源码 hash** 匹配,不是文件名或路径 —— 后两者在文件被编辑后仍会匹配上。
115
+
116
+ 而且门槛是"**跑过**回测",不是"结果好"。亏钱的回测同样通过,因为它证明了策略能跑完、没崩溃、且你看过它的行为。要求盈利只会让人不停调参直到数字好看 —— 那恰好是过拟合。
117
+
118
+ ### AI 启用实盘前必须先问你
119
+
120
+ 前置条件全部通过只说明这个 Profile **可以**启动,不说明**应该**启动。
121
+
122
+ 默认情况下 AI 根本看不到启用工具(见[给 AI agent 用](#给-ai-agent-用))。但一旦你开了 `live agent-access on`,**系统就不会再拦住它启用实盘** —— 这是刻意的。
123
+
124
+ 曾经有一版要求手打 Profile 名字,但那道摩擦对人价值很小(你就是刚创建它的人),实际只挡住了 AI,把"该不该交易"变成了"能不能猜到一个字符串"。那不是同一个问题,也不会让决定变得更明智。
125
+
126
+ 现在的约束写在 AI 的 Skill 里:启用 `environment: live` 的 Profile 前必须停下来问你,并且必须给出配置、预算、回测的**验证段**指标、以及模拟盘跑出的信号统计。"要不要启动?"这样光秃秃一句不算问 —— 你需要数字才能有意义地回答。
127
+
128
+ ### 环境必须一致
129
+
130
+ Profile 环境与行情环境不一致会被拒绝。模拟盘和实盘是**两个独立市场、价格不同**(实测同一时刻价差数美元、24h 成交量差 5 倍),一个在实盘交易的 Profile 基于模拟盘 K 线决策,等于用一个从未适用于它自身市场的价格做判断。
131
+
132
+ ```bash
133
+ desic-okx market env # 查看行情环境
134
+ desic-okx market env live # 切换,需重启
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 风控闸门
140
+
141
+ 每根收线按顺序检查,**从便宜到昂贵** —— Profile 自身设置就已禁止的决策,不会走到需要网络请求的 `precheck`。
142
+
143
+ | # | 闸门 | 拦什么 |
144
+ |---|---|---|
145
+ | 1 | Profile 已启用 | |
146
+ | 2 | generation 未变 | 评估期间你点了停止 |
147
+ | 3 | 方向权限 | 只允许做多却收到 `open_short` |
148
+ | 4 | 单笔预算 | 一次开仓的保证金上限 |
149
+ | 5 | 同向总预算 | 已有多仓 40,再开 40 会超上限 |
150
+ | 6 | 当日亏损限额 | 今日已实现亏损触及限额 |
151
+ | 7 | 冷却时间 | 上次**下单**后 N 秒内不再下单 |
152
+ | 8 | 张数 ≥ `minSz` + `precheck` | 合约规格、权限 |
153
+
154
+ 第 2 条是 TOCTOU 防护:检查与提交之间有时间差,停止可能落在这个缝隙里。提交前会**再查一次** generation。
155
+
156
+ ### 平仓刻意跳过 4/5/6/7
157
+
158
+ 平仓**按持仓量算张数,不按预算**,且跳过预算、亏损、冷却三道闸门。
159
+
160
+ 两个理由:
161
+
162
+ - 一个阻止你平掉亏损仓位的亏损限额,只会让亏损更大 —— 与它存在的目的正好相反
163
+ - 按预算算出的部分平仓,会留下策略以为已经清掉的敞口
164
+
165
+ 方向权限同理:禁止做多的 Profile 仍可平掉已有多仓,否则会把仓位困死。
166
+
167
+ 平仓单带 `reduceOnly` —— 迟到的成交只会平仓,不会反向开新仓。
168
+
169
+ ### 数字全部来自交易所
170
+
171
+ - **持仓 / 已用保证金**:OKX 的 `imr`(本地推导在全仓模式下会与交易所不一致)
172
+ - **当日已实现亏损**:从当天成交汇总,**含手续费**(一整天全花在成本上是真实亏损),按 UTC 日切分
173
+ - **可用权益**:读逐币种明细而非账户汇总(OKX 在某些账户模式下把顶层 `availEq` 留空)
174
+
175
+ 本地账本一旦遇到手动平仓、部分成交或强平就会漂移,而策略基于漂移的数字决策,正是整个设计要避免的失败。
176
+
177
+ ---
178
+
179
+ ## 读信号历史
180
+
181
+ ```bash
182
+ desic-okx live signals --id lp_xxxx --limit 30
183
+ ```
184
+
185
+ ```
186
+ 分钟 动作 状态 详情 张数
187
+ 18:52 no_action no_action holding probe position -
188
+ 18:51 open_long submitted 3859050322711461888 probe entry 1.29
189
+ 18:50 open_long blocked side_budget: 同向预算已满 -
190
+ 18:49 open_long error Order precheck failed -
191
+ ```
192
+
193
+ 六种状态:
194
+
195
+ | 状态 | 含义 |
196
+ |---|---|
197
+ | `no_action` | 策略没有请求任何动作 |
198
+ | `submitted` | 订单已到交易所 |
199
+ | `blocked` | 某道闸门拒绝了,`详情`列出是哪一道 |
200
+ | `error` | 评估失败 |
201
+ | `ambiguous` | **结果未知,等人处理**(见下) |
202
+ | `reserved` | 已占位但未决策(崩溃残留) |
203
+
204
+ ### `blocked` 记录比成交更重要
205
+
206
+ 它们是**风控运行过的证据**。只存成交的话,"今天没下单"有两种可能 —— 风控挡住了,或者代码根本没跑。这两种必须能区分。
207
+
208
+ ### `ambiguous` 需要人工介入
209
+
210
+ 意味着订单**可能存在也可能不存在**。系统**绝不自动重试** —— 重发一个可能已存在的订单,比漏掉一个更糟。
211
+
212
+ 看到 `ambiguous` 时:
213
+
214
+ ```bash
215
+ desic-okx account get-order --inst BTC-USDT-SWAP --ord-id <详情里的ID>
216
+ desic-okx call account_get_positions --json '{"account":"demo"}'
217
+ ```
218
+
219
+ 确认交易所实际状态后再决定。
220
+
221
+ ---
222
+
223
+ ## 自动停用
224
+
225
+ 连续 **3** 次**系统性**失败 → 自动停用 Profile 并写明原因。
226
+
227
+ 关键在于**哪些失败计数**:
228
+
229
+ | 计数(不会自愈) | 不计数(会自愈) |
230
+ |---|---|
231
+ | 缺少 Python 环境 | 连接断开 |
232
+ | 源码违规 | 频率限制 |
233
+ | 权限被撤 | 数据窗口待修补 |
234
+ | 策略抛异常 | socket 断开 |
235
+ | **`AMBIGUOUS_WRITE`** | |
236
+ | **任何无法识别的错误** | |
237
+
238
+ 两个刻意的决定:
239
+
240
+ **`AMBIGUOUS_WRITE` 计数**,尽管它本质是网络症状 —— 它意味着订单状态未知,在未知持仓上继续交易正是最该快速停下的情况。
241
+
242
+ **无法识别的错误计数** —— 反复出现的未知故障恰恰是自动停用存在的理由。
243
+
244
+ 不计数的失败**仍会记录**为 `lastError`,只是不推向停用。连续 20 次网络失败,Profile 依然在跑。
245
+
246
+ 数的是**连续**失败:一次成功清零。但两次真实故障之间夹一次网络抖动**不清零** —— 故障还在那里。
247
+
248
+ 停用会递增 generation,所以已决定但未提交的动作会被拦住。
249
+
250
+ ---
251
+
252
+ ## 崩溃恢复
253
+
254
+ 运行时启动时自动执行,无需干预:
255
+
256
+ 1. `status='running'` 的 Profile 标为 `stopped` 并递增 generation(worker 已不存在)
257
+ 2. 等 750ms 让 `executions` 表先完成自己的恢复
258
+ 3. 找出 `reserved` / `submitted` 状态的信号
259
+ 4. **向交易所对账**,不假设成功或失败
260
+
261
+ ### 最关键的一个区分
262
+
263
+ **"交易所说没有这笔订单"** ≠ **"问不到交易所"**
264
+
265
+ 第一个是答案,可以关闭信号。第二个不是 —— 把它当成第一个,会静默丢弃一笔可能已成交的订单,所以标为 `ambiguous`。
266
+
267
+ 仍在挂单或部分成交的订单也标 `ambiguous`,不自动处理:那是策略不知道的持仓,自动平掉等于替你决定如何处置还没看到的敞口。
268
+
269
+ ### 为什么能对账
270
+
271
+ `clOrdId` 从 `(profileId, cutoffAt)` **确定性派生** —— 正是信号表 UNIQUE 约束的那一对。所以恢复能查询一笔它从未见过响应的订单。有测试把这个派生钉死在实际发出的 id 上:两处一旦分叉,恢复会查一个交易所从未收到的 id,然后得出"没有订单"的错误结论。
272
+
273
+ 验证方式:
274
+
275
+ ```bash
276
+ kill -9 <runtime pid>
277
+ desic-okx start
278
+ grep "live-signals-reconciled" <数据目录>/run/lifecycle.log
279
+ ```
280
+
281
+ ---
282
+
283
+ ## 切换到实盘
284
+
285
+ **在做够模拟盘验证之前不要做这一步。**
286
+
287
+ 至少确认过:
288
+ - 信号历史里有 `submitted`、`blocked`、`no_action` 三种记录,且都合理
289
+ - 至少经历过一次 `kill -9` 重启并看到对账日志
290
+ - 单笔规模与你的预期一致
291
+
292
+ ### 步骤
293
+
294
+ ```bash
295
+ # 1. 配置实盘账户(权限不要勾提币,建议绑 IP 白名单)
296
+ desic-okx account add --name main
297
+
298
+ # 2. 行情切实盘
299
+ desic-okx market env live
300
+ desic-okx stop
301
+
302
+ # 3. 实盘数据是独立的,需重新下载
303
+ desic-okx data download --inst BTC-USDT-SWAP --days 90
304
+
305
+ # 4. 用实盘数据重跑回测(前置条件按 hash + 合约匹配,换环境要重跑)
306
+ desic-okx strategy backtest --file ema.py --inst BTC-USDT-SWAP --days 30 --follow
307
+
308
+ # 5. 创建实盘 Profile —— 预算设小
309
+ desic-okx live create --file ema.py --inst BTC-USDT-SWAP --account main \
310
+ --environment live --entry-budget 50 --side-budget 100 --daily-loss 100 \
311
+ --name ema-btc-live
312
+
313
+ # 6. 启用
314
+ desic-okx live start --id lp_xxxx
315
+ ```
316
+
317
+ 第 3 步不能省:模拟盘和实盘 K 线不同,`dataSnapshotId` 不可跨环境复用。
318
+
319
+ ### 建议的第一次实盘配置
320
+
321
+ - `--entry-budget` 设成你**能接受全部亏掉**的金额
322
+ - `--daily-loss` 设成单笔预算的 1–2 倍,让它很容易触发(先验证限额工作,再放宽)
323
+ - `--cooldown 300` 或更长,限制出错时的下单频率
324
+ - 先只允许一个方向(`--no-short`),减少一半的意外面
325
+
326
+ ---
327
+
328
+ ## 命令参考
329
+
330
+ ```bash
331
+ desic-okx live list # 全部 Profile 及状态
332
+ desic-okx live create --file ... --inst ... --account ... # 创建(不会启动)
333
+ desic-okx live readiness --id <id> # 还差什么
334
+ desic-okx live start --id <id> # 启用
335
+ desic-okx live stop --id <id> [--reason "..."] # 停止(永远允许)
336
+ desic-okx live signals --id <id> [--limit 30] # 决策历史
337
+ desic-okx live delete --id <id> --yes # 删除(需先停止)
338
+ ```
339
+
340
+ `create` 的必填项:`--file` `--inst` `--account` `--entry-budget` `--side-budget` `--daily-loss`
341
+
342
+ 可选项:`--name` `--environment`(默认 demo)`--leverage`(默认 10)`--margin-mode`(默认 cross)`--cooldown`(默认 0)`--params` `--no-long` `--no-short`
343
+
344
+ ### 交互界面
345
+
346
+ ```
347
+ > /live 列出全部
348
+ > /live signals <id> 决策历史
349
+ > /live stop <id> 停止
350
+ ```
351
+
352
+ **创建和启动刻意不在交互界面** —— 它们是把资金投入某个策略的两个动作,一个按键就能开始交易的界面不值得信任。
353
+
354
+ ---
355
+
356
+ ## 给 AI agent 用
357
+
358
+ 默认只暴露**只读 + 停止**:
359
+
360
+ | 工具 | 用途 |
361
+ |---|---|
362
+ | `live_list_profiles` | 全部 Profile 及状态 |
363
+ | `live_get_profile` | 单个 Profile |
364
+ | `live_readiness` | 阻碍启动的项 |
365
+ | `live_signals` | 决策历史,含每次拒绝与对应闸门 |
366
+ | `live_stop` | 停止(永远允许) |
367
+
368
+ **默认情况下 `live_create_profile`、`live_start`、`live_delete_profile` 不在 MCP 工具列表里** —— 不是拒绝调用,而是根本不出现在清单中。agent 看不到的工具不会去猜,也不会去试。
369
+
370
+ ### 打开 agent 的实盘权限
371
+
372
+ ```bash
373
+ desic-okx live agent-access on # 允许 agent 创建和启用
374
+ desic-okx live agent-access # 查看当前设置
375
+ desic-okx live agent-access off # 收回
376
+ ```
377
+
378
+ **需重启 MCP 客户端生效** —— 工具列表在客户端连接时构建一次,改配置不会影响已连接的会话。
379
+
380
+ 开启后 agent 能跑完整条链:写策略 → 回测 → 调参 → 建 Profile → 启用 → 读信号 → 停止。这是刻意的:把"AI 自动分析交易"和"用户手写策略回测"接成一条链,而不是两个各自独立的功能。
381
+
382
+ ### 创建 Profile 时必须给出理由
383
+
384
+ `origin` 为 `agent` 的 Profile 必须带 `rationale`。这不是装饰 —— 它把"为什么要建这个 Profile"和 Profile 本身存在一起,你之后翻 `live list` 时能看到当初的判断依据,而不是一行来历不明的配置。
385
+
386
+ ### 启用实盘前 Skill 要求先问你
387
+
388
+ 前置条件全部通过只说明**可以**启动。`okx-live-trading` Skill 里写明:模拟盘上放手做,启用 `environment: live` 的 Profile 前必须停下来问你,并给出 Profile 配置、三个预算、回测的**验证段**指标、以及模拟盘跑出的信号统计。Skill 明确写了"要不要启动?"这样光秃秃一句不算问。
389
+
390
+ 系统不会替你拦这一步(见上文[启用前置条件](#启用前置条件))。开 `agent-access` 就是把这个信任交出去了。
391
+
392
+ ---
393
+
394
+ ## 常见问题
395
+
396
+ **信号全是 `error Order precheck failed`**
397
+ 查 `desic-okx live signals` 的详情列。如果是 `Market decision snapshot is not time-consistent`,说明用的不是实盘循环路径 —— 实盘会自动传 `executabilityOnly`(资金费率每 8 小时才更新,物理上无法与 ticker 对齐到 1 秒内)。其他 blocker 是真实问题。
398
+
399
+ **启用被拒,提示 "No completed backtest"**
400
+ 用该策略源码 + 该合约跑一次回测。注意源码改一个字符 hash 就变了,需重跑。换环境(demo↔live)也要重跑。
401
+
402
+ **启用被拒,提示 "market data is streaming from ..."**
403
+ Profile 环境与行情环境不一致。`desic-okx market env <环境>` 后重启。
404
+
405
+ **Profile 自动停用了**
406
+ `desic-okx live list` 看 `连续错误` 列,`live_get_profile` 看 `lastError`。连续 3 次系统性失败会自动停 —— 先解决根因再重新启用。
407
+
408
+ **信号是 `ambiguous`**
409
+ 订单状态未知,**不会自动重试**。用 `account_get_order` 和 `account_get_positions` 确认交易所实际状态,再决定。
410
+
411
+ **策略读到的持仓是空的,但交易所有仓位**
412
+ 检查 Profile 的 `instId` 是否与持仓合约一致。策略只看到自己合约的持仓。
413
+
414
+ **改了策略文件,实盘行为没变**
415
+ 这是刻意的。Profile 绑定的是**启用时的源码快照**。要用新版本:停止 → 用新文件重跑回测 → 新建 Profile。
416
+
417
+ ---
418
+
419
+ ## 必须知道的限制
420
+
421
+ **这是自动交易,不是"会赚钱"。** 回测通过只证明策略能跑完并且你看过它的行为 —— 亏钱的回测同样能启用。
422
+
423
+ **明确不支持:**
424
+
425
+ - **`set_protection` / `cancel_protection`** —— 原生改单与对账未实现。入场时可附带 TP/SL 请求,但不支持动态修改。回测里完全可用。
426
+ - **反手** —— 必须先平后开,与回测一致。持多仓时直接 `open_short` 会报错。
427
+ - **一个 Profile 一个合约** —— 多合约需要多个 Profile。
428
+ - **热切换环境** —— 改配置后必须重启 runtime。
429
+
430
+ **评估的时间约束:**
431
+
432
+ - 策略单次决策超过 **5 秒**视为故障,跳过本轮(会话保持存活,指标状态不丢)
433
+ - 会话内存保留最近 **20,000** 根 K 线
434
+ - 新会话预热 **300** 根历史,预热不产生决策
435
+
436
+ **数据完整性是 fail-closed 的:**窗口有缺口时**拒绝评估**,不会基于残缺数据下单。
437
+
438
+ **回测与实盘的决策一致,但成交不一致。** 同一策略同一段历史,两条路径的决策序列完全相同(有测试保证)。但回测的成交是模拟的:固定手续费滑点、下根开盘成交、限价单按 K 线保守估计、无订单簿队列。实盘成交由交易所决定。
439
+
440
+ **风控闸门限制的是规模和频率,不是亏损。** 它们能阻止"单笔过大"和"频繁下单",但阻止不了一个持续做出错误决策的策略慢慢亏光。**当日亏损限额是唯一的止损性约束,把它设小。**
441
+
442
+ ---
443
+
444
+ ## 相关文件位置
445
+
446
+ | 内容 | 路径 |
447
+ |---|---|
448
+ | 账户凭证 | 配置目录 `config.json`(**明文**,仅靠文件权限 0600 保护) |
449
+ | Profile 与信号 | 数据目录 SQLite 的 `live_profiles` / `live_signals` |
450
+ | 幂等记录 | 同库 `executions` 表 |
451
+ | 运行日志 | 数据目录 `run/lifecycle.log` |
452
+
453
+ `desic-okx status` 和 `desic-okx doctor` 会打印实际路径。
454
+
455
+ 策略编写与回测见 **[策略研究使用指南](strategy-research.md)**。