24af8d88f0
7 steps with comments explaining what each does and which files it reads: 1. Run portfolio.py --days 30 (regenerate forward P&L) 2. Read portfolio.json per-wallet forward realized (core decision data) 3. Read watch_sharps.json copy_pnl + conv_win rankings (reference only) 4. Check daily.log for floor drift warnings 5. Check live bot journalctl for trading activity 6. Query chain pUSD balance via SecureClient 7. Find new candidates in watch_sharps not in backtest.json Includes one-shot script that runs all 7 steps at once.
245 lines
9.3 KiB
Markdown
245 lines
9.3 KiB
Markdown
# 每周五 Bench Review 完整流程
|
||
|
||
> 每周五在服务器上跑一遍,把输出贴给 AI 代理分析。
|
||
> AI 代理按 AGENT.md 的 5 个维度给建议,人类拍板执行。
|
||
|
||
---
|
||
|
||
## 第 1 步:重新跑 30 天回测
|
||
|
||
> **做什么**:用最新的 cache 数据,对 backtest.json 里的所有钱包(live + bench)跑一次 30 天模拟跟单,产出 portfolio.json
|
||
>
|
||
> **相关文件**:`backtest.json`(输入:钱包列表)-> `portfolio.json`(输出:前瞻盈亏)
|
||
|
||
```bash
|
||
cd /opt/winning-wallet-finder/live && python3 portfolio.py --days 30
|
||
```
|
||
|
||
---
|
||
|
||
## 第 2 步:看每个钱包的前瞻盈亏排名
|
||
|
||
> **做什么**:读 portfolio.json 的 wallets 数组,按 30 天前瞻 realized 盈亏排序,标注哪个是 LIVE 哪个是 bench
|
||
>
|
||
> **相关文件**:`portfolio.json`(读)-> `copybot.paper.json`(对比哪些是 LIVE)
|
||
>
|
||
> **这是决策的核心数据**:前瞻 realized > 0 才考虑保留,连续 2 周负考虑降级
|
||
|
||
```bash
|
||
python3 -c "
|
||
import json
|
||
d = json.load(open('portfolio.json'))
|
||
live_names = {'Kruto2027','0xbadaf319','1kto1m','Vahan88','LSB1','EdwardIN','lma0o0o0o','Coteykens'}
|
||
ws = d.get('wallets', [])
|
||
print('=== 30天前瞻盈亏排名 ===')
|
||
print(f'{\"钱包\":20s} {\"笔数\":>4s} {\"胜\":>3s} {\"负\":>3s} {\"卖\":>3s} {\"已实现\":>10s} {\"状态\":>6s}')
|
||
print('-' * 60)
|
||
for w in sorted(ws, key=lambda x: x.get('realized',0), reverse=True):
|
||
name = w.get('name','?')
|
||
tag = 'LIVE' if name in live_names else 'bench'
|
||
print(f'{name:20s} {w.get(\"bets\",0):4d} {w.get(\"won\",0):3d} {w.get(\"lost\",0):3d} {w.get(\"sold\",0):3d} \${w.get(\"realized\",0):+9.2f} {tag:>6s}')
|
||
print(f'\n总计: equity \${d[\"equity\"]:,.0f} | realized \${d[\"realized\"]:+,.0f} | {d[\"resolved_count\"]} resolved')
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## 第 3 步:看候选池排名
|
||
|
||
> **做什么**:读 watch_sharps.json,按 copy_pnl 排序,看信念胜率和前瞻胜率
|
||
>
|
||
> **相关文件**:`watch_sharps.json`(daily.sh 自动产出)
|
||
>
|
||
> **注意**:copy_pnl 是 in-sample 的,会骗人(oliman2 copy_pnl #1 但前瞻亏)。只作参考,不作决策依据
|
||
|
||
```bash
|
||
cat watch_sharps.json | python3 -c "
|
||
import sys,json
|
||
data=json.load(sys.stdin)
|
||
data.sort(key=lambda w: w.get('copy_pnl',0), reverse=True)
|
||
print('=== watch_sharps 候选排名 ===')
|
||
for i,w in enumerate(data):
|
||
name = w.get('name') or w.get('wallet','')[:10]
|
||
win = w.get('conv_win')
|
||
winstr = f'{win:.0f}%' if win is not None else '?'
|
||
fwd = w.get('fwd_win',0)
|
||
fwdstr = f'{fwd:.0f}%' if fwd else '?'
|
||
print(f'#{i+1:2d} {name:20s} copy_pnl+{w.get(\"copy_pnl\",0):5d} conv_win={winstr} fwd_win={fwdstr}')
|
||
print(f'\n总共 {len(data)} 个候选')
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## 第 4 步:看 floor 有没有漂移
|
||
|
||
> **做什么**:读 daily.log 里 sync_floors 的输出,看有没有门槛大幅漂移的警告
|
||
>
|
||
> **相关文件**:`daily.log`(读)-> `copybot.paper.json`(floor 被 sync_floors.py 写入)
|
||
>
|
||
> **判断**:`⚠ floor X->Y` 漂移 > 15% -> 建议钉 floor_pin 防止 paper/live 门槛不一致
|
||
|
||
```bash
|
||
grep "floor" daily.log | tail -10
|
||
```
|
||
|
||
---
|
||
|
||
## 第 5 步:看本周 bot 跟单记录
|
||
|
||
> **做什么**:读 live bot 最近 7 天的日志,看 FOLLOW(跟了什么)、skip(跳过了什么)、OPEN(实际下单了什么)
|
||
>
|
||
> **相关文件**:journalctl(systemd 日志)
|
||
>
|
||
> **用途**:看 bot 实际跟了哪些信号、有没有异常(大量 skip / ORDER FAILED / RTDS down)
|
||
|
||
```bash
|
||
journalctl -u copybot-live --since "7 days ago" --no-pager | grep -E "FOLLOW|OPEN|skip" | tail -30
|
||
```
|
||
|
||
---
|
||
|
||
## 第 6 步:看链上真实余额
|
||
|
||
> **做什么**:通过 SecureClient 查存款钱包的实际 pUSD 余额
|
||
>
|
||
> **相关文件**:`/etc/copybot/live.env`(读私钥)-> Polymarket 链上
|
||
>
|
||
> **用途**:确认真实资金状况,对比 bot 账本是否一致(CASH≠CHAIN)
|
||
|
||
```bash
|
||
export LIVE_PRIVATE_KEY=$(grep LIVE_PRIVATE_KEY /etc/copybot/live.env | cut -d= -f2-) && export HTTPS_PROXY=http://127.0.0.1:7890 && python3 -c "from polymarket import SecureClient; c=SecureClient.create(private_key='$LIVE_PRIVATE_KEY'); b=c.get_balance_allowance(asset_type='COLLATERAL'); print('链上 pUSD: %.2f' % (b.balance/1e6)); c.close()"
|
||
```
|
||
|
||
---
|
||
|
||
## 第 7 步:找出新候选(watch_sharps 里有但 backtest.json 里没有的)
|
||
|
||
> **做什么**:对比 watch_sharps.json 和 backtest.json,找出 daily.sh 新筛出来但还没在观察区的钱包
|
||
>
|
||
> **相关文件**:`watch_sharps.json`(读:全部候选)+ `backtest.json`(读:已在观察的)
|
||
>
|
||
> **用途**:发现新钱包,如果 copy_pnl 高 + 信念胜率好,加到 backtest.json 开始观察前瞻表现
|
||
|
||
```bash
|
||
python3 -c "
|
||
import json
|
||
sharps = json.load(open('watch_sharps.json'))
|
||
bt = json.load(open('backtest.json'))
|
||
bt_addrs = {w['wallet'].lower() for w in bt['wallets']}
|
||
|
||
new_candidates = [w for w in sharps if w.get('wallet','').lower() not in bt_addrs]
|
||
new_candidates.sort(key=lambda w: w.get('copy_pnl',0), reverse=True)
|
||
|
||
print('=== watch_sharps 里的新候选(不在 backtest.json 里)===')
|
||
print(f'watch_sharps 总共 {len(sharps)} 个,backtest.json 已有 {len(bt[\"wallets\"])} 个')
|
||
print(f'新候选: {len(new_candidates)} 个')
|
||
print()
|
||
print(f'{\"名字\":20s} {\"copy_pnl\":>10s} {\"信念胜率\":>8s} {\"前瞻胜率\":>8s}')
|
||
print('-' * 50)
|
||
for w in new_candidates[:15]:
|
||
name = w.get('name') or w.get('wallet','')[:10]
|
||
win = w.get('conv_win')
|
||
winstr = f'{win:.0f}%' if win is not None else '?'
|
||
fwd = w.get('fwd_win',0)
|
||
fwdstr = f'{fwd:.0f}%' if fwd else '?'
|
||
print(f'{name:20s} +{w.get(\"copy_pnl\",0):9d} {winstr:>8s} {fwdstr:>8s}')
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## 一键跑全部 7 步
|
||
|
||
> 如果想一次性跑完所有步骤,复制下面整段:
|
||
|
||
```bash
|
||
cd /opt/winning-wallet-finder/live
|
||
|
||
echo "========== 第 1 步:跑回射 =========="
|
||
python3 portfolio.py --days 30
|
||
|
||
echo ""
|
||
echo "========== 第 2 步:前瞻盈亏排名 =========="
|
||
python3 -c "
|
||
import json
|
||
d = json.load(open('portfolio.json'))
|
||
live_names = {'Kruto2027','0xbadaf319','1kto1m','Vahan88','LSB1','EdwardIN','lma0o0o0o','Coteykens'}
|
||
ws = d.get('wallets', [])
|
||
print('=== 30天前瞻盈亏排名 ===')
|
||
print(f'{\"钱包\":20s} {\"笔数\":>4s} {\"胜\":>3s} {\"负\":>3s} {\"卖\":>3s} {\"已实现\":>10s} {\"状态\":>6s}')
|
||
print('-' * 60)
|
||
for w in sorted(ws, key=lambda x: x.get('realized',0), reverse=True):
|
||
name = w.get('name','?')
|
||
tag = 'LIVE' if name in live_names else 'bench'
|
||
print(f'{name:20s} {w.get(\"bets\",0):4d} {w.get(\"won\",0):3d} {w.get(\"lost\",0):3d} {w.get(\"sold\",0):3d} \${w.get(\"realized\",0):+9.2f} {tag:>6s}')
|
||
print(f'\n总计: equity \${d[\"equity\"]:,.0f} | realized \${d[\"realized\"]:+,.0f} | {d[\"resolved_count\"]} resolved')
|
||
"
|
||
|
||
echo ""
|
||
echo "========== 第 3 步:候选池排名 =========="
|
||
cat watch_sharps.json | python3 -c "
|
||
import sys,json
|
||
data=json.load(sys.stdin)
|
||
data.sort(key=lambda w: w.get('copy_pnl',0), reverse=True)
|
||
print('=== watch_sharps 候选排名 ===')
|
||
for i,w in enumerate(data):
|
||
name = w.get('name') or w.get('wallet','')[:10]
|
||
win = w.get('conv_win')
|
||
winstr = f'{win:.0f}%' if win is not None else '?'
|
||
fwd = w.get('fwd_win',0)
|
||
fwdstr = f'{fwd:.0f}%' if fwd else '?'
|
||
print(f'#{i+1:2d} {name:20s} copy_pnl+{w.get(\"copy_pnl\",0):5d} conv_win={winstr} fwd_win={fwdstr}')
|
||
print(f'\n总共 {len(data)} 个候选')
|
||
"
|
||
|
||
echo ""
|
||
echo "========== 第 4 步:floor 漂移 =========="
|
||
grep "floor" daily.log | tail -10
|
||
|
||
echo ""
|
||
echo "========== 第 5 步:本周跟单记录 =========="
|
||
journalctl -u copybot-live --since "7 days ago" --no-pager | grep -E "FOLLOW|OPEN|skip" | tail -30
|
||
|
||
echo ""
|
||
echo "========== 第 6 步:链上余额 =========="
|
||
export LIVE_PRIVATE_KEY=$(grep LIVE_PRIVATE_KEY /etc/copybot/live.env | cut -d= -f2-) && export HTTPS_PROXY=http://127.0.0.1:7890 && python3 -c "from polymarket import SecureClient; c=SecureClient.create(private_key='$LIVE_PRIVATE_KEY'); b=c.get_balance_allowance(asset_type='COLLATERAL'); print('链上 pUSD: %.2f' % (b.balance/1e6)); c.close()"
|
||
|
||
echo ""
|
||
echo "========== 第 7 步:新候选 =========="
|
||
python3 -c "
|
||
import json
|
||
sharps = json.load(open('watch_sharps.json'))
|
||
bt = json.load(open('backtest.json'))
|
||
bt_addrs = {w['wallet'].lower() for w in bt['wallets']}
|
||
new_candidates = [w for w in sharps if w.get('wallet','').lower() not in bt_addrs]
|
||
new_candidates.sort(key=lambda w: w.get('copy_pnl',0), reverse=True)
|
||
print('=== watch_sharps 里的新候选(不在 backtest.json 里)===')
|
||
print(f'watch_sharps 总共 {len(sharps)} 个,backtest.json 已有 {len(bt[\"wallets\"])} 个')
|
||
print(f'新候选: {len(new_candidates)} 个')
|
||
print()
|
||
print(f'{\"名字\":20s} {\"copy_pnl\":>10s} {\"信念胜率\":>8s} {\"前瞻胜率\":>8s}')
|
||
print('-' * 50)
|
||
for w in new_candidates[:15]:
|
||
name = w.get('name') or w.get('wallet','')[:10]
|
||
win = w.get('conv_win')
|
||
winstr = f'{win:.0f}%' if win is not None else '?'
|
||
fwd = w.get('fwd_win',0)
|
||
fwdstr = f'{fwd:.0f}%' if fwd else '?'
|
||
print(f'{name:20s} +{w.get(\"copy_pnl\",0):9d} {winstr:>8s} {fwdstr:>8s}')
|
||
"
|
||
|
||
echo ""
|
||
echo "========== 全部完成,把以上输出贴给 AI 代理分析 =========="
|
||
```
|
||
|
||
---
|
||
|
||
## 跑完后
|
||
|
||
1. 把全部输出复制给 AI 代理
|
||
2. AI 代理按 AGENT.md 的 5 个维度分析,输出建议报告
|
||
3. 人类根据建议做决策
|
||
4. 人类在服务器执行变更(晋升/降级/钉 floor/加新候选)
|
||
5. 变更后更新 `setup_wallets.py` 记录
|