xuanzhu 0.11.0 → 0.13.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/README.md +4 -2
- package/dist/assets/btc/paper.py +55 -3
- package/dist/cli.js +548 -543
- package/dist/skills/btc-paper-trading/SKILL.md +19 -0
- package/dist/skills/btc-trading-ops/SKILL.md +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -234,6 +234,7 @@ xzh
|
|
|
234
234
|
| `/model [编号\|id]` | 查看 / 切换当前模型 |
|
|
235
235
|
| `/auto [on\|off]` | 自动批准(**不带参数 = 开**,`/auto off` 才关;写入配置) |
|
|
236
236
|
| `/autonomy [ask\|observe\|auto]` | 自治等级:逐项确认 / 只观察 / 全自动 |
|
|
237
|
+
| `/monitor` | 查看全部叫醒条件(完整阈值 / 公式 / 链式进度);面板只显示前 2 条 |
|
|
237
238
|
| `/compact` / `/context` / `/usage` | 压缩历史 / 看上下文预算 / 看 token 用量 |
|
|
238
239
|
| `/tools` | 列出本轮发给模型的工具(排查「某个工具没被调用」) |
|
|
239
240
|
| `/memory` | 查看项目记忆(`show`、`global`、`clear`) |
|
|
@@ -1250,7 +1251,7 @@ xzh btc stop # 两个都停(--paper 只停模拟盘)
|
|
|
1250
1251
|
| 成交 | **限价挂单**:价格到达限价即成交;限价已在市场另一侧则**挂出即成交**,成交价取更优价(不会比限价差) |
|
|
1251
1252
|
| 价格源 | 实时标记价;取不到才用库内最新收盘价,并在输出里标注「可能滞后」 |
|
|
1252
1253
|
| 成本 | 手续费 0.05%(开平各一次),不计资金费 |
|
|
1253
|
-
| 杠杆 | `
|
|
1254
|
+
| 杠杆 | **默认 9x**(`BTC_PAPER_LEVERAGE` 可覆盖),由 xzh 按可用余额与信心调整;余额不足时自动提到「够开这一单」,**上限 20x**,显式给的倍率不会被改写 |
|
|
1254
1255
|
| 持仓 | 同时只允许一个持仓;可挂多档(最多 5 张未成交) |
|
|
1255
1256
|
| 初始资金 | 默认 100000 USDT(`BTC_PAPER_CAPITAL` 可改) |
|
|
1256
1257
|
| 账本 | `~/.btc/data/btc.db` 的 `paper_account` / `paper_trades` 表 |
|
|
@@ -1348,7 +1349,8 @@ btc 模式下右侧面板不再是终端,而是只读仪表盘(每 8 秒刷
|
|
|
1348
1349
|
两段数据各有边界:
|
|
1349
1350
|
|
|
1350
1351
|
- **监控**:倒计时来自后端 state(每 5 分钟评估一次叫醒条件);后端没在跑时显示「后端未运行」。
|
|
1351
|
-
面板只列前 2
|
|
1352
|
+
面板只列前 2 条条件并附带最近观测值;描述比右栏宽时按显示宽度**折行**(每条最多 3 行),
|
|
1353
|
+
不再整行截断。要看全部条件用 `/monitor`(不经过模型,直接打印配置)。
|
|
1352
1354
|
- **最近交易**:模拟盘读虚拟账本的已平仓记录(最近 3 笔,含入场→出场与盈亏);
|
|
1353
1355
|
实盘读动作账本 `run/actions.jsonl`(只含**我们自己发起**的开/平仓,手动操作不在内)。
|
|
1354
1356
|
|
package/dist/assets/btc/paper.py
CHANGED
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
"""
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
import math
|
|
17
18
|
import os
|
|
18
19
|
import sqlite3
|
|
19
20
|
from datetime import datetime, timedelta, timezone
|
|
20
21
|
|
|
21
22
|
FEE_RATE = 0.0005
|
|
23
|
+
#: 余额不足时自动提高倍率的上限(与 Node 侧 `MAX_AUTO_LEVERAGE` 一致)
|
|
24
|
+
MAX_AUTO_LEVERAGE = 20.0
|
|
22
25
|
|
|
23
26
|
SCHEMA = """
|
|
24
27
|
CREATE TABLE IF NOT EXISTS paper_account (
|
|
@@ -369,6 +372,18 @@ def status(
|
|
|
369
372
|
"unrealized_pct": round(unrealized / notional * 100, 2) if notional else 0.0,
|
|
370
373
|
}
|
|
371
374
|
|
|
375
|
+
# 占用保证金 = 持仓占用 + 未成交挂单占用;「可用」就是 cash(已扣过占用)
|
|
376
|
+
pending_margin = 0.0
|
|
377
|
+
for row in conn.execute(
|
|
378
|
+
"SELECT notional, leverage FROM paper_orders WHERE status='open'"
|
|
379
|
+
).fetchall():
|
|
380
|
+
pending_margin += float(row["notional"] or 0) / _lev(row["leverage"])
|
|
381
|
+
position_margin = (
|
|
382
|
+
float(account["entry_notional"]) / _lev(account["leverage"])
|
|
383
|
+
if account["side"]
|
|
384
|
+
else 0.0
|
|
385
|
+
)
|
|
386
|
+
|
|
372
387
|
initial = float(account["initial_capital"])
|
|
373
388
|
return {
|
|
374
389
|
"symbol": symbol,
|
|
@@ -377,7 +392,10 @@ def status(
|
|
|
377
392
|
"price_source": "mark" if _mark(mark) is not None else "close",
|
|
378
393
|
"initial_capital": round(initial, 2),
|
|
379
394
|
"cash": round(cash, 2),
|
|
395
|
+
"available": round(cash, 2),
|
|
380
396
|
"equity": round(equity, 2),
|
|
397
|
+
"margin_used": round(position_margin + pending_margin, 2),
|
|
398
|
+
"leverage": _lev(account["leverage"]) if account["side"] else None,
|
|
381
399
|
"return_pct": round((equity - initial) / initial * 100, 2) if initial else 0.0,
|
|
382
400
|
"position": position,
|
|
383
401
|
"open_orders": open_orders(conn),
|
|
@@ -424,7 +442,14 @@ def place_order(
|
|
|
424
442
|
if pending is not None and int(pending["n"]) >= 5:
|
|
425
443
|
raise RuntimeError("未成交挂单已有 5 张(多档上限),先撤掉不用的再挂")
|
|
426
444
|
|
|
427
|
-
|
|
445
|
+
# 模拟盘是**合约**:没有倍率就没有意义。优先级:
|
|
446
|
+
# 调用方显式给 → BTC_PAPER_LEVERAGE → 默认 9(与内置策略的 leverage=9 一致)
|
|
447
|
+
explicit_leverage = leverage is not None
|
|
448
|
+
lev = (
|
|
449
|
+
_lev(leverage)
|
|
450
|
+
if explicit_leverage
|
|
451
|
+
else _lev(os.getenv("BTC_PAPER_LEVERAGE") or 9)
|
|
452
|
+
)
|
|
428
453
|
qty = notional / limit_price
|
|
429
454
|
margin = notional / lev
|
|
430
455
|
fee = notional * FEE_RATE
|
|
@@ -436,10 +461,35 @@ def place_order(
|
|
|
436
461
|
"SELECT notional, leverage FROM paper_orders WHERE status='open'"
|
|
437
462
|
).fetchall():
|
|
438
463
|
occupied += float(row["notional"] or 0) / _lev(row["leverage"])
|
|
464
|
+
|
|
465
|
+
# 余额不足且倍率是默认值(不是调用方指定)时,允许自动提高到刚好够开,上限 20x。
|
|
466
|
+
# 显式指定 5x 说明调用方想保守,不能悄悄改成 20x。
|
|
467
|
+
auto_bumped = False
|
|
468
|
+
need = 0.0
|
|
469
|
+
room = cash - occupied - fee
|
|
470
|
+
if room > 0 and notional > 0:
|
|
471
|
+
need = math.ceil(notional / room)
|
|
472
|
+
if occupied + margin + fee > cash + 1e-9 and not explicit_leverage:
|
|
473
|
+
if room > 0 and need <= MAX_AUTO_LEVERAGE and need > lev:
|
|
474
|
+
lev = float(need)
|
|
475
|
+
margin = notional / lev
|
|
476
|
+
auto_bumped = True
|
|
477
|
+
|
|
439
478
|
if occupied + margin + fee > cash + 1e-9:
|
|
479
|
+
need_text = (
|
|
480
|
+
f"至少需要 {need:g}x(上限 {MAX_AUTO_LEVERAGE:g}x)"
|
|
481
|
+
if need > 0
|
|
482
|
+
else "可用余额不足以覆盖已挂单占用与手续费"
|
|
483
|
+
)
|
|
484
|
+
if explicit_leverage:
|
|
485
|
+
raise RuntimeError(
|
|
486
|
+
f"可用保证金不足:按你指定的 {lev:g}x 本单需 {margin:.2f}"
|
|
487
|
+
f"(名义 {notional:.2f})+ 手续费 {fee:.2f},已挂单占用 {occupied:.2f},"
|
|
488
|
+
f"当前可用 {cash:.2f};{need_text},或减少名义金额。"
|
|
489
|
+
)
|
|
440
490
|
raise RuntimeError(
|
|
441
|
-
f"
|
|
442
|
-
f"
|
|
491
|
+
f"可用保证金不足:{need_text}。名义 {notional:.2f}、手续费 {fee:.2f}、"
|
|
492
|
+
f"已挂单占用 {occupied:.2f}、当前可用 {cash:.2f} —— 请减少名义或先入金。"
|
|
443
493
|
)
|
|
444
494
|
|
|
445
495
|
minutes = 60.0
|
|
@@ -469,6 +519,8 @@ def place_order(
|
|
|
469
519
|
"status": "open",
|
|
470
520
|
"expires_at": expires_at,
|
|
471
521
|
"leverage": lev,
|
|
522
|
+
# 余额不足被自动提上来的倍率(调用方要据此提醒「强平更近」)
|
|
523
|
+
"leverage_auto": auto_bumped,
|
|
472
524
|
}
|
|
473
525
|
|
|
474
526
|
|