前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。
本稿は、暗号資産マーケット‐メイカー Bot(以下 MMBot)を Docker 環境で運用する際に遭遇した 「ログが出ない/接続箇所が特定できない」 問題を、最短で切り分けるまでの開発メモを整理したものです。
売買ロジックや実運用パラメータは伏せ、公開してもエッジを損なわない範囲の“開発ノウハウ”だけを共有します。
環境依存の落とし穴と対策
| 症状 | 原因 | 一発解決テクニック | 
|---|---|---|
| DEBUG が標準出力に出ず、Docker logs が空 | loguru のデフォルトレベル=INFO | logger.add(lambda m: print(m, end="", flush=True), level="DEBUG")✓ レベル昇格 ✓ バッファ即 flush | 
| grep では見えるはずの文字列がヒットしない | JSON シリアライズで改行が崩れる | まず 生ログ を見る → 必要なら jq -r '.message'で整形 | 
| WS ストリームが沈黙 | Subscribe 失敗 or 心拍欠如 | before/after ws_connectマーカー → 詰まり位置を 0.5 秒で特定 | 
段階的な接続ヘルスチェック
① REST : ping instruments-info → OK? ② get_minQty: DBG before / after → 数値取得? ③ WS connect: DBG before / after → ハンドシェイク通過? ④ orderbook : HDLR ERR 例外ログ → パース成功?
REST → WS → パーサ の順に「パイプの詰まり」を潰すと、再現性のあるデバッグ手順になります。
計測用 METRIC 行の設計
10 秒間隔で 運用に直結しない抽象値 だけを残すことで、安全に統計が取れます。
METRIC spr_pct=<%> spr_ticks=<tick差> notional=<USD> loop_ms=<ms>
- パラメータ (<%>,<USD>) は範囲化 or 正規化して保存
- loop_msでボトルネック(DB I/O や API レイテンシ)を即検知
開発ログから得た学び — 2 時間のタイムライン
| 時刻 | アクション | 学び | 
|---|---|---|
| T+0 min | Docker イメージ再構築 → mainnet へデプロイ | まずは現象再現 | 
| +10 min | REST 疎通テスト(aiohttp 5 s timeout) | 外形監視を最小実装しておくと安心 | 
| +15 min | DBG マーカーを 2 か所挿入 | レイヤごとに “光を当てる” | 
| +25 min | HDLR 例外捕捉 → メッセージ構造を確認 | 仕様変更耐性アップ | 
| +30 min | stdout シンクを DEBUG + flush | ログが「出ない」原因は大抵これ | 
| +35 min | METRIC 行でループ遅延を可視化 | 調整に必要なデータ構造が完成 | 
今後の改善 TODO
| 項目 | 狙い | 
|---|---|
| 24 h ログ収集 → ヒートマップ | spread × fill の実測から 適切なしきい値 を導出 | 
| max_cycles = 0 | 長期計測モードへの切替え | 
| Watchdog + Slack 死活通知 | 稼働中断を 1 分以内に検知 | 
| CI に log-lint | level="DEBUG"やflush=Trueの抜けを自動チェック | 
おわりに
今回のアップデートで 実行パイプラインの見える化 と 計測フレーム が整備されました。これにより、次フェーズの パラメータ最適化 を 「勘」ではなくデータドリブン で進められます。
同じ問題に悩む開発者の参考になれば幸いです。
👇ラジオで話したこと
きょうは 「MMBotを“静かに”24 時間まわすためのデバッグ&リアルタイム計測テク」 がテーマです。ポイントは ①.env→tpl→json の安全な設定パイプライン、②Makefile 1行で Mainnet/Testnet を切り替える運用フロー、③Loguru で WARN だけ を抽出して tail 監視するログ設計、④スプレッドが狭い市場では「Fill 0 = 成功」と腹をくくるリスク管理、の 4 本柱です。
1. なぜ「静かな 24 h 監視」が必要?
- Mainnet 最小ロット(0.0001 BTC)でまず 1 bps だけ差し込むと、板が詰まっている日は 注文が一度も約定しない ことがあります。
- しかしこの “Fill 0” は 損しない という意味で成功シナリオ。— 市場が開くまで待てる「我慢強さ」を Bot 側で担保しておくわけです。 SQL Easy
2. .env → tpl → json の安全パイプライン
- .env.prodに API キーやロットサイズを保存。
- config_mainnet.tplに- ${BYBIT_KEY_MAIN}のようなプレースホルダを書く。
- Makefile で
envsubst < config_mainnet.tpl > config_mainnet.json
 — envsubst はシェル組込みではなく GNU gettext に付属するコマンドで、環境変数を一括展開します。 Stack Overflow
4. 生成後はすぐ .gitignore に入っているか確認し、rm -f で掃除。
3. Makefile ワンライナー運用
ENV ?= .env.test # “?=” は「未定義なら代入」の意 run: $(CONFIG) set -a && source $(ENV) && set +a && \ docker compose run --rm --entrypoint "" $(SERVICE) \ python -m MMbotbybit.MMbotbybit \ --lot $(LOT) --max_loss_usd $(LOSS)
- set -a(セット・ハイフン・エー) は 「読み込んだ変数をすべて export」 の意味。 Stack Overflow
- ENV=.env.prod make runと打てば 後勝ち ルールで- .env.prodが優先されます。
4. Loguru で WARN だけを追う
logger.add("logs/warn.log",
           level="WARNING",
           rotation="10 MB",
           enqueue=True)
logger.add(lambda m: print(m, end="", flush=True), level="DEBUG")
- flush=Trueを付けないと DEBUG が バッファに溜まって Docker logs に流れません。 LoguruReal Python
- 端末では tail -F logs/warn.log。-Fは “ファイル名の切替えも追従” の略なので、ローテーション後も自動で追い続けます。 prefetch.net
5. リアルタイム計測用 METRIC 行
METRIC spr_pct=0.12 spr_ticks=3 notional=24 loop_ms=87
- 10 秒おきに “抽象値” だけを残し、個別約定情報は書かないので流出リスクが低い。
- loop_msが 500 ms を超えたら DB I/O やネット遅延を疑う。ログ設計の基本は「まず可視化,後で最適化」 です。 Better Stack
6. 24 h ランで詰まったポイント & 直し方
| つまずき | 原因 | 即 fix | 
|---|---|---|
| ${…}が残る | .env.prod未定義 →envsubst空展開 | 変数を追加して再生成 | 
| JSONDecodeError | 数値を "50"とクオートしていた | 数値は裸の 50にする Stack Overflow | 
| TypeError: '>' not supported | env が文字列で渡る | float(cfg["max_notional"])でキャスト | 
| Fill が来ない | スプレッドが 0.1 bps と狭い | curlで板を取得し S_ENTRY を再調整 Bybit Exchange | 
7. 今日の学び
- “何もしない” もテスト — スプレッドが狭い日はマッチしないのが正解。
- ログレベル分離 は tail × flush で 90 % 片付く。
- 環境変数を数字にする と JSON 生成エラーが減る。
- 小さいコミットを刻む と git revertで 10 分ロールバックが可能。 Stack Overflow
一言用語解説
| 用語 | 読み⽅ | ひと言で何? | ざっくり解説 | 
|---|---|---|---|
| GNU | 「グヌー」 | “自由ソフト”の旗印 | GNU = “GNU’s Not Unix” の再帰略語。Linux カーネルと組み合せて OS が完成。 | 
| プレースホルダ | – | 「あとで値を入れる空席」 | 例: %sや${S_ENTRY}。実行時に実データと置換される。 | 
| 後勝ちルール | 「あとがち」 | 同じ変数を後で再定義すると後が優先 | Makefile・シェルとも共通。 .env→ コマンド行上書きが代表例。 | 
| flush=True | 「フラッシュ トゥルー」 | ログを“即書き出し”モード | バッファを溜めずに標準出力へ強制送信。Docker logs が欠ける問題を解消。 | 
| METRIC 行 | 「メトリック」 | 統計用の専用ログ行 | METRIC spr=0.05 lot=0.001のような計測データだけを 10 秒ごとに吐く仕組み。 | 
| 抽象値 | 「ちゅうしょうち」 | “直接バレても困らない加工値” | 例:実残高でなく 正規化 した 0 〜 1 の値をログへ。安全に共有・統計できる。 | 
| I/O / DB I/O | 「アイオー」 | 入出⼒/データベース操作 | CPU ではなくディスク・ネットの遅延がボトルネックか判断するときに計測。 | 
| ${VAR} | 「ダラー ブイエーアール」 | bash の変数展開 | envsubstでテンプレを実値に差し替える記法。 | 
| クオートする | 「クオート」 | 文字列を ' 'や"で囲む | 数値をクオートすると JSONDecodeError の原因になるので要注意。 | 
| curl | 「カール」 | HTTP を叩くコマンド | `curl -s | 
| tail -F | 「テイル エフ」 | “ファイルを追尾+切替え検知” | ログローテでファイル名が変わってもストリームが途切れない。 | 
| tail × flush | – | tail -F + flush=True の合わせ技 | 出し忘れ&読めないを同時に無くす王道セット。 | 
| JSON 生成エラー | – | JSONDecodeError/ValueError | ほぼ「数値をクオートした」「カンマ抜け」の 2 大原因。 | 
| git revert | 「ギット リバート」 | 特定コミット を“打ち消す”新コミット | 安全な巻き戻し。 git revert HEAD~1で 1 つ前を取り消し ⇒ 10 分ロールバック など即時復旧に使う。 | 
最後まで聞いてくださってありがとうございました。
それではまた次回の放送でお会いしましょう。よだかでした。
