Bot mmnot 開発ログ

🛠️開発記録#236(2025/5/22)「CI×E2E完全モック化で高速安全チェック Day」

テストネット運用の安全性向上とPDCA高速化を狙い、MMBotのCIパイプラインにE2Eテストを組み込みました。今回はWebSocket/HTTP呼び出しを完全モック化し、「o4-mini」AI伴走開発を最大活用して、1分以内に全チェックが完走する環境を実現した流れをまとめます。


今回のゴール

  • CI上でE2Eを自動実行:Pull Request→Merge時に必ずE2Eが走るように
  • WebSocket&HTTP完全モック化:実API依存を排除し、安定・高速なテストを実現
  • ChatGPT(o4-mini)伴走:プロンプトドリブンで差分リファクタ&ワークフロー構築

技術スタックと前提

  • 言語・依存管理:Python 3.11 + Poetry
  • コンテナ管理:Docker Compose V2
  • CI/CD:GitHub Actions
  • 外部連携:Bybit Testnet API/Slack Webhook
  • AI伴走:ChatGPT o4-mini をモデル切り替えで活用

1. やったこと

カテゴリ作業内容効果
CI整備.github/workflows/e2e.yml に E2E ジョブ追加PR/Merge 時に自動で E2E が実行される
モック化環境変数 MOCK_STREAM で WS & HTTP をモック実 API 非依存で安定&高速テスト
スクリプトtests/e2e/testnet_checks.sh を A–H フェーズ対応にリファクタ手動確認フェーズを自動スキップ&フェーズ検証
Bot実装run_loop() にモック判定を追加し、ClientSession を動的生成モック/実運用を同一コードベースで兼用

2. コード抜粋

# src/mmbot/cli.py(抜粋)
MOCK_STREAM = os.getenv("MOCK_STREAM", "").lower() in ("1", "true", "yes")

async def run_loop(...):
    if MOCK_STREAM:
        logger.debug("MOCK_STREAM enabled: skipping real WebSocket connect")
        orderbook = {"bid": 100.0, "ask": 100.0}
        sess = aiohttp.ClientSession()
    else:
        async with pybotters.Client(base_url=ws_public) as ws, \
                   aiohttp.ClientSession() as sess:
            await ws.ws_connect(...)
            ...
# .github/workflows/e2e.yml(抜粋)
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker images
        run: docker compose build mmbot
      - name: Run E2E tests
        env:
          MOCK_STREAM: '1'                     # WS/HTTPをモック
          SLACK_ENABLE: 'true'
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_WEBHOOK_URL }}
        run: |
          chmod +x tests/e2e/testnet_checks.sh
          printf "\n" | ./tests/e2e/testnet_checks.sh

3. 結果と効果

  • 実行時間:1分以内に A–H 全 8 フェーズが完了(旧来5分→1分)
  • 安定性:テストネット本番相当のモックにより外部不安定要因を排除
  • 開発速度:AI伴走でスクリプト+CI設定を約30%短時間実装

4. 学び・改善ポイント

  • ClientSession のクローズ忘れ:短命実行向けでも明示的に await sess.close() を入れるとさらにクリーン
  • ユニットテスト強化MOCK_STREAM モードの振る舞いを pytest でカバーすると回帰防止に有効
  • ドキュメント追加:環境変数やモックフラグの説明を README に追記

5. 次の予定

  1. 実API接続版E2E の整備(Testnet Live チャネルで 24h 運転)
  2. Prometheus+Grafana で PnL/DD を可視化
  3. FastAPI+WebSocket ダッシュボードβ 公開
  4. Adaptive Spread EntryFunding Rate 管理 の v0.2 機能開発

付録:E2Eチェックフェーズ一覧

フェーズ内容
A手動確認(残高・サブアカウント制限)
BDD guard(損失0.01%で停止)
Cspread-skip(閾値以下は発注抑制)
DAPI error(Exception でも継続)
ESlack 404(通知失敗でも継続)
Fmax_cycles=3(3周で正常終了)
HDD auto-flat(大幅DD時に完全決済)

今回の合言葉
「モックで地盤を固め、CIで網を張り、次は空中戦へ」💪

以上が、CI×E2Eモック化による高速安全チェックの流れでした。次回もお楽しみに!

おまけ:懸念点・抜け漏れチェック

  1. ClientSession のクローズ漏れ
    • モック時は明示的に aiohttp.ClientSession() を作っているものの、await sess.close() を呼ばないとリソースリークにつながる可能性があります。
    • 本番モードでも例外パスでのセッションクローズが抜けるケースがないか要確認。
  2. WebSocket モックの挙動簡素化
    • モック時は板情報を固定値(bid=ask=100)でセットしていますが、実際の「板の変動」を再現していないため、スキップ/エントリー判断ロジックに偏りが出るかも。
    • モック用に簡易的な価格変動パターンを作っておくとより網羅的なテストになるでしょう。
  3. Slack 通知のモック限界
    • CIでは通知失敗を WARN ログで扱い続行していますが、実環境で頻発するとロストアラートの見落としリスクがあります。
    • 「通知待ち」「再試行ロジック」「エスカレーション手順」も別途ユニットテストしておくと安心です。
  4. 環境変数/ファイル参照の散在
    • .env.testnetMOCK_STREAM フラグを複数箇所で扱うため、新規環境構築時に設定漏れが起こりやすい状態。
    • 設定仕様を一箇所にまとめたドキュメント化や、起動チェックで必須項目を明示的にバリデートする仕組みがあるとミスを防げます。
  5. ユニットテストとの重複カバレッジ
    • E2Eで一連のフローを動かすテストはあるものの、個々の純関数(should_enterdd_warnなど)との組み合わせで“境界値”が抜けている可能性あり。
    • E2Eフェーズでは網羅できない細かいエラーケースをユニットテストで補完すると、品質がさらに向上します。
  6. CI 実行環境とローカル環境のギャップ
    • ローカルでは Docker for Mac を使い、CIでは Linux 上の Docker Compose V2。環境差異で微妙に動作が変わるケースも。
    • たとえばファイルパスの大文字・小文字、sed -i の挙動など、CI用に一度“真っ新”のクローンで動作確認しておくと安心です。
  7. 依存ライブラリのバージョン固定
    • pybottersaiohttp のメジャーアップデートで API 仕様が変わるリスクがあります。
    • Poetry の pyproject.toml で「~=」指定にとどめず、CIで依存関係の脆弱性スキャンや定期的なアップデートテストを組み込むとよいでしょう。

-Bot, mmnot, 開発ログ