# 每周 Bench Review 流程 > 跟原作者的方法论一致:每周五对跟单钱包和 bench 观察区钱包做前瞻盈亏 review,决定晋升/降级。 > > 原作者的原话(HANDOFF_ARCHIVE.md):forward table = portfolio.py resolved rows, two windows: since last review and since the last swap. --- ## 为什么要每周 review watch_sharps.json 的 copy_pnl 是 **in-sample**(用历史数据算的),只能告诉你"过去跟这个钱包赚没赚"。但市场在变,钱包的表现也会变。 **前瞻盈亏(Forward P&L)** 是 out-of-sample 的:看"从某个时间点开始,这个钱包的信念单实际赚了多少"。这才是决定留还是踢的真实依据。 --- ## review 时间 **每周五**(跟作者一样)。可以在 1Panel 加一个定时提醒。 --- ## review 步骤 > 完整 7 步命令见 `每周五Review命令.md`(含一键跑全部的脚本)。以下是每步说明 + 执行操作。 ### 第 1 步:跑回测 > **做什么**:用最新 cache 数据对 backtest.json 里的所有钱包跑 30 天模拟跟单 > **相关文件**:`backtest.json`(输入)-> `portfolio.json`(输出) ```bash cd /opt/winning-wallet-finder/live python3 portfolio.py --days 30 ``` ### 第 2 步:看前瞻盈亏排名 > **做什么**:读 portfolio.json 的 wallets 数组,按 30 天前瞻 realized 排序 > **相关文件**:`portfolio.json`(读) > **这是决策的核心数据** ```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天前瞻盈亏排名 ===') 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} bets={w.get(\"bets\",0):3d} W={w.get(\"won\",0):2d} L={w.get(\"lost\",0):2d} S={w.get(\"sold\",0):2d} realized=\${w.get(\"realized\",0):+9.2f} [{tag}]') " ``` ### 第 3 步:看候选池排名 > **做什么**:读 watch_sharps.json,按 copy_pnl 排序,看信念胜率 > **相关文件**:`watch_sharps.json`(daily.sh 自动产出) > **注意**:copy_pnl 是 in-sample 的,会骗人,只作参考 ```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) 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 '?' print(f'#{i+1:2d} {name:20s} copy_pnl+{w.get(\"copy_pnl\",0):5d} conv_win={winstr}') print(f'总共 {len(data)} 个候选') " ``` ### 第 4 步:看 floor 漂移 > **做什么**:读 daily.log 里 sync_floors 的输出 > **相关文件**:`daily.log`(读) ```bash grep "floor" daily.log | tail -10 ``` ### 第 5 步:看本周跟单记录 > **做什么**:读 live bot 7 天日志 > **相关文件**:journalctl(systemd 日志) ```bash journalctl -u copybot-live --since "7 days ago" --no-pager | grep -E "FOLLOW|OPEN|skip" | tail -30 ``` ### 第 6 步:看链上余额 > **做什么**:查存款钱包的实际 pUSD 余额 > **相关文件**:`/etc/copybot/live.env`(读私钥) ```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.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(f'watch_sharps {len(sharps)} 个,backtest.json {len(bt[\"wallets\"])} 个,新候选 {len(new_candidates)} 个') print() 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 '?' print(f'{name:20s} copy_pnl+{w.get(\"copy_pnl\",0):5d} conv_win={winstr}') " ``` --- ## 决策(5 个维度) 对照 5 个维度做决策(详见 `AGENT.md`): | 维度 | 数据来源 | 晋升条件 | 降级条件 | |------|---------|---------|---------| | **前瞻盈亏** | 第 2 步 portfolio.json | 正盈亏 | 连续 2 周负 | | **copy_pnl** | 第 3 步 watch_sharps.json | 排名靠前 | 跌出 watch_sharps | | **信念胜率** | 第 3 步 watch_sharps.json | >60% | <30% | | **季节性 + niche** | 第 5 步日志 + 人工判断 | 赛季开始 / ITF网球 / 三级电竞 | 赛季结束 / 5min BTC / 长持仓 | | **floor 稳定** | 第 4 步 daily.log | 正常 | p80 漂移 > 15% 需 pin | --- ## 执行操作 ### 晋升(bench -> live) > 从 backtest.json 里选一个表现好的,加到跟单配置 ```bash cd /opt/winning-wallet-finder python3 -c " import json promote_name = 'AIcAIc' # 改成你要晋升的钱包 bt = json.load(open('live/backtest.json')) promote = next((w for w in bt['wallets'] if w.get('name') == promote_name), None) if not promote: print(f'{promote_name} not found in backtest.json'); exit(1) for path in ['live/copybot.paper.json', 'config.live.json']: cfg = json.load(open(path)) if not any(w['wallet'].lower() == promote['wallet'].lower() for w in cfg['wallets']): cfg['wallets'].append({'wallet': promote['wallet'], 'name': promote['name'], 'class': 'volume', 'floor': 25.0}) json.dump(cfg, open(path, 'w'), indent=2) print(f'{path}: added {promote_name}') " chown wwf:wwf live/copybot.paper.json config.live.json systemctl restart copybot-paper copybot-live ``` ### 降级(live -> bench) > 从跟单配置里删除,但留在 backtest.json 继续观察 ```bash cd /opt/winning-wallet-finder python3 -c " import json demote_name = 'BikesAreTheBikes' # 改成你要降级的钱包 for path in ['live/copybot.paper.json', 'config.live.json']: cfg = json.load(open(path)) old = [w['name'] for w in cfg['wallets']] cfg['wallets'] = [w for w in cfg['wallets'] if w['name'] != demote_name] json.dump(cfg, open(path, 'w'), indent=2) print(f'{path}: {old} -> {[w[\"name\"] for w in cfg[\"wallets\"]]}') " chown wwf:wwf live/copybot.paper.json config.live.json systemctl restart copybot-paper copybot-live ``` ### 加新候选到 bench 观察区 > 从第 7 步发现的新钱包里选一个,加到 backtest.json 开始追踪前瞻表现 ```bash cd /opt/winning-wallet-finder/live python3 -c " import json new_wallet = '0xNEW_WALLET_ADDRESS' # 从第 7 步输出里选 new_name = 'NewWalletName' # 对应的名字 bt = json.load(open('backtest.json')) if not any(w['wallet'].lower() == new_wallet.lower() for w in bt['wallets']): bt['wallets'].append({'wallet': new_wallet, 'name': new_name, 'class': 'volume'}) json.dump(bt, open('backtest.json', 'w'), indent=2) print(f'已添加 {new_name} 到 backtest.json,总共 {len(bt[\"wallets\"])} 个') print('下周 review 就能看到它的前瞻盈亏了') else: print(f'{new_name} 已在 backtest.json 里') " ``` > 加完后不需要重启 bot(backtest.json 只被 daily.sh 的 portfolio.py 读,不影响 bot 运行)。 > 但需要手动跑一次 `python3 portfolio.py --days 30` 确认新钱包有数据。 ### 钉死 floor_pin > 如果第 4 步显示某个钱包 floor 漂移太大 ```bash cd /opt/winning-wallet-finder python3 -c " import json pin_name = 'Kruto2027' # 要钉的钱包 pin_value = 80.0 # 钉死的值 for path in ['live/copybot.paper.json', 'config.live.json']: cfg = json.load(open(path)) for w in cfg['wallets']: if w['name'] == pin_name: w['floor'] = pin_value w['floor_pin'] = pin_value print(f'{path}: {pin_name} floor_pin = {pin_value}') json.dump(cfg, open(path, 'w'), indent=2) " chown wwf:wwf live/copybot.paper.json config.live.json systemctl restart copybot-paper copybot-live ``` ### 更新 setup_wallets.py > 每次换完钱包后,同步更新 setup_wallets.py 里的 OUR_WALLETS 数组,下次 sync-upstream 时不会丢 --- ## 当前状态 ### live 跟单(8 个) | 钱包 | floor | floor_pin | niche | |------|-------|-----------|-------| | Kruto2027 | $80 | ✅ 80 | 综合 | | 0xbadaf319 | $42 | - | 综合 | | 1kto1m | $332 | - | BTC Up/Down | | Vahan88 | $245 | - | 板球/体育 | | LSB1 | $315 | - | 瑞典足球 | | EdwardIN | $25 | - | 待观察 | | lma0o0o0o | $25 | - | 待观察 | | Coteykens | $25 | - | 待观察 | ### bench 观察(8 个) | 钱包 | 状态 | 备注 | |------|------|------| | gkmgkldfmg | 被淘汰 | daily.sh 已移出 watch_sharps | | AIcAIc | 观察 | 作者 07-16 重新加入(电竞赛季) | | BikesAreTheBikes | 观察 | 信念胜率 21% 偏低 | | imwalkinghere | 永久排除 | 5min BTC 市场,结算比跟单快 | | leegunner | 新候选 | 作者 bench rev 5 新加 | | oliman2 | 新候选 | 作者 bench rev 5 新加 | | JuiceFarm | 新候选 | 作者 bench rev 5 新加 | | 0xb0E43B | 新候选 | 作者 bench rev 5 新加 | --- ## 1Panel 快速命令 **每周 review 一键跑全部 7 步**:见 `每周五Review命令.md` 末尾的整段脚本,复制到 1Panel 保存为快速命令。