前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。
**この記事は “自宅 PC × Docker Compose × Python‐bot” を初めて回し始めたときに私が **“ハマって → 抜け出した” トラブル集 です。
同じ所ではまった未来の自分&読者さんのために、
- 何が起きた?(症状)
- なぜ?(原因)
- どう直した?(応急処置)
- 次は迷わないコツ(再発防止)
をまとめました。
※ API キーや Slack URL など “秘密情報” は すべて伏せ字 にしてあります。
1. config_mainnet.json
が「フォルダ扱い」になって読めない
内容 | |
---|---|
症状 | コンテナ内で cat /app/config_mainnet.json → Is a directory と怒られる |
原因 | ホスト側に 同じ名前のディレクトリ を作ってしまい、 Docker が “ディレクトリ over ファイル” でマウントした |
応急処置 | bash mv config_mainnet.json config_mainnet_backup_dir → 改めて JSON ファイルを作成 |
もう迷わない | コマンドを習慣に:ls -ld config_mainnet.json → 先頭が -rw ならファイル、drw ならフォルダ |
2. --profile
オプションが効かない
内容 | |
---|---|
症状 | unknown flag: --profile |
原因 | Docker Compose v2 はdocker compose --profile live up -d の順番じゃないと読んでくれない |
応急処置 | コマンドを並び替え |
もう迷わない | bash alias dcu='docker compose --profile live up -d' |
3. ソースを書き換えても古いコードが動く(.pyc
の罠)
内容 | |
---|---|
症状 | 直したはずのバグがコンテナ内で再現… |
原因 | Python は先に .pyc を読む。タイムスタンプが古いと新ファイルを無視することも |
応急処置 | bash find . -name '*.pyc' -delete touch *.py で更新時間を前に出す |
もう迷わない | 開発中は環境変数 PYTHONDONTWRITEBYTECODE=1 に。.dockerignore に __pycache__/ を追加 |
4. from __future__ import annotations
なのに SyntaxError
内容 | |
---|---|
症状 | 「future import はファイル冒頭に置け」と怒られる |
原因 | #!/usr/bin/env… と docstring の さらに後ろ に書いていた |
応急処置 | docstring の直後 に移動 |
もう迷わない | VS Code / PyCharm の Linter を有効化(位置ズレで即警告) |
5. envsubst
で作るはずの設定ファイルが空
内容 | |
---|---|
症状 | /app/config_mainnet.json が 0 byte |
原因 | 同じパスを volume マウントすると、 生成された直後にホストの空ファイルで上書き |
応急処置 | テンプレートは /tmp/config.tpl として 読み取り専用 でマウントし、entrypoint で /app/config_mainnet.json を生成 |
黄金パターン | ```yaml |
volumes: | ./config.tpl:/run/config.tpl:ro entrypoint: > /bin/sh -c " envsubst < /run/config.tpl > /app/config_mainnet.json && exec python … "``` | |
6. Bybit エラー retCode 110007 (InsufficientAB)
内容 | |
---|---|
症状 | 注文が弾かれ “証拠金不足” メッセージ |
原因 | MAX_NOTIONAL_USD を超えるロット/レバが低すぎ |
応急処置 | ロットを半分 (0.0005 ) にし、環境変数 DEFAULT_LEVERAGE=10 を設定 |
もう迷わない | 注文前に “余力 API” を叩いてログ出力 → 門前払い するコードを仕込む |
7. Slack 通知が毎回 “Cancel” になる
内容 | |
---|---|
症状 | 取引所では約定しているのに Slack では全部 Cancel |
原因 | 約定チェックを Order List REST でポーリング。 実際の Fill は Execution WebSocket で流れてくる |
応急処置 | 現在 WS 版に書き換え中(TODO) |
もう迷わない | 原則: 「口座残高が動くイベント=WebSocketで即時検知」 |
迷ったら使う“5 ステップ”デバッグ
- 1.症状の種類をラベル付け(ビルド?ランタイム?API?)
- 2.最小再現を 1 コマンドに↓
docker compose exec mmbot python - <<'PY' # 20 行以下で症状を再現 PY
- 3.ログを絞る
docker compose logs -f mmbot | grep -E 'ERROR|retCode'
- 4.ホストとコンテナの差分を疑う
docker compose exec mmbot env | sort | head docker inspect mmbot-mmbot-1 --format '{{ json .Mounts }}'
- 5.1 問題 = 1 コミット / 1 メモ
Notion や Git の PR に “現象→原因→Fix” を残すと未来の自分が助かる
そもそもトラブルを減らす仕掛け
仕組み | 何が嬉しい? |
---|---|
CI で docker build && pytest | 変な import や空 JSON をプッシュ前に検知 |
.dockerignore を整理 | 古い .pyc や .env がイメージに混入しない |
Secrets Manager or .env ファイル | API キーをシェル履歴に残さない |
Makefile / bash alias | make up , make logs でタイプ量 1/3 |
Runbook | 「110007 が出たら余力チェック」など 判断を手順化 |
次の To Do
- Execution WS で約定検知 → Slack 完全同期
- DB に正しく保存 → PnL 計算ロジックをテスト
- パラメータ (lot / s_entry) チューニング
- GitHub Actions で CI 設定 → “壊しても怖くない” フローへ
このサイクルを回せば、ほとんどのトラブルは 「仕組みで未然防止 or 1 コマンドで再現&修正」 できるようになります。
それでは楽しい自動売買ライフを!🚀
👇ラジオで話したこと
MMBot開発ログ13|Docker MMBotが動くまでにハマった7つの落とし穴と抜け道
こんにちは、よだかです。
今回は、自分がDocker上でMMBotを初めて回したときにぶつかった
**「7つのトラブルと、それをどう乗り越えたか」**をまとめてお届けします。
どれも初心者が最初の一歩で引っかかりやすい落とし穴ばかり。
将来の自分や、これからBot開発に入る方へのメモとしても残しておきたい内容です。
1️⃣ config_mainnet.json が「フォルダ扱い」になった
症状
Dockerの中で cat config_mainnet.json
を実行したら
「Is a directory」って怒られる
原因
ホスト側で config_mainnet.json/
というフォルダを作ってしまっていた。
Dockerはファイルとディレクトリが同じ名前なら、ディレクトリを優先してマウントしてしまう仕様です。
抜け道
ディレクトリを退避して、ちゃんとした .json
ファイルを作り直す。
再発防止のコツ
ls -ld config_mainnet.json
で事前に確認:先頭が -rw
ならファイル、drw
ならフォルダ。
2️⃣ --profile
オプションが効かない
症状docker compose --profile live up -d
を打ったのに「unknown flag」と出る。
原因
Compose v2では --profile
の位置がコマンドの途中にあると無効。
正解はコレ:
docker compose --profile live up -d
抜け道
間違えないようにエイリアスを登録:
alias dcu='docker compose --profile live up -d'
3️⃣ ソースを書き換えても反映されない(.pycの罠)
症状
修正したはずのバグが、Dockerコンテナ内で再現され続ける。
原因
Pythonは .pyc
という中間ファイルを自動で読み込む。
古い.pycファイルが残っていると、ソース変更が無視されることがある。
対処法
find . -name '*.pyc' -delete touch *.py
予防策
.dockerignore
に__pycache__/
を追加- 環境変数で
.pyc
を書かせない:
PYTHONDONTWRITEBYTECODE=1
4️⃣ future import の位置エラー
症状from __future__ import annotations
を書いたら、SyntaxError が出た
原因
この行はファイルの先頭じゃないとダメ。
私は #!/usr/bin/env python
や docstring の後ろに書いていた。
抜け道"""モジュール説明"""
の直後、すぐに future import を書く。
コツ
VSCodeやPyCharmの**Linter(構文チェッカー)**をONにしておくと、
この位置ズレも即座に警告してくれる。
5️⃣ envsubst で作る設定ファイルが 0 バイト
症状
Bot起動時に /app/config_mainnet.json
を作るはずが、空っぽ(0バイト)。
原因
ホスト側と同じパスをvolumeでマウント → マウント元が空ファイルだと、生成した内容が上書きされて消える。
抜け道
テンプレートは /run/config.tpl
にしてreadonlyでマウントし、
起動時に envsubst
で /app/config_mainnet.json
を生成。
volumes: ./config.tpl:/run/config.tpl:ro entrypoint: > /bin/sh -c " envsubst < /run/config.tpl > /app/config_mainnet.json && exec python … "
6️⃣ retCode 110007:証拠金不足エラー
症状
注文が通らず「InsufficientAB」というエラーが返る。
原因
- レバレッジが低すぎた
- ロットが
MAX_NOTIONAL_USD
を超えていた
抜け道
- ロットを0.0005 BTCに下げる
- 環境変数でレバレッジを10倍に:
DEFAULT_LEVERAGE=10
再発防止
発注前に「余力チェックAPI」を叩くようにコードを修正。
7️⃣ Slack 通知が全部 Cancel 扱い
症状
Slack通知が全部「Cancel」になるのに、実際は約定していた。
原因
Botは /order/list
をポーリングして約定を見ていたが、
本物のFillはExecution WebSocket(WS)からしか来なかった
対応中
現在、約定検知をREST → WebSocketに切り替え中。
原則として覚えること:
「口座残高が変わるような重要イベントは、WebSocketでリアルタイム検知するのが基本」
💡 迷ったら使う「5ステップ」デバッグ術
- 症状にラベルをつける(ビルド?ランタイム?API?)
- 最小再現コードを1コマンドにする
- ログを絞る(
docker compose logs -f mmbot | grep 'ERROR|retCode'
) - ホスト/コンテナの差分をチェック(
env
やdocker inspect
) - 1問題=1コミット/1メモ(NotionやPRに記録)
🛡️ トラブルを減らす“仕掛け”たち
仕組み | 効果 |
---|---|
CIで docker build && pytest | プッシュ前に構文&動作チェック |
.dockerignore の整理 | ゴミファイル混入を防止 |
.env やSecrets Managerの使い分け | 鍵の流出防止 |
Makefile/alias | コマンド入力を1/3に短縮 |
Runbook | 「110007が出たらどうする?」を手順化 |
✅ 次のTo Do
- Execution WebSocketでfill検知 → Slack連携完成
- DBにfill保存 → PnL計算ロジックをテスト
- パラメータ(lot / s_entry)を調整
- GitHub ActionsにCIフロー導入
→ 壊しても怖くない開発体制へ!
🎙️おまけコーナー:
「今回出てきたけど、ちょっと気になった言葉たちをまとめて解説します」
🎤さて、ここからはおまけコーナー。
今回の開発ログで出てきた用語の中から、初心者の方にとって “ここちょっとわかりにくそうだな” というものを、ひとつずつ解説していきますね。
✅ ホスト側(ほすとがわ)
これは「Botを動かすマシン側のこと」。
Dockerの場合、コンテナの外にあるPCやMacのことを“ホスト”って呼びます。
つまり「自分のパソコン上で動いてるDockerの親」です。
✅ ls -ld config_mainnet.json
これは config_mainnet.json
が「ファイルなのか、フォルダなのか」を調べるコマンドです。
ls
:ファイルを見る-l
:詳細表示(パーミッションとか)-d
:ディレクトリをそのまま表示(中に入らず)
✅ -rw
とdrw
の違い
-rw
は「普通のファイル」-
:これはファイルrw
:読み書き可能
drw
は「ディレクトリ(フォルダ)」d
:これはディレクトリrw
:読み書き可能
最初の文字だけ見れば、
ファイルかフォルダか一発で分かります。
✅ docker compose --profile live up -d
の「-d
」
これは **--detach
の略で「バックグラウンドで起動」**という意味です。
つまり、
画面にログを出しっぱなしにせず、
後ろでこっそりBotを動かしてくれるオプションです。
✅ エイリアス(alias)
長いコマンドに、短いニックネームをつける仕組みです。
例えば:
alias dcu='docker compose --profile live up -d'
って書けば、
次回からは dcu
と打つだけで、長いコマンドを一発で呼び出せます。
✅ PYTHONDONTWRITEBYTECODE=1
読み:パイソンドントライトバイトコード=ワン
意味:**「.pyc
ファイルを作るな」**という指示です。
開発中に不要なキャッシュが増えないように、
この環境変数をセットしておくと安心です。
✅ .pyc
と__pycache__
.pyc
は「Pythonの中間ファイル」。
→ 実行速度を上げるために、自動で作られることがあります。__pycache__/
はその.pyc
を保存しておく専用のフォルダです。
開発中は古い .pyc
がバグの原因になりやすいので、削除することも多いです。
✅ from __future__ import annotations
これはPythonの「将来の機能を先取りして使いたい」という宣言文です。
ただし、この文だけは
ファイルの一番上に書かないとエラーになる
というルールがあるので注意が必要です。
✅ volumeでマウント
「ホストのファイルやフォルダをDockerコンテナの中に共有する方法」のことをボリュームマウントといいます。
たとえば:
./config.tpl:/run/config.tpl:ro
という書き方をすれば、
**自分のパソコンのconfig.tpl
**を、Dockerの中の/run/
に持ち込むという意味になります。
✅ readonlyでマウント(:ro
)
これは上のボリュームマウントに付けるオプションで、
:ro
=read-only=読み取り専用- コンテナの中からは、そのファイルを書き換えできなくなります。
事故防止にめちゃくちゃ役立ちます。
✅ envsubst(エンブサブ)
環境変数を埋め込んだテンプレートから、実際の設定ファイルを生成するコマンドです。
config.tpl
みたいなテンプレートに ${API_KEY}
と書いておいて、
それを envsubst
に通すと、
今の環境変数の値を埋め込んで .json
などに変換してくれます。
✅ 「余力チェックAPI」を叩く
Botが注文を出す前に、
**「いまの口座でちゃんと買える? 証拠金足りてる?」**という情報を取得するAPIを叩くこと。
これをやらないと、
発注エラーが起きたときに理由がわからず迷子になります。
✅ 約定検知を REST → WebSocket に切り替え
- REST API:定期的に「何か起きた?」って聞きに行く方式(Pull型)
- WebSocket:相手から「今これ起きたよ!」ってリアルタイム通知が来る方式(Push型)
Botは注文の約定(fill)を即座に検知したいので、
WebSocketを使う方がベストです。
✅ Runbook(ランブック)
「このエラーが出たら、こう直す」っていう手順書です。
- 例:
110007
が出たら → ロットを下げて余力を確認 - 一度書いておけば、次に同じことが起きたときに即対処できるので便利です。
✅ GitHub Actions
これは GitHubが提供するCI/CD(自動実行)サービス。
- コードを push したら
- 自動で
docker build
やpytest
を動かして - 「壊れてないか?」をチェックしてくれる
まさに “小さなロボットエンジニア” みたいな存在です。
✅ CI(シーアイ)
正式には Continuous Integration(継続的インテグレーション)。
「コードを変更したら、すぐに自動でテストして、バグを早期に検出する仕組み」のことです。
GitHub Actionsなどのツールを使って、CIを自分のプロジェクトに導入できます。
ということで、おまけコーナーでした!
“あれ何だったっけ?”を全部ここで消化できていたらうれしいです。
このへん理解しておくと、トラブルにも強くなれるので、時間あるときにちょっとずつ復習してみてくださいね。
🏁 エンディング
今回の開発ログは、Botが動くまでのリアルなつまずきと回復の記録でした。
トラブルは防げないけど、
仕組みで未然に防ぐ or 1コマンドで再現して直せる状態にしておく、
これが次のステージに進む鍵になります。
あなたのBotも、最初のつまずきを経て強くなる。
良き開発と、トラブルを恐れない成長を!
また次回お会いしましょう!よだかでした。🎤