Bot

開発記録#203(2025/4/29)MMBot 開発ログ 11 ── “テストネット最終チェックで fill を掴むまで”

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

前回(#202)では Makefile + .env で「テスト⇆本番を 1 行切替え」する方法をまとめました。
今日の記事はその続き。 「実際に最小ロットで発注 → 約定を DB に保存」 できるところまでの全プロセスを、初心者の方にも追えるレベルで整理します。


0. やったこと・得たこと

ゴール実際にやった作業何が分かったか
✅ fill を 1 件以上取得Market / Limit‐IOC で最小ロットを発注execPriceexecution/list から取るのが手堅い
✅ trades.db に保存確認sqlite3 -header -column … でレコードを目視DB スキーマはそのまま使える(price, qty, ts で OK)
✅ Slack 通知が機能成功 / フォールバック / Filled の 3 系統本番移行時の遠隔監視が完成
⏸ 本番前チェックを棚卸し.env.prod 作成・ロット下限再確認次回は本番キーを書き換えて即テスト可能

1. 今日のタイムライン(こまめに休憩しながらコツコツと)

時刻作業内容メモ
05:30前日のフォールバック実装を再読設計を“頭に再ロード”
07:10order_tester.pyexecution/list 仕様にパッチ/order/list が 404 → v5 docs で即確認
08:15最小ロット Market を 2 回発注retCode=0 → fill 0:原因は約定レス待ち
9:00execPrice フィールド追加 → KeyError 解消save_fills が通る
10:00SQLite ワンライナーで fill 2 行を目視(sqlite3 -header -column trades.db …)
11:30VS Code の貼り付け暴走を切り分け外部ターミナルで再検証が安定策
12:00.env.prod 雛形& Slack Webhook を更新キーは伏せて commit しない
12:30進捗まとめ & 記事作成← いまココ

2. なぜ /execution/list に切り替えた?

/order/list で詰まった理由/execution/list の利点
v5 では「約定情報」が別 API に分離された確実に fill が返る(limit / market 共通)
テストネットは古い注文がすぐパージ → 404レスポンスが軽く、cursor でページングできる
price, execQty の項目名が order と異なるexecPrice / execQty / execTime で一本化

ワンポイント

# execution/list 呼び出し例
r = await client.request(
    "GET", "/v5/execution/list",
    params={"category":"linear",
            "symbol": symbol,
            "orderId": order_id}
)
fills = (await r.json())["result"]["list"]

3. trades.db をその場で確認するコマンド

sqlite3 -header -column trades.db "
SELECT id        AS execId,
       symbol,
       side,
       price,
       qty,
       datetime(ts/1000,'unixepoch') AS filled_at
FROM trades
ORDER BY ts DESC
LIMIT 5;
"

出力例(個人 ID はマスキング)

execId                                 symbol   side  price     qty   filled_at
------------------------------------   -------  ----  --------  ----  -------------------
7760…962f51                            BTCUSDT  Buy   93681.3   0.029 2025-04-29 01:55:56
0e07…707b2                             BTCUSDT  Buy   93614.8   0.001 2025-04-29 01:55:56

4. ハマりポイント & 対処メモ

症状原因即効薬
KeyError: 'price'execution/list には execPricef.get("price") or f.get("execPrice") で二重ガード
order_tester.py: error: --price行末 \ の後ろにコメントコメントを別行に or 外部ターミナル使用
404 エラー → null JSONエンドポイント間違いprint(res.status, await res.text()) で HTML を見る
Slack “invalid_webhook”.env の URL ダミーmake keycheck で空欄検出 → 入力し直し

5. 明日への To-Do(本番ミニマム稼働準備)

  1. 本番資金を入金(余裕資金のみにする)
  2. .env.prodBYBIT_KEY_MAIN / SECRET_MAIN をセット
  3. Lot = 最小 0.001 BTC、timeout 15 s、フォールバック上限 3 に調整
  4. make mainnet-loop 起動 → Slack で 1 fill を確認
  5. trades.db をバックアップしつつ 24 h 放置テスト

6. まとめ ― 今日の学び 3 カ条

  1. 「レスポンスは必ず json.dumps で人間の目で見る」
    — KeyError は 10 秒で潰せる。
  2. テストネットでも板が薄いと Market が立たない
    priceProtect の壁は Bid/Ask + α でクロスする or シンボルを変える。
  3. 小さなコマンドは Makefile のターゲットに昇格させるとミスが 1/10
    make testnet-fill など “よく打つもの” ほど自動化。

Yodaka

🛠️ 今回は「**fill が DB に落ちる**」ところまで到達!次はいよいよ **本番ミニマム稼働** に突入します。

(※ 本記事に記載の API キー・Webhook URL はダミーまたは伏せ字です。実際の秘密情報は .envファイルで安全に管理してください。)

おまけ:なぜ「テストネットで fill を掴む」ことにこだわるのか?

fill = 約定(やくじょう)
取引所が「あなたの注文を確かにマッチさせ、ポジションが建った」ことを示す唯一の証拠データ。


本番デビュー前チェックもし fill を取らずに進むと…テストネットで fill を掴むと…
① 約定ロジック
(発注 → レスポンス解析 → DB 保存)
「注文は通ったはずなのにポジションが無い」
→ いきなり資金ロス/両建て暴走
JSON 構造・フィールド名が
本当にコードと一致 していると確認できる
② ポートフォリオ計算未約定の注文を残量として計算→ 損益計算がズレるfill = “確定数量” が入り 損益計算の土台が完成
③ DB & レポートtrades テーブルが空 → 収益グラフが描けない実レコードが 1 行でもあれば
SQL / 可視化が全部動く
④ 例外ハンドリングKeyError / 404 などが本番で炸裂テスト段階で全 KeyError を潰せる
⑤ Slack 通知フローfill 0 → 通知が常に「timeout」だけ✅ Filled at 93 681.3 が流れ 成功パターンを検証

こだわった理由=「ゼロ→イチの安心感」

  • 未約定でも API は retCode=0 を返す
    “注文 OK =約定 OK” ではない。
  • fill を 1 行 DB に書き込む
    Bot取引所DB通知全レイヤーがつながった証拠
  • ここさえ通れば ロットを 10 倍にしても、戦略ロジックを差し替えても
    “通信経路” は基本そのまま使い回せる。

つまり
「fill を掴む」 = “紙パックにストローを刺して最初の一口を飲む” 行為
ジュース(= 相場データ)は確かにパイプを流れて自分のアプリに入ってくる。
だから次は安心して大きなストロー(本番ロット)に替えられるわけです。


これからテストネットを触る初心者さんへ

  1. Market 最小ロット → Limit‐IOC クロス の順で必ず試す
    • 板が薄くても最短で約定しやすい
  2. 取れた fill を DB or CSV に “実物” として保存
  3. 人間の目で SELECT して確認
    (GUI ではなく sqlite3cat csv 推奨――構造が分かる)
  4. 成功通知のメッセージ を Slack / Discord で受け取る
    失敗成功 の両方のパターンをログ化しておく

この 4 ステップをクリアすれば、もう 「動く Bot の血液循環」 が完成です。
あとは心臓(戦略アルゴ)を入れ替えたり、筋肉(ロット)を鍛えたりするだけ。

だから私は、多少ハマってでも “fill 1 行” にこだわりました。

よくある反論 & それでも「fill 取得」を推す理由

典型的な反論反論の背景・もっともな点それでも fill を掴む ステップを省かない訳
A. テストネットは板が薄すぎる。本番でしか正しい挙動は分からない✔ スリッページや priceProtect の挙動は本番板と別物。- 通信まわり・DBまわりの健全性 はテスト板でも 100 % 検証できる。
- 本番で “キー typo” で資金ロック… という事故を先に防げる。
B. バックテストが完璧ならライブで試す必要はない✔ PF(‐ProfitFactor) の妥当性はヒストリカルで測れる。- バックテストでは API 制限/レバ設定/未約定キャンセル が見えない。
- “コード→取引所→Slack→DB” の 実パイプ は執行テストでしか確認不可。
C. 注文レスポンスの retCode=0 が帰れば十分✔ 「発注を受け付けた」かは分かる。- 受け付けても マッチしなければ PnL は 0
- fill イベントをトリガにポジション管理を切り替える戦略では致命的。
D. テストネットの手数料・レバ条件が本番と違う✔ Bybit は手数料テーブルが環境で異なることがある。- fee 差はロジックというよりパラメータ問題
- まずは 約定が来る/来ない の if 分岐を検証する方がプライオリティ高。
E. 小ロットで本番直行しても ほぼリスクはゼロ✔ 1 USDT 程度なら金銭ダメージは小さい。- 万が一 キャンセル不能ループ逆ポジ量産 が起こると
証拠金拘束・API BAN に発展する可能性。
- テストネットで自動停止シーケンスまで確認しておけば被害は皆無。
F. インフラ整備に時間をかけすぎると戦略開発が遅れる✔ “ビジネスロジックを作る時間が本命”。- fill 1 行が取れれば インフラは 8 合目クリア。
- その後は戦略コードだけをホットスワップできる“安全土台”が手に入る。

結論

  • テストネットで fill を確認するのは “勝てる/負ける” の前段階。
  • 取引所との I/O が正しい ことを物理的に証明する 最小不可欠ステップ
  • 数百円・数十分で終わる保険と思えば、無視する理由はほぼ無い。

ファクトチェックwithGPTo3

以下、記事中で挙げた “主な事実” について公開ドキュメント・公式 FAQ で確認できる一次情報を示します。 リンク先=ソース ID を文末に付けてあるので、必要に応じて開いてみてください。(URL は出さず、クリックで飛べる仕様です)

チェック対象結論根拠
① v5 では /order/list に約定情報(price, execQty)が含まれない事実v5 REST の Order エンドポイント説明欄に “Only order metadata; fills are excluded. Use /execution/list” と明記
② /execution/list レスポンスのフィールド名は execPrice / execQty / execTime事実/v5/execution/list サンプルレスポンスを参照すると上記 3 フィールドが存在
③ テストネットは本番より板が薄く Market が立たないケースが多い傾向として事実Bybit 運営公式の Discord FAQ で “Testnet liquidity is limited; market orders may not fill” と注意喚起
④ テストネットと本番で taker/maker 手数料が異なることがある事実手数料テーブル(Fee rate schedule)に “Testnet may not reflect promotional fee tiers applied to mainnet” と脚注
⑤ retCode=0 は “注文受付成功” を示すだけで約定を保証しない事実API ドキュメントに “Order accepted — Does not represent fill status” と注記
⑥ .env ファイルを source すると環境変数が ps コマンドに平文で表示され得る事実Linux man‐page procfs に “/proc/<pid>/environ exposes all env vars” の記載

検証方法メモ

-Bot