jcc_hyper_tool 0.1.4 → 0.1.6
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/README.md +159 -21
- package/dist/advisor/actionRunner.d.ts +35 -0
- package/dist/advisor/actionRunner.d.ts.map +1 -0
- package/dist/advisor/actionRunner.js +194 -0
- package/dist/advisor/actionRunner.js.map +1 -0
- package/dist/advisor/actionSchema.d.ts +1551 -0
- package/dist/advisor/actionSchema.d.ts.map +1 -0
- package/dist/advisor/actionSchema.js +202 -0
- package/dist/advisor/actionSchema.js.map +1 -0
- package/dist/advisor/adviseDisplay.d.ts +26 -0
- package/dist/advisor/adviseDisplay.d.ts.map +1 -0
- package/dist/advisor/adviseDisplay.js +174 -0
- package/dist/advisor/adviseDisplay.js.map +1 -0
- package/dist/advisor/adviseEngine.d.ts +53 -0
- package/dist/advisor/adviseEngine.d.ts.map +1 -0
- package/dist/advisor/adviseEngine.js +172 -0
- package/dist/advisor/adviseEngine.js.map +1 -0
- package/dist/advisor/ambushPolicy.d.ts +47 -0
- package/dist/advisor/ambushPolicy.d.ts.map +1 -0
- package/dist/advisor/ambushPolicy.js +161 -0
- package/dist/advisor/ambushPolicy.js.map +1 -0
- package/dist/advisor/contextBuilder.d.ts +51 -0
- package/dist/advisor/contextBuilder.d.ts.map +1 -0
- package/dist/advisor/contextBuilder.js +153 -0
- package/dist/advisor/contextBuilder.js.map +1 -0
- package/dist/advisor/deepseekClient.d.ts +26 -0
- package/dist/advisor/deepseekClient.d.ts.map +1 -0
- package/dist/advisor/deepseekClient.js +96 -0
- package/dist/advisor/deepseekClient.js.map +1 -0
- package/dist/advisor/executionPolicy.d.ts +92 -0
- package/dist/advisor/executionPolicy.d.ts.map +1 -0
- package/dist/advisor/executionPolicy.js +273 -0
- package/dist/advisor/executionPolicy.js.map +1 -0
- package/dist/advisor/guards.d.ts +31 -0
- package/dist/advisor/guards.d.ts.map +1 -0
- package/dist/advisor/guards.js +198 -0
- package/dist/advisor/guards.js.map +1 -0
- package/dist/advisor/indicatorCompute.d.ts +45 -0
- package/dist/advisor/indicatorCompute.d.ts.map +1 -0
- package/dist/advisor/indicatorCompute.js +259 -0
- package/dist/advisor/indicatorCompute.js.map +1 -0
- package/dist/advisor/positionPlan.d.ts +33 -0
- package/dist/advisor/positionPlan.d.ts.map +1 -0
- package/dist/advisor/positionPlan.js +118 -0
- package/dist/advisor/positionPlan.js.map +1 -0
- package/dist/advisor/promptTemplate.d.ts +11 -0
- package/dist/advisor/promptTemplate.d.ts.map +1 -0
- package/dist/advisor/promptTemplate.js +230 -0
- package/dist/advisor/promptTemplate.js.map +1 -0
- package/dist/advisor/sessionLog.d.ts +41 -0
- package/dist/advisor/sessionLog.d.ts.map +1 -0
- package/dist/advisor/sessionLog.js +7 -0
- package/dist/advisor/sessionLog.js.map +1 -0
- package/dist/advisor/touchProbability.d.ts +54 -0
- package/dist/advisor/touchProbability.d.ts.map +1 -0
- package/dist/advisor/touchProbability.js +215 -0
- package/dist/advisor/touchProbability.js.map +1 -0
- package/dist/advisor/tpslPolicy.d.ts +22 -0
- package/dist/advisor/tpslPolicy.d.ts.map +1 -0
- package/dist/advisor/tpslPolicy.js +120 -0
- package/dist/advisor/tpslPolicy.js.map +1 -0
- package/dist/cli/advisorCli.d.ts +3 -0
- package/dist/cli/advisorCli.d.ts.map +1 -0
- package/dist/cli/advisorCli.js +706 -0
- package/dist/cli/advisorCli.js.map +1 -0
- package/dist/cli/index.js +6 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/riskCli.d.ts +3 -0
- package/dist/cli/riskCli.d.ts.map +1 -0
- package/dist/cli/riskCli.js +120 -0
- package/dist/cli/riskCli.js.map +1 -0
- package/dist/cli/strategyCli.d.ts.map +1 -1
- package/dist/cli/strategyCli.js +4 -2
- package/dist/cli/strategyCli.js.map +1 -1
- package/dist/cli/tradingCli.d.ts.map +1 -1
- package/dist/cli/tradingCli.js +34 -2
- package/dist/cli/tradingCli.js.map +1 -1
- package/dist/core/cliBin.d.ts +8 -0
- package/dist/core/cliBin.d.ts.map +1 -0
- package/dist/core/cliBin.js +15 -0
- package/dist/core/cliBin.js.map +1 -0
- package/dist/core/errorFormat.d.ts +7 -0
- package/dist/core/errorFormat.d.ts.map +1 -0
- package/dist/core/errorFormat.js +59 -0
- package/dist/core/errorFormat.js.map +1 -0
- package/dist/core/errors.d.ts +2 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +3 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/hyperliquid/asset.d.ts +2 -0
- package/dist/core/hyperliquid/asset.d.ts.map +1 -1
- package/dist/core/hyperliquid/asset.js +25 -0
- package/dist/core/hyperliquid/asset.js.map +1 -1
- package/dist/core/hyperliquid/client.d.ts +3 -0
- package/dist/core/hyperliquid/client.d.ts.map +1 -1
- package/dist/core/hyperliquid/client.js +31 -21
- package/dist/core/hyperliquid/client.js.map +1 -1
- package/dist/core/hyperliquid/exchange.d.ts +3 -0
- package/dist/core/hyperliquid/exchange.d.ts.map +1 -1
- package/dist/core/hyperliquid/exchange.js +31 -21
- package/dist/core/hyperliquid/exchange.js.map +1 -1
- package/dist/core/hyperliquid/exchangeParse.d.ts +3 -0
- package/dist/core/hyperliquid/exchangeParse.d.ts.map +1 -1
- package/dist/core/hyperliquid/exchangeParse.js +62 -0
- package/dist/core/hyperliquid/exchangeParse.js.map +1 -1
- package/dist/core/hyperliquid/httpRequest.d.ts +36 -0
- package/dist/core/hyperliquid/httpRequest.d.ts.map +1 -0
- package/dist/core/hyperliquid/httpRequest.js +171 -0
- package/dist/core/hyperliquid/httpRequest.js.map +1 -0
- package/dist/core/hyperliquid/orders.d.ts +5 -0
- package/dist/core/hyperliquid/orders.d.ts.map +1 -1
- package/dist/core/hyperliquid/orders.js +15 -5
- package/dist/core/hyperliquid/orders.js.map +1 -1
- package/dist/core/hyperliquid/rounding.d.ts +23 -0
- package/dist/core/hyperliquid/rounding.d.ts.map +1 -0
- package/dist/core/hyperliquid/rounding.js +53 -0
- package/dist/core/hyperliquid/rounding.js.map +1 -0
- package/dist/core/risk/isolatedTopUp.d.ts +112 -0
- package/dist/core/risk/isolatedTopUp.d.ts.map +1 -0
- package/dist/core/risk/isolatedTopUp.js +209 -0
- package/dist/core/risk/isolatedTopUp.js.map +1 -0
- package/dist/core/risk/isolatedTopUpHistory.d.ts +7 -0
- package/dist/core/risk/isolatedTopUpHistory.d.ts.map +1 -0
- package/dist/core/risk/isolatedTopUpHistory.js +26 -0
- package/dist/core/risk/isolatedTopUpHistory.js.map +1 -0
- package/dist/core/risk/isolatedTopUpParse.d.ts +16 -0
- package/dist/core/risk/isolatedTopUpParse.d.ts.map +1 -0
- package/dist/core/risk/isolatedTopUpParse.js +78 -0
- package/dist/core/risk/isolatedTopUpParse.js.map +1 -0
- package/dist/core/risk/runIsolatedTopUpReconcile.d.ts +28 -0
- package/dist/core/risk/runIsolatedTopUpReconcile.d.ts.map +1 -0
- package/dist/core/risk/runIsolatedTopUpReconcile.js +184 -0
- package/dist/core/risk/runIsolatedTopUpReconcile.js.map +1 -0
- package/dist/core/state/gcTradeState.js +1 -1
- package/dist/core/state/gcTradeState.js.map +1 -1
- package/dist/core/state/gridReconcile.d.ts +2 -0
- package/dist/core/state/gridReconcile.d.ts.map +1 -1
- package/dist/core/state/gridReconcile.js +42 -2
- package/dist/core/state/gridReconcile.js.map +1 -1
- package/dist/core/state/intentFactory.d.ts +1 -0
- package/dist/core/state/intentFactory.d.ts.map +1 -1
- package/dist/core/state/intentFactory.js +1 -0
- package/dist/core/state/intentFactory.js.map +1 -1
- package/dist/core/state/profileStore.d.ts +6 -0
- package/dist/core/state/profileStore.d.ts.map +1 -0
- package/dist/core/state/profileStore.js +26 -0
- package/dist/core/state/profileStore.js.map +1 -0
- package/dist/core/state/runReconcile.d.ts.map +1 -1
- package/dist/core/state/runReconcile.js +92 -30
- package/dist/core/state/runReconcile.js.map +1 -1
- package/dist/core/state/schema.d.ts +565 -124
- package/dist/core/state/schema.d.ts.map +1 -1
- package/dist/core/state/schema.js +62 -0
- package/dist/core/state/schema.js.map +1 -1
- package/dist/core/state/snapshot.d.ts +13 -0
- package/dist/core/state/snapshot.d.ts.map +1 -1
- package/dist/core/state/snapshot.js +36 -0
- package/dist/core/state/snapshot.js.map +1 -1
- package/dist/core/state/statePaths.d.ts +1 -0
- package/dist/core/state/statePaths.d.ts.map +1 -1
- package/dist/core/state/statePaths.js +4 -0
- package/dist/core/state/statePaths.js.map +1 -1
- package/dist/core/state/store.d.ts +21 -3
- package/dist/core/state/store.d.ts.map +1 -1
- package/dist/core/state/store.js +123 -14
- package/dist/core/state/store.js.map +1 -1
- package/dist/core/state/types.d.ts +13 -0
- package/dist/core/state/types.d.ts.map +1 -1
- package/dist/daemon/index.js +50 -5
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/validateChild.d.ts +13 -0
- package/dist/daemon/validateChild.d.ts.map +1 -0
- package/dist/daemon/validateChild.js +77 -0
- package/dist/daemon/validateChild.js.map +1 -0
- package/dist/strategies/grid.d.ts +1 -0
- package/dist/strategies/grid.d.ts.map +1 -1
- package/dist/strategies/grid.js +1 -0
- package/dist/strategies/grid.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
面向 Hyperliquid 永续合约的命令行工具:
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- **只读 `/info` 查询**:配置、行情、盘口、K 线、持仓、挂单、成交等
|
|
6
|
+
- **签名 `/exchange`**:限价 / 触发单 / bracket 等下单与撤单,以及 HTTP 轮询 **`watch orders`**
|
|
7
|
+
- **网格策略(`strategy grid`)**:在价格区间内批量铺限价
|
|
8
|
+
- **本地 JSON 状态**(默认 **`~/.jcc_hyper_tool/trade-state.json`**;根或子命令 **`--state-file`** 可改路径;根 **`--no-state`** 可关闭挂单类命令的读写):**`state reconcile`** / **`state cancel-open`**,跟踪 bracket / grid 意图,并在入场视为成交后再推进 TP/SL
|
|
9
|
+
- **逐仓自动加保证金(`risk isolated-top-up`)**:在 **`state reconcile`** 每轮开头评估逐仓持仓强平距离,必要时 **`updateIsolatedMargin`**;配置写入 **`userProfile.isolatedTopUp`**(默认关闭)
|
|
10
|
+
- **LLM 顾问(`advise`)**:DeepSeek 推理接口 + K 线与持仓上下文 → 结构化动作(`wait` / `open_with_bracket` / `close_position` / `cancel_all`);默认 **dry-run**,真下单时经子命令既有 **`YES`** / **`--assume-yes`** 流程;用户偏好写入同文件 **`userProfile`**(**`advisor profile`**)
|
|
9
11
|
|
|
10
12
|
私钥**仅**通过**环境变量**提供,请勿写入仓库或配置文件;变量名、何时必填与安全注意见 **[环境变量](#环境变量)**。
|
|
11
13
|
|
|
@@ -19,20 +21,33 @@
|
|
|
19
21
|
|
|
20
22
|
## 守护进程(定时循环)
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
**网格**与 **LLM 自动交易(advise)** 应各跑一个 **`jcc_hyper_daemon`**,**不要混在同一进程**(分开 state 文件,避免持仓/挂单互相撤改)。**若 advise 使用 `open_with_bracket`,还需另起一个 `state reconcile` daemon 指向同一份 advise state**(入场成交后挂 TP/SL;仅跑 advise 不会自动挂保护腿)。详见 **[Manual.md → 定时循环](./Manual.md#定时循环)**。
|
|
25
|
+
|
|
26
|
+
**`jcc_hyper_daemon`** 按固定间隔 **`spawn`** 一次 **`jcc_hyper_tool`**;子命令写在 **`--`** 之后。
|
|
23
27
|
|
|
24
28
|
```bash
|
|
25
|
-
|
|
29
|
+
# 网格:对账 / 补单 / 逐仓加保证金(可 30–120s)
|
|
30
|
+
jcc_hyper_daemon --mode grid --interval 60 --state-file ~/.jcc_hyper_tool/grid-state.json -- \
|
|
31
|
+
state reconcile --live --assume-yes
|
|
32
|
+
|
|
33
|
+
# 自动交易:advise 单轮 + 自动执行(间隔 ≥ 300s,建议 900s+)
|
|
34
|
+
jcc_hyper_daemon --mode advise --interval 900 --state-file ~/.jcc_hyper_tool/advise-state.json -- \
|
|
35
|
+
advise --coin xyz:CL --max-sz 2 --once --auto --live --assume-yes
|
|
36
|
+
|
|
26
37
|
jcc_hyper_daemon --once -- config print
|
|
27
38
|
```
|
|
28
39
|
|
|
29
40
|
选项摘要:
|
|
30
41
|
|
|
31
|
-
- **`-i, --interval <seconds>`**:周期间隔,默认 `60
|
|
32
|
-
- **`--
|
|
33
|
-
- **`--
|
|
42
|
+
- **`-i, --interval <seconds>`**:周期间隔,默认 `60`;**`advise` 子命令至少 300 秒**。
|
|
43
|
+
- **`--mode grid|advise`**:约束子命令类型,防止 grid 与 advise 混用。
|
|
44
|
+
- **`--once`(daemon 层)**:守护进程**只跑一轮**子命令后退出;**长期 advise 循环不要加此项**。
|
|
45
|
+
- **`advise --once`(子命令层)**:每次 spawn 的 advise **只问模型一次**后退出;与 daemon 循环配合使用(见 **[Manual.md → 自动交易守护进程](./Manual.md#自动交易守护进程-mode-advise)**)。
|
|
46
|
+
- **`--jcc-bin <path>`**:显式指定 `jcc_hyper_tool` 可执行文件。
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
**`userProfile` / `advisor profile`**:偏好写在 **`trade-state.json` 同一文件**的 `userProfile` 字段里,**不是**单独配置文件;网格与 advise 可各用不同 state 路径,但 profile 须写入**该 daemon 使用的 `--state-file`**。审计日志在 **`advisor-log/`**,与 profile 无关。
|
|
49
|
+
|
|
50
|
+
收到 **`SIGINT` / `SIGTERM`** 时守护进程会立即退出。
|
|
36
51
|
|
|
37
52
|
## 从源码参与开发
|
|
38
53
|
|
|
@@ -67,6 +82,8 @@ npm run lint
|
|
|
67
82
|
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
68
83
|
| `JCC_HYPER_NETWORK` | 全局 **`--network`** 的默认值:`mainnet` 或 `testnet`。不传 CLI 且未设置时 **默认为 `mainnet`**。与 **[测试网](#测试网)** 行为一致。 |
|
|
69
84
|
| `JCC_HYPER_API_URL` 或 `HYPERLIQUID_API_URL` | 可选:覆盖 **`/info` / `/exchange` 所用 HTTP 源**(仅 **`https://` 或 `http://` 的 origin**,误写 `.../info` 会被规范成 origin)。同全局 **`--api-url`**。 |
|
|
85
|
+
| `DEEPSEEK_API_KEY` | **`advise`** 必填:DeepSeek OpenAI 兼容 **`/v1/chat/completions`**。勿提交到仓库。 |
|
|
86
|
+
| `DEEPSEEK_MODEL` | 可选:覆盖默认模型 ID(默认 **`deepseek-v4-pro`**;若 DeepSeek 调整命名可改此项)。 |
|
|
70
87
|
|
|
71
88
|
### 钱包私钥(签名 / `--live`)
|
|
72
89
|
|
|
@@ -90,6 +107,7 @@ npm run lint
|
|
|
90
107
|
| `HYPERLIQUID_ADDRESS` / `JCC_HYPER_WALLET_ADDRESS` | 可选账户地址;只读查询或与私钥交叉校验 |
|
|
91
108
|
| `JCC_HYPER_NETWORK` | 默认 `mainnet` \| `testnet` |
|
|
92
109
|
| `JCC_HYPER_API_URL` / `HYPERLIQUID_API_URL` | 可选 API origin,同 **`--api-url`** |
|
|
110
|
+
| `DEEPSEEK_API_KEY` / `DEEPSEEK_MODEL` | **`advise`**:API 密钥;可选模型覆盖 |
|
|
93
111
|
|
|
94
112
|
### 示例(勿照抄私钥值)
|
|
95
113
|
|
|
@@ -115,7 +133,7 @@ Hyperliquid 提供 **[测试网 / 预览环境](https://hyperliquid.gitbook.io/h
|
|
|
115
133
|
|
|
116
134
|
全局选项:`--network mainnet|testnet`、`--api-url <origin>`、`-v` / `--verbose`、**`--state-file <path>`**(覆盖默认 **`~/.jcc_hyper_tool/trade-state.json`**)、**`--no-state`**(本次调用中 **`order place` / `order tpsl` / `strategy grid`** 不写、不读 trade state;与 **`state …`** 子命令同用会报错)。
|
|
117
135
|
|
|
118
|
-
###
|
|
136
|
+
### 只读查询
|
|
119
137
|
|
|
120
138
|
- `config print`、`wallet address`
|
|
121
139
|
- `perp meta`、`perp mid <coin>`、`perp book <coin>`、**`perp kline <coin>`**(K 线 / OHLCV,见下)
|
|
@@ -168,17 +186,17 @@ jcc_hyper_tool perp kline xyz:CL --interval 1h
|
|
|
168
186
|
|
|
169
187
|
HIP-3 合约名称形如 `deployer:ASSET`(例如 `xyz:CL`)。调用 `/info` 的 `allMids` 时需要正确的 **`dex`**(部署方);本 CLI 在 `perp mid` 中会从 `coin` 里 `:` 前缀推断(也可用 **`--dex`** 覆盖)。**REST 里的 `coin` 字符串可能与网页 URL 路径不一致** — 若接口返回 `null` 或异常,请用 `perp meta --dex xyz` 核对 `universe[].name`(例如 WTI 类原油在 API 快照里常为 `xyz:CL`,而非路径里的 `xyz:WTIOIL`)。
|
|
170
188
|
|
|
171
|
-
###
|
|
189
|
+
### 交易
|
|
172
190
|
|
|
173
191
|
官方 HTTP 接口说明见 [Exchange endpoint](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)。签名遵循 Python SDK 的 `action_hash` + phantom **EIP-712** `Agent`(链 ID `1337`,域名为 `Exchange`)。
|
|
174
192
|
|
|
175
193
|
- **`jcc_hyper_tool order place`** — 构造**限价单** wire;默认输出 **dry-run** JSON(无需私钥、不访问交易所)。
|
|
176
194
|
- **`--live`** — 签名并 `POST /exchange`(需要私钥)。提交前须在终端输入 **`YES`**,除非使用 **`--assume-yes`**。
|
|
177
|
-
- **`--state-file <path>`**(可选)— 覆盖根默认路径;在未使用根 **`--no-state`** 时,会在本地写入 / 更新 **`single_limit`** 意图(详见 **
|
|
195
|
+
- **`--state-file <path>`**(可选)— 覆盖根默认路径;在未使用根 **`--no-state`** 时,会在本地写入 / 更新 **`single_limit`** 意图(详见 **[本地状态与对账](#本地状态与对账)**)。
|
|
178
196
|
- 示例:
|
|
179
197
|
`jcc_hyper_tool order place --coin ETH --side buy --limit-px 2000 --sz 0.01 --tif Gtc`
|
|
180
198
|
|
|
181
|
-
- **`jcc_hyper_tool order tpsl`** — **触发类**止盈 / 止损(`--tpsl tp|sl`,wire 为 `t.trigger`)。必填:`--coin`、`--side`、`--sz`、`--trigger-px`、`--tpsl`。二选一:**`--is-market`**(触发后按市价成交)或 **`--limit-px`**(触发后限价),不可同时使用。默认 **仅减仓(reduce-only)**;**`--no-reduce-only`** 允许加仓(与 **`--grouping positionTpsl`** 互斥)。可选 **`--grouping na|normalTpsl|positionTpsl`**(默认 **`na`**);**`positionTpsl`** 下 **`--sz 0`** 表示按仓位全量 TP/SL。另有:`--cloid`、**`--dex`**(HIP-3;省略时从 `--coin` 的 `deployer:` 前缀推断,与 `order place` 一致)、**`--live`**、**`--assume-yes`**、**`--state-file`**(写入 **`standalone_tpsl`**,见
|
|
199
|
+
- **`jcc_hyper_tool order tpsl`** — **触发类**止盈 / 止损(`--tpsl tp|sl`,wire 为 `t.trigger`)。必填:`--coin`、`--side`、`--sz`、`--trigger-px`、`--tpsl`。二选一:**`--is-market`**(触发后按市价成交)或 **`--limit-px`**(触发后限价),不可同时使用。默认 **仅减仓(reduce-only)**;**`--no-reduce-only`** 允许加仓(与 **`--grouping positionTpsl`** 互斥)。可选 **`--grouping na|normalTpsl|positionTpsl`**(默认 **`na`**);**`positionTpsl`** 下 **`--sz 0`** 表示按仓位全量 TP/SL。另有:`--cloid`、**`--dex`**(HIP-3;省略时从 `--coin` 的 `deployer:` 前缀推断,与 `order place` 一致)、**`--live`**、**`--assume-yes`**、**`--state-file`**(写入 **`standalone_tpsl`**,见 **[本地状态与对账](#本地状态与对账)**)。默认 dry-run;**`--live`** 行为类似 `order place`(除非 **`--assume-yes`** 否则需输入 **`YES`**)。**风险**:务必先 dry-run;**`--live`** 请仅在测试网 + 一次性密钥上初次验证。
|
|
182
200
|
- 测试网 dry-run(触发后市价):
|
|
183
201
|
`jcc_hyper_tool --network testnet order tpsl --coin BTC --side sell --sz 0.001 --trigger-px 95000 --tpsl sl --is-market`
|
|
184
202
|
- 测试网 dry-run(整仓 TP/SL,`sz=0`,`positionTpsl`):
|
|
@@ -190,7 +208,7 @@ HIP-3 合约名称形如 `deployer:ASSET`(例如 `xyz:CL`)。调用 `/info`
|
|
|
190
208
|
|
|
191
209
|
- **`jcc_hyper_tool watch orders`** — 轮询合并后的 `openOrders`(默认 perp + 各 builder dex),在 oid 集合或 payload 变化时打印 JSON 行。选项:`--poll-ms`、`--coin`、`--full`。
|
|
192
210
|
|
|
193
|
-
###
|
|
211
|
+
### 策略
|
|
194
212
|
|
|
195
213
|
**`jcc_hyper_tool strategy grid`** — 在 **`--lower`** 与 **`--upper`** 之间按 **`--grids`** 档均匀铺限价,每档 **`--order-sz`**。默认输出 **dry-run** JSON(含解析后的 `prices` 与 `action`)。**`--live`** 时签名并 POST `/exchange`,与 `order place` 类似(需私钥;除非 **`--assume-yes`** 否则输入 **`YES`**)。
|
|
196
214
|
|
|
@@ -206,11 +224,61 @@ Dry-run 示例:
|
|
|
206
224
|
|
|
207
225
|
- **`--state-file <path>`**(可选)— 覆盖根默认;未使用 **`--no-state`** 时写入网格意图;配合 **`--live`** 时尝试从响应解析 **oid** 写回各 **leg**,便于 **`state reconcile`**。
|
|
208
226
|
|
|
227
|
+
### LLM 顾问(`advise`)
|
|
228
|
+
|
|
229
|
+
使用 **DeepSeek** OpenAI 兼容接口(环境变量 **`DEEPSEEK_API_KEY`**,可选 **`DEEPSEEK_MODEL`**,默认模型 **`deepseek-v4-pro`**)。拉取当前 **`coin`** 的 **5m / 1h / 1d** K 线与 **clearinghouse 持仓**,拼成结构化上下文;模型只允许输出 **JSON** 动作(经 Zod 校验,失败会自动重试最多 2 次)。**`--max-sz`** 为强制硬顶;价格相对 **mid** 偏离超过 profile / 默认 **3%** 的限价会被拒绝;**`open_with_bracket` / `order bracket` 还须满足 Hyperliquid 最低名义价值 **$10**(`limit_px × sz`,上下文含 **`min_order_sz`** 参考)。
|
|
230
|
+
|
|
231
|
+
**动作枚举**:`wait` | `open_with_bracket` | `close_position` | `cancel_all`。执行时通过 **`spawnSync`** 调本包 **`jcc_hyper_tool`** 子命令,**继承**现有 **`--live` / `--assume-yes` / `YES`** 与 dry-run 语义。**`open_with_bracket`**、**`cancel_all`** 需要可写 **`trade-state.json`**(勿与根 **`--no-state`** 同用)。**`close_position`** 的 **market** 在实现上为 **IOC** + 相对 mid 的激进限价(近似市价减仓);持仓大于 **`--max-sz`** 时**按 cap 部分平仓**,不再整单拒绝。
|
|
232
|
+
|
|
233
|
+
**一轮 advise** = **一次模型调用 → 一个动作**;模型返回 **`wait`** 则不下单。**`--auto`** 会在通过护栏后自动执行该动作(仍可用不加 **`--live`** 做 dry-run)。
|
|
234
|
+
|
|
235
|
+
**反同质化护栏**(CLI 或 **`userProfile`**,详见 Manual):
|
|
236
|
+
|
|
237
|
+
- **`--min-confidence`** / **`minConfidenceToExecute`**:低于阈值不执行;**`--auto`** 且未配置时默认 **0.55**。
|
|
238
|
+
- **`--limit-jitter-pct`** / **`limitPriceJitterPct`**:限价随机微偏移(仍须在 mid 偏离带宽内)。
|
|
239
|
+
- **`--sl-entry-shift <0-1>`** / **`bracketSlEntryShift`**:bracket 入场向模型止损平移(**1** = 以原 SL 价挂限价单,TP/SL 等量平移;未成交无仓)。
|
|
240
|
+
- **`--execute-cooldown-sec`** / **`executeCooldownSec`**:同 coin + 同动作类型冷却;**`open_with_bracket` 另按 `side`(buy/sell)区分**;记录写在 state 的 **`adviseExecuteHistory`**(**`--live` 成功**后更新,键如 **`${coin}:open_with_bracket:sell`**)。
|
|
241
|
+
- **`defaultMinSz` / `minSzByCoin`**(`advisor profile set --min-sz` / `--coin-min COIN=size`):开仓数量下限,与 HL $10 名义价值检查叠加(例如 `xyz:CL` 设 `--coin-min xyz:CL=1` 可禁止 0.15 等小 fractional 仓)。
|
|
242
|
+
|
|
243
|
+
会话留痕目录(默认 **`~/.jcc_hyper_tool/advisor-log/<uuid>.json`**)包含 **`reasoning_content`**(仅落盘;按 DeepSeek 要求**不会**回传到下一轮的 `messages`)。**这不是 profile 文件**——偏好仍在 **`trade-state.json` → `userProfile`**。
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
export DEEPSEEK_API_KEY='sk-…'
|
|
247
|
+
# 交互 REPL(默认):模型回合后输入自然语言 / show / execute / quit
|
|
248
|
+
jcc_hyper_tool advise --coin BTC --max-sz 0.002
|
|
249
|
+
|
|
250
|
+
# 单轮
|
|
251
|
+
jcc_hyper_tool advise --coin BTC --max-sz 0.002 --note "manual note" --once
|
|
252
|
+
|
|
253
|
+
# 单轮后立刻走执行分支(仍可 dry-run,不加 --live 则子命令亦 dry-run)
|
|
254
|
+
jcc_hyper_tool advise --coin BTC --max-sz 0.002 --once --auto
|
|
255
|
+
|
|
256
|
+
# v2 提示词:预计算指标模式(节省 token,指标值精确)
|
|
257
|
+
jcc_hyper_tool advise --coin BTC --max-sz 0.002 --context-version precomputed_indicators --once
|
|
258
|
+
|
|
259
|
+
# 用户风险偏好写入 trade-state 的 userProfile(与 intents 同文件;reconcile / cancel-open 不改此块)
|
|
260
|
+
jcc_hyper_tool advisor profile set --state-file ~/.jcc_hyper_tool/advise-state.json \
|
|
261
|
+
--min-confidence 0.6 --limit-jitter-pct 0.002 --sl-entry-shift 1 --execute-cooldown-sec 1800
|
|
262
|
+
jcc_hyper_tool advisor profile show --state-file ~/.jcc_hyper_tool/advise-state.json
|
|
263
|
+
jcc_hyper_tool advisor profile clear --state-file ~/.jcc_hyper_tool/advise-state.json
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
K 线条数默认 **48 / 48 / 30**,可用 **`--bars5m` / `--bars1h` / `--bars1d`** 覆盖。
|
|
267
|
+
|
|
268
|
+
**Prompt 上下文版本**(`--context-version`):控制发送给模型的 K 线和技术指标格式。
|
|
269
|
+
|
|
270
|
+
| 版本 | 说明 |
|
|
271
|
+
|------|------|
|
|
272
|
+
| **`raw_kline`**(默认,v1) | 原始 K 线 OHLCV 全量数据;模型自行分析 EMA/MACD/RSI/布林带等指标。**兼容旧版行为。** |
|
|
273
|
+
| **`precomputed_indicators`**(v2) | 服务端使用 `trading-signals` 库预计算技术指标(EMA 排列、MACD、RSI、布林带、ATR、量价),输出结构化中文摘要替代大部分 K 线数据;仅保留精简 5m/1h/1d K 线(与 v1 相同根数,仅 h/l/o/c/v 五字段)供波浪/缠论多周期联立、K 线形态和量价配合分析。**大幅节省 token(约 75%)且指标值精确。** |
|
|
274
|
+
|
|
275
|
+
v2 模式下,模型 §1 分析框架会从「从裸 K 线计算指标」变为「解读预计算指标摘要并做综合判断」。相比 v1 额外提供的对数收益率衍生指标(ATR%、历史波动率、价格 Z-Score)让模型可以从跨价格量级可比的角度判断波动率环境和价格极端程度。
|
|
276
|
+
|
|
209
277
|
---
|
|
210
278
|
|
|
211
279
|
## 实战:单边 / 双边网格、定时补单、一键撤销
|
|
212
280
|
|
|
213
|
-
|
|
281
|
+
(默认 state 路径与 **`state cancel-open`** 等行为与下文 **[本地状态与对账](#本地状态与对账)** 一致。)
|
|
214
282
|
|
|
215
283
|
本 CLI **不会替你自动「成交后在对侧按价差补单」**;典型做法是:**用脚本读行情或读 `state` + 你自己的步长公式**,算出新的区间后再调一次 **`strategy grid --live`**。下面用 **`ST`** 表示你的 `coin`;**`/path/to/state.json`** 在示例里显式写出,若你使用默认 state 文件,可省略所有 **`--state-file`**(见上文全局选项)。
|
|
216
284
|
|
|
@@ -305,9 +373,9 @@ jcc_hyper_tool state cancel-open --state-file ./trade-state.json --intent <意
|
|
|
305
373
|
|
|
306
374
|
---
|
|
307
375
|
|
|
308
|
-
##
|
|
376
|
+
## 本地状态与对账
|
|
309
377
|
|
|
310
|
-
**默认**使用 **`~/.jcc_hyper_tool/trade-state.json`**;根 **`--state-file`** 或各子命令 **`--state-file`** 可覆盖。**`--no-state`** 时 **`order place` / `order tpsl` / `strategy grid`** 不写 state;**`order bracket`** 与 **`state`** 子命令不可用 **`--no-state
|
|
378
|
+
**默认**使用 **`~/.jcc_hyper_tool/trade-state.json`**;根 **`--state-file`** 或各子命令 **`--state-file`** 可覆盖。**`--no-state`** 时 **`order place` / `order tpsl` / `strategy grid`** 不写 state;**`order bracket`** 与 **`state`** 子命令不可用 **`--no-state`**。工具在本地 JSON 中保存各**意图**及其推进情况,面向**任务可读**的追踪,而不是 HL 原始 payload 的完整镜像。
|
|
311
379
|
|
|
312
380
|
### 状态文件结构
|
|
313
381
|
|
|
@@ -317,8 +385,10 @@ jcc_hyper_tool state cancel-open --state-file ./trade-state.json --intent <意
|
|
|
317
385
|
- **`grid`**:网格参数 + 每一档 **leg**(含 oid、阶段等)。
|
|
318
386
|
- **`single_limit`**:单笔限价(配合 `order place --state-file`)。
|
|
319
387
|
- **`standalone_tpsl`**:独立触发单(配合 `order tpsl --state-file`)。
|
|
320
|
-
- **`events
|
|
321
|
-
-
|
|
388
|
+
- **`events`**:与该意图相关的事件日志(逐仓加保证金事件使用虚拟 intentId **`_risk`**)。
|
|
389
|
+
- **`userProfile`**(可选):顾问偏好 + **`isolatedTopUp`** 风控参数;**reconcile / cancel-open 不删此块**。
|
|
390
|
+
- **`adviseExecuteHistory`**(可选):advise **`--live` 成功执行**后的冷却记录(键为 **`${coin}:${action}`**;**`open_with_bracket` 为 `${coin}:open_with_bracket:${side}`**)。
|
|
391
|
+
- **写入**:先写同目录临时文件再 **`rename`**,尽量原子化;**跨进程**(例如 advise + reconcile 两个 daemon 共用 `--state-file`)通过 **`${stateFile}.lock`** 互斥,默认最多等待 **30s**、每 **50ms** 重试;reconcile 写回时会保留 advise 刚更新的 **`adviseExecuteHistory`** / **`userProfile`**。重复对账依赖 **`dedupeKeys`**(`plan:*` / `done:*`),避免在同一模式下重复生成同一类「拟执行动作」。
|
|
322
392
|
|
|
323
393
|
未使用根 **`--no-state`** 时,**`order place` / `order tpsl` / `strategy grid`** 会默认写入默认 state 文件(或根 / 子命令 **`--state-file`** 指定路径)。**`--no-state`** 则完全不写、不读。
|
|
324
394
|
|
|
@@ -326,7 +396,7 @@ jcc_hyper_tool state cancel-open --state-file ./trade-state.json --intent <意
|
|
|
326
396
|
|
|
327
397
|
| 子命令 | 作用 |
|
|
328
398
|
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
329
|
-
| **`state reconcile`** | 读状态 → 拉 **合并后的 openOrders**(默认 perp + 各 builder dex)与 **clearinghouseState(仓位)** → 推进 bracket/grid 状态机 → **默认只输出 dry-run 计划**;加 **`--live`** 则在确认后真实下单 /
|
|
399
|
+
| **`state reconcile`** | 读状态 → 拉 **合并后的 openOrders**(默认 perp + 各 builder dex)与 **clearinghouseState(仓位)** → **(可选)逐仓自动加保证金** → 推进 bracket/grid 状态机 → **默认只输出 dry-run 计划**;加 **`--live`** 则在确认后真实下单 / 撤单 / 加保证金(需私钥;可用 **`--assume-yes`** 跳过交互)。**`--intent <id>`** 可只处理一条意图(逐仓评估也仅针对该 intent 的 coin)。写回前会 **GC** 终态意图。 |
|
|
330
400
|
| **`state cancel-open`** | 从 state 收集 oid,与 **合并后的 openOrders**(默认 perp + 各 builder dex)求交后按 **coin / assetIndex** 批量撤单;默认 **dry** 只出计划;**`--live`** 真实撤单(**`--assume-yes`** 可非交互)。结束后 **GC** 本地 state。 |
|
|
331
401
|
| **`state list`** | 以任务可读方式列出全部意图摘要(阶段、下一步提示等)。 |
|
|
332
402
|
| **`state show <intentId>`** | 单条意图的结构化详情 + 最近相关事件。 |
|
|
@@ -376,6 +446,74 @@ jcc_hyper_tool state reconcile --state-file ./trade-state.json --live --assume-y
|
|
|
376
446
|
|
|
377
447
|
---
|
|
378
448
|
|
|
449
|
+
## 逐仓自动加保证金(`risk isolated-top-up`)
|
|
450
|
+
|
|
451
|
+
当网格或 bracket 产生**逐仓持仓**且 mark 与强平价距离偏紧时,可在 **`state reconcile`** 每轮**开头**(grid/bracket 动作之前)自动调用 Hyperliquid **`updateIsolatedMargin`** 追加 USDC 保证金。
|
|
452
|
+
|
|
453
|
+
**适用范围(代码硬约束)**
|
|
454
|
+
|
|
455
|
+
| 场景 | 行为 |
|
|
456
|
+
|------|------|
|
|
457
|
+
| 全仓(`leverage.type === "cross"`) | 跳过 |
|
|
458
|
+
| 无持仓(`\|szi\| === 0`) | 跳过 |
|
|
459
|
+
| 逐仓 + 有持仓 | 评估是否加仓 |
|
|
460
|
+
|
|
461
|
+
**加多少(目标驱动)**
|
|
462
|
+
|
|
463
|
+
1. 计算当前安全距离:`distancePct = |mark − liq| / mark × 100`
|
|
464
|
+
2. 若 `distancePct >= safeDistancePct`(默认 **8%**)→ 不加
|
|
465
|
+
3. 否则算拉到安全距离所需 USDC:`neededUsd ≈ gapPx × |szi| × safetyFactor`(默认 **`safetyFactor = 1.10`**)
|
|
466
|
+
4. 可加仓池:`withdrawable − reserveUsd`(默认 **`reserveUsd = 100`**,留给网格挂单)
|
|
467
|
+
5. 钱够 → 加 `neededUsd`;不够 → 加 `availableToAdd`(partial);若 partial 后不足 **`minPartialUsd`(默认 20)** → 只记日志、不加
|
|
468
|
+
|
|
469
|
+
**配置**(写入 **`trade-state.json` → `userProfile.isolatedTopUp`**,默认 **`enabled: false`**):
|
|
470
|
+
|
|
471
|
+
```json
|
|
472
|
+
{
|
|
473
|
+
"userProfile": {
|
|
474
|
+
"isolatedTopUp": {
|
|
475
|
+
"enabled": true,
|
|
476
|
+
"safeDistancePct": 8,
|
|
477
|
+
"safetyFactor": 1.1,
|
|
478
|
+
"reserveUsd": 100,
|
|
479
|
+
"minTopUpUsd": 5,
|
|
480
|
+
"minPartialUsd": 20,
|
|
481
|
+
"maxSingleTopUpUsd": 5000,
|
|
482
|
+
"maxDailyTopUpUsd": 20000,
|
|
483
|
+
"cooldownSec": 300
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**CLI**
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
# 启用并设置保留金(写入 state 文件 userProfile)
|
|
493
|
+
jcc_hyper_tool risk isolated-top-up configure --enable --reserve-usd 100 --state-file ./trade-state.json
|
|
494
|
+
|
|
495
|
+
# 仅预览本轮评估(不 POST /exchange)
|
|
496
|
+
jcc_hyper_tool risk isolated-top-up plan --state-file ./trade-state.json
|
|
497
|
+
|
|
498
|
+
# 与 grid 对账一起跑(dry 会在 dryPlan 里列出 isolated_top_up / isolated_top_up_skip)
|
|
499
|
+
jcc_hyper_tool state reconcile --state-file ./trade-state.json
|
|
500
|
+
|
|
501
|
+
# 真实加保证金(与 grid live 共用一次 YES / --assume-yes)
|
|
502
|
+
jcc_hyper_tool state reconcile --state-file ./trade-state.json --live --assume-yes
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**daemon 示例**(仅 **grid** daemon;与 advise 分开进程,见 **[守护进程](#守护进程定时循环)**):
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
jcc_hyper_daemon --mode grid --interval 60 -- state reconcile --state-file ~/.jcc_hyper_tool/grid-state.json --live --assume-yes
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**输出**:`state reconcile` JSON 的 **`dryPlan` / `actionsExecuted`** 含 **`isolated_top_up`** 或 **`isolated_top_up_skip`**;事件类型 **`isolated_margin_top_up_executed`** / **`_skipped`** / **`_failed`** 写入 **`events`**。
|
|
512
|
+
|
|
513
|
+
**注意**:`withdrawable` 为**账户级**;同地址多 coin 多 daemon 会共享可加仓池。加保证金成功后**不会**立刻 refetch 全量仓位;下轮 reconcile 用新 `liquidationPx` 验证效果。
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
379
517
|
## 校验与测试
|
|
380
518
|
|
|
381
519
|
仓库内跑静态检查与单元测试:
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AdvisorAction } from "./actionSchema.js";
|
|
2
|
+
export type GlobalCliPrefixedArgs = {
|
|
3
|
+
network?: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
stateFile?: string;
|
|
6
|
+
noState?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function buildGlobalPrefix(opts: GlobalCliPrefixedArgs): string[];
|
|
9
|
+
/** Aggressive IOC-style limit (best-effort) to unwind quickly. */
|
|
10
|
+
export declare function aggressiveCloseLimitPx(side: "buy" | "sell", mid: number): number;
|
|
11
|
+
export declare function assertAdviseActionNeedsState(action: AdvisorAction, noState: boolean, stateFile: string | undefined): void;
|
|
12
|
+
export declare function advisorActionToCliArgs(action: AdvisorAction, params: {
|
|
13
|
+
coin: string;
|
|
14
|
+
mid: number | null;
|
|
15
|
+
positionSignedSz: number | undefined;
|
|
16
|
+
globals: string[];
|
|
17
|
+
live: boolean;
|
|
18
|
+
assumeYes: boolean;
|
|
19
|
+
/** Hard cap for close size (partial close when position exceeds cap). */
|
|
20
|
+
szCap?: number;
|
|
21
|
+
/** Optional jitter on aggressive market-close limit. */
|
|
22
|
+
limitJitterPct?: number;
|
|
23
|
+
maxDevPct?: number;
|
|
24
|
+
szDecimals?: number;
|
|
25
|
+
}): string[];
|
|
26
|
+
export declare function formatCliInvocation(args: string[]): string;
|
|
27
|
+
export type SpawnCapture = {
|
|
28
|
+
status: number | null;
|
|
29
|
+
stdout: string;
|
|
30
|
+
stderr: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function spawnJccHyperTool(args: string[], opts?: {
|
|
33
|
+
stdio?: "inherit" | "pipe";
|
|
34
|
+
}): SpawnCapture;
|
|
35
|
+
//# sourceMappingURL=actionRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionRunner.d.ts","sourceRoot":"","sources":["../../src/advisor/actionRunner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQvD,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAcvE;AAED,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,IAAI,CAaN;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE;IACN,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA,MAAM,EAAE,CAwIV;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAS1D;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GACpC,YAAY,CAmBd"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ConfigError } from "../core/errors.js";
|
|
2
|
+
import { inferHlDexFromPrefixedPerpCoin } from "../core/hyperliquid/prefixedPerpCoin.js";
|
|
3
|
+
import { resolveJccHyperToolSpawn } from "../core/cliBin.js";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { isAdvisorBracketOpenAction } from "./actionSchema.js";
|
|
6
|
+
import { applyLimitJitterWithinBand, roundAdvisorLimitPx, resolveCloseSz, } from "./executionPolicy.js";
|
|
7
|
+
export function buildGlobalPrefix(opts) {
|
|
8
|
+
const out = [];
|
|
9
|
+
if (opts.network) {
|
|
10
|
+
out.push("--network", opts.network);
|
|
11
|
+
}
|
|
12
|
+
if (opts.apiUrl) {
|
|
13
|
+
out.push("--api-url", opts.apiUrl);
|
|
14
|
+
}
|
|
15
|
+
if (opts.noState) {
|
|
16
|
+
out.push("--no-state");
|
|
17
|
+
}
|
|
18
|
+
else if (opts.stateFile) {
|
|
19
|
+
out.push("--state-file", opts.stateFile);
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/** Aggressive IOC-style limit (best-effort) to unwind quickly. */
|
|
24
|
+
export function aggressiveCloseLimitPx(side, mid) {
|
|
25
|
+
if (side === "sell") {
|
|
26
|
+
return mid * 0.92;
|
|
27
|
+
}
|
|
28
|
+
return mid * 1.08;
|
|
29
|
+
}
|
|
30
|
+
export function assertAdviseActionNeedsState(action, noState, stateFile) {
|
|
31
|
+
if (action.action !== "open_with_bracket" &&
|
|
32
|
+
action.action !== "place_limit_ambush" &&
|
|
33
|
+
action.action !== "cancel_all") {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (noState || !stateFile) {
|
|
37
|
+
throw new ConfigError(`advise: action "${action.action}" requires a writable trade state path (do not use --no-state; pass --state-file if needed).`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function advisorActionToCliArgs(action, params) {
|
|
41
|
+
const g = [...params.globals];
|
|
42
|
+
const dex = inferHlDexFromPrefixedPerpCoin(params.coin);
|
|
43
|
+
if (isAdvisorBracketOpenAction(action)) {
|
|
44
|
+
const args = [
|
|
45
|
+
...g,
|
|
46
|
+
"order",
|
|
47
|
+
"bracket",
|
|
48
|
+
"--coin",
|
|
49
|
+
params.coin,
|
|
50
|
+
"--side",
|
|
51
|
+
action.side,
|
|
52
|
+
"--limit-px",
|
|
53
|
+
String(action.limit_px),
|
|
54
|
+
"--sz",
|
|
55
|
+
String(action.sz),
|
|
56
|
+
"--tp",
|
|
57
|
+
String(action.tp_px),
|
|
58
|
+
"--sl",
|
|
59
|
+
String(action.sl_px),
|
|
60
|
+
];
|
|
61
|
+
if (dex) {
|
|
62
|
+
args.push("--dex", dex);
|
|
63
|
+
}
|
|
64
|
+
if (action.is_market) {
|
|
65
|
+
args.push("--is-market");
|
|
66
|
+
}
|
|
67
|
+
else if (action.protection_limit_px !== undefined) {
|
|
68
|
+
args.push("--protection-limit-px", String(action.protection_limit_px));
|
|
69
|
+
}
|
|
70
|
+
if (action.action === "place_limit_ambush") {
|
|
71
|
+
args.push("--expires-in-ms", String(Math.round(action.expires_in_min * 60_000)));
|
|
72
|
+
args.push("--strategy", "ambush");
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
args.push("--strategy", "scalp");
|
|
76
|
+
}
|
|
77
|
+
if (params.live) {
|
|
78
|
+
args.push("--live");
|
|
79
|
+
}
|
|
80
|
+
if (params.assumeYes) {
|
|
81
|
+
args.push("--assume-yes");
|
|
82
|
+
}
|
|
83
|
+
return args;
|
|
84
|
+
}
|
|
85
|
+
if (action.action === "close_position") {
|
|
86
|
+
const cap = params.szCap;
|
|
87
|
+
const { sz, capped, positionAbs } = cap !== undefined && Number.isFinite(cap) && cap > 0
|
|
88
|
+
? resolveCloseSz(params.positionSignedSz, cap)
|
|
89
|
+
: (() => {
|
|
90
|
+
const pos = params.positionSignedSz;
|
|
91
|
+
if (pos === undefined || !Number.isFinite(pos) || pos === 0) {
|
|
92
|
+
throw new ConfigError("close_position: no open position for this coin.");
|
|
93
|
+
}
|
|
94
|
+
const positionAbs = Math.abs(pos);
|
|
95
|
+
return { sz: positionAbs, capped: false, positionAbs };
|
|
96
|
+
})();
|
|
97
|
+
if (capped) {
|
|
98
|
+
process.stderr.write(`advise: close_position size capped to ${sz} (position ${positionAbs}, cap ${cap}).\n`);
|
|
99
|
+
}
|
|
100
|
+
const pos = params.positionSignedSz;
|
|
101
|
+
const closeSide = pos > 0 ? "sell" : "buy";
|
|
102
|
+
let limitPx;
|
|
103
|
+
if (action.method === "market") {
|
|
104
|
+
if (params.mid === null || params.mid <= 0) {
|
|
105
|
+
throw new ConfigError("close_position: market close needs mid price.");
|
|
106
|
+
}
|
|
107
|
+
limitPx = aggressiveCloseLimitPx(closeSide, params.mid);
|
|
108
|
+
limitPx = roundAdvisorLimitPx(limitPx, params.szDecimals);
|
|
109
|
+
const jitterPct = params.limitJitterPct ?? 0;
|
|
110
|
+
const maxDev = params.maxDevPct ?? 1;
|
|
111
|
+
if (jitterPct > 0) {
|
|
112
|
+
const jittered = applyLimitJitterWithinBand(limitPx, params.mid, jitterPct, maxDev, Math.random, params.szDecimals);
|
|
113
|
+
if (jittered.applied) {
|
|
114
|
+
process.stderr.write(`advise: market close limit jitter ${limitPx} → ${jittered.px}.\n`);
|
|
115
|
+
}
|
|
116
|
+
limitPx = jittered.px;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
if (action.limit_px === undefined || !Number.isFinite(action.limit_px)) {
|
|
121
|
+
throw new ConfigError("close_position: limit method needs limit_px.");
|
|
122
|
+
}
|
|
123
|
+
limitPx = roundAdvisorLimitPx(action.limit_px, params.szDecimals);
|
|
124
|
+
}
|
|
125
|
+
const args = [
|
|
126
|
+
...g,
|
|
127
|
+
"order",
|
|
128
|
+
"place",
|
|
129
|
+
"--coin",
|
|
130
|
+
params.coin,
|
|
131
|
+
"--side",
|
|
132
|
+
closeSide,
|
|
133
|
+
"--limit-px",
|
|
134
|
+
String(limitPx),
|
|
135
|
+
"--sz",
|
|
136
|
+
String(sz),
|
|
137
|
+
"--tif",
|
|
138
|
+
action.method === "market" ? "Ioc" : "Gtc",
|
|
139
|
+
"--reduce-only",
|
|
140
|
+
];
|
|
141
|
+
if (dex) {
|
|
142
|
+
args.push("--dex", dex);
|
|
143
|
+
}
|
|
144
|
+
if (params.live) {
|
|
145
|
+
args.push("--live");
|
|
146
|
+
}
|
|
147
|
+
if (params.assumeYes) {
|
|
148
|
+
args.push("--assume-yes");
|
|
149
|
+
}
|
|
150
|
+
return args;
|
|
151
|
+
}
|
|
152
|
+
if (action.action === "cancel_all") {
|
|
153
|
+
const args = [...g, "state", "cancel-open"];
|
|
154
|
+
if (params.live) {
|
|
155
|
+
args.push("--live");
|
|
156
|
+
}
|
|
157
|
+
if (params.assumeYes) {
|
|
158
|
+
args.push("--assume-yes");
|
|
159
|
+
}
|
|
160
|
+
return args;
|
|
161
|
+
}
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
export function formatCliInvocation(args) {
|
|
165
|
+
const { cmd, prefixArgs } = resolveJccHyperToolSpawn();
|
|
166
|
+
const all = [...prefixArgs, ...args];
|
|
167
|
+
const quote = (s) => (/\s/.test(s) ? JSON.stringify(s) : s);
|
|
168
|
+
const tail = all.map(quote).join(" ");
|
|
169
|
+
if (prefixArgs.length === 0) {
|
|
170
|
+
return `${quote(cmd)} ${tail}`;
|
|
171
|
+
}
|
|
172
|
+
return `${quote(cmd)} ${tail}`;
|
|
173
|
+
}
|
|
174
|
+
export function spawnJccHyperTool(args, opts) {
|
|
175
|
+
const { cmd, prefixArgs } = resolveJccHyperToolSpawn();
|
|
176
|
+
const mode = opts?.stdio ?? "pipe";
|
|
177
|
+
if (mode === "inherit") {
|
|
178
|
+
const r = spawnSync(cmd, [...prefixArgs, ...args], {
|
|
179
|
+
stdio: "inherit",
|
|
180
|
+
encoding: "utf-8",
|
|
181
|
+
});
|
|
182
|
+
return { status: r.status ?? 1, stdout: "", stderr: "" };
|
|
183
|
+
}
|
|
184
|
+
const r = spawnSync(cmd, [...prefixArgs, ...args], {
|
|
185
|
+
encoding: "utf-8",
|
|
186
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
status: r.status,
|
|
190
|
+
stdout: r.stdout ?? "",
|
|
191
|
+
stderr: r.stderr ?? "",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=actionRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionRunner.js","sourceRoot":"","sources":["../../src/advisor/actionRunner.ts"],"names":[],"mappings":"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"}
|