## 全局地图 ``` 服务器 │ ├── /opt/winning-wallet-finder/ ← 项目代码(git clone 来的) │ ├── copybot.py ← bot 主程序 │ ├── copybot.paper.json ← paper 配置(跟哪些钱包、金额) │ ├── config.live.json ← live 配置(跟哪些钱包、金额) │ ├── copybot_state.json ← paper bot 的账本(自动生成) │ ├── copybot_state.live.json ← live bot 的账本(自动生成) │ ├── copybot_fills.jsonl ← paper 成交记录 │ ├── copybot_fills.live.jsonl ← live 成交记录 │ └── live/ │ ├── serve_dashboard.py ← 网页 dashboard 程序 │ ├── bot_dashboard.html ← 中文界面 │ ├── copybot_live.json ← paper bot 的实时 feed │ ├── copybot_live_real.json ← live bot 的实时 feed │ ├── portfolio.py ← 回测程序 │ ├── backtest.json ← 回测配置 │ ├── daily.sh ← 每日流水线 │ └── cache.duckdb ← 钱包历史数据缓存 │ ├── /etc/systemd/system/ ← systemd 服务定义(4 个) │ ├── copybot-paper.service ← paper bot 服务 │ ├── copybot-live.service ← live bot 服务 │ ├── copybot-dashboard.service ← dashboard 服务 │ └── mihomo.service ← 代理服务 │ ├── /etc/copybot/ ← 环境变量文件(密钥、代理) │ ├── paper.env ← paper bot 的环境变量 │ └── live.env ← live bot 的环境变量 │ ├── /etc/mihomo/ ← 代理配置 │ ├── config.yaml ← Clash 订阅配置 │ └── cache.db ← 记住上次选的节点 │ ├── /usr/local/bin/mihomo ← 代理程序本体(二进制) ├── /opt/mihomo-healthcheck.sh ← 代理健康检查脚本 ├── /opt/winning-wallet-finder/.netrc ← Gitea PAT 认证(wwf 用户用,bot 自动 push 时读) │ └── crontab ← 定时任务 ├── 0 2 * * * daily.sh ← 每日 10:00 北京时间跑回测 └── */5 * * * * mihomo-healthcheck.sh ← 每 5 分钟检查代理 ``` > `.netrc` 不在目录树里显示是因为它是隐藏文件(以 `.` 开头)。用 `ls -la` 才能看到。 ## 三个文件夹的分工 | 文件夹 | 放什么 | 为什么在这 | | ----------------------------- | -------------------------- | ---------------------------------- | | `/opt/winning-wallet-finder/` | 项目代码 + 配置 + 状态 | git clone 来的,所有代码在这 | | `/etc/systemd/system/` | 服务定义(.service 文件) | Linux 约定俗成,systemd 服务都放这 | | `/etc/copybot/` | 环境变量(密钥、代理地址) | 敏感文件不放代码仓库,独立管理 | | `/etc/mihomo/` | 代理配置 | mihomo 的数据目录 | > `/opt` 是你的代码,`/etc` 是系统配置。分开是因为**密钥不应该跟代码放一起**(怕 commit 到 Gitea 泄露)。 ## live.env 和 config.live.json 怎么连起来的 它们**不在一个文件夹**,但 systemd 是桥梁: ``` /etc/systemd/system/copybot-live.service │ │ ExecStart=python3 copybot.py --config config.live.json --live │ ↑ │ 读 /opt/winning-wallet-finder/config.live.json │ (跟哪些钱包、金额、风险参数) │ │ EnvironmentFile=/etc/copybot/live.env │ ↑ │ 读 /etc/copybot/live.env │ (私钥、代理地址、确认短语) │ ▼ copybot.py 启动时: 1. 从 EnvironmentFile 读 LIVE_PRIVATE_KEY -> 放进 config["live"]["private_key"] 2. 从 EnvironmentFile 读 HTTPS_PROXY -> 所有网络请求走代理 3. 从 --config 读 config.live.json -> 知道跟哪些钱包、bankroll 多少 4. 合并两者 -> 完整配置 ``` 简单说: | 文件 | 内容 | 在哪 | 谁读 | | ------------------ | -------------------------- | ----------------------------- | ------------------------------------------ | | `config.live.json` | 跟哪些钱包、金额、风险参数 | `/opt/winning-wallet-finder/` | `--config` 参数传给 copybot.py | | `live.env` | 私钥、代理、确认短语 | `/etc/copybot/` | systemd `EnvironmentFile` 自动注入环境变量 | **为什么要分开**:config.live.json 可以 commit 到 Gitea(里面没有密钥),live.env 绝不能 commit(里面有私钥)。 ## 每个服务的完整启动链 ``` paper bot: systemd -> copybot.py --config copybot.paper.json + EnvironmentFile: paper.env (ALCHEMY_RPC_URL) = 直连 Polymarket,不走代理 live bot: systemd -> copybot.py --config config.live.json --live + EnvironmentFile: live.env (LIVE_PRIVATE_KEY + HTTPS_PROXY + TRADE LIVE) = 走代理绕 geo-block,真钱下单 dashboard: systemd -> serve_dashboard.py = 读本地 JSON 文件(不涉及 Gitea),网页展示 - /api/feed -> live/copybot_live.json (paper) - /api/live -> live/copybot_live_real.json (live) - / -> live/bot_dashboard.html (中文界面) mihomo: systemd -> mihomo -d /etc/mihomo = 代理服务,监听 127.0.0.1:7890 ``` ## bot 自动推 Gitea(自动备份 + 远程可读) bot 和 daily.sh 会自动把状态文件 commit + push 到 Gitea,**不需要你手动操作**。 ### 推什么 | 推什么 | 频率 | 谁推的 | 目的 | |---|---|---|---| | `copybot_state.json` / `copybot_state.live.json` | 有状态变化时(节流) | bot 自动(`publish_feed()`) | 备份账本 | | `live/copybot_live.json` / `live/copybot_live_real.json` | 有状态变化时 | bot 自动 | 备份 feed | | `copybot_fills.jsonl` / `copybot_fills.live.jsonl` | 有成交时 | bot 自动 | 备份成交记录 | | `live/watch_sharps.json` + `watch_skilled.json` + `dashboard.html` + `portfolio.json` | 每天 1 次 | daily.sh 自动 | 刷新钱包池 | ### 认证方式 wwf 用户的 `.netrc` 文件(`/opt/winning-wallet-finder/.netrc`)里有 Gitea PAT,git push 时自动读,不需要手动输密码。 ### git log 里你会看到 ``` copybot: live paper feed [skip ci] ← bot 自动推的(每次有状态变化) fix: re-query order after cancel... ← 你手动推的(改代码) docs: add 日常使用.md... ← 你手动推的(改文档) ``` `[skip ci]` 表示跳过 CI(这个项目没配 CI,只是习惯标记)。 ### 这导致的副作用 你在本地改完代码 `git push` 时经常被拒: ``` ! [rejected] main -> main (fetch first) ``` 因为服务器上的 bot 已经自动 commit 了新的 state。解决方法: ```bash # 方法 1:rebase(推荐,保留你的改动) git pull --rebase --autostash origin main && git push origin main # 方法 2:强制用远程版本(会丢本地未提交的改动,慎用) git fetch origin && git reset --hard origin/main ``` ### 远程读 JSON(不用 SSH 上服务器) Gitea 提供 raw URL,浏览器直接访问就能看 bot 的实时数据: ``` # paper bot feed https://code.aifunny.ltd/gavindiaz/winning-wallet-finder/raw/branch/main/live/copybot_live.json # live bot feed https://code.aifunny.ltd/gavindiaz/winning-wallet-finder/raw/branch/main/live/copybot_live_real.json # 钱包候选列表 https://code.aifunny.ltd/gavindiaz/winning-wallet-finder/raw/branch/main/live/watch_sharps.json ``` > 但 raw JSON 不好看,建议还是用 dashboard(`http://45.207.206.36:18080/`)。 ### ⚠️ 注意:本地 Clash 会拦截直连 IP 如果你本地开了 Clash Verge 系统代理,访问 `http://45.207.206.36:18080/` 可能被拦截(Clash 把直连 IP 也走了代理)。解决方法: 1. **关掉 Clash 系统代理**(最简单) 2. 或在 Clash 规则里加 `IP-CIDR,45.207.206.36/32,DIRECT`(让这个 IP 直连不走代理) --- ## 你日常改东西去哪改 | 想改什么 | 改哪个文件 | 在哪 | | --------------------------- | ------------------------------------------ | ----------------------------- | | 跟哪些钱包 / 金额 | `copybot.paper.json` 或 `config.live.json` | `/opt/winning-wallet-finder/` | | 私钥 / 代理地址 / 确认短语 | `live.env` | `/etc/copybot/` | | Alchemy RPC | `paper.env` | `/etc/copybot/` | | bot 程序参数(poll 间隔等) | `.service` 文件 | `/etc/systemd/system/` | | 代理节点 / 订阅 | `config.yaml` | `/etc/mihomo/` | | 每日 cron 时间 | `crontab -e` | 系统 | | dashboard 端口 | `.service` 文件加 `Environment="PORT=xxx"` | `/etc/systemd/system/` | 改完任何东西记得 `systemctl restart 对应服务`。