CEX(bitbank)で動かす新botを開発し始めたので、今日はそのサマリだけ載せます。
新bot、ようやく実装通った。署名のエンコーディング形式ミスでずっと詰まってたのか。取引所ごとの仕様差が原因だった。めちゃくちゃ初歩的なやつ。今回はBase64とhexの取り違えだった。なんでもやってみるもんだな。
後で取引所別のサイン・ヘッダ・時刻ルールをモジュール化しておくと良いかも。
— よだか(夜鷹/yodaka) (@yodakablog) August 25, 2025
スイングbot📒 開発ログのサマリ
✅ 解決までの道筋
- 初期症状
- どのAPIを叩いても
{"success":0,"data":{"code":20001}}
- HTTP 200 が返るため、通信自体は成功。認証だけ失敗。
- どのAPIを叩いても
- 初期仮説
- 環境変数に古いキーが残っていた → 解決してもエラー継続。
- 「Bitbank側のキー設定や口座状態では?」と早計に結論。
- 技術的切り分けの再実施
- サーバ側ではなく、クライアント実装差を徹底検証。
- 署名生成・nonce管理・ヘッダ名を1つずつ再点検。
- 核心の発見
- Rust実装では署名を Base64エンコードして送信していた。
- Bitbankが要求するのは hex文字列(64文字)。
- 修正
base64
→hex
に変換。- 即座にレスポンスが
{"success":1,"data":{"assets":[...]}}
に。
- 副次的課題
- 残高パース(文字列数値混在)
- OHLCV取得で404(クエリ形式の差)
→ 20001とは別系統の仕様対応へ移行。
スイングbot開発フローの改善点
1. 切り分け手順の明文化
- 20001のような「認証失敗」コードはサーバ・クライアント両面で出る。
- まずは 署名対象文字列・エンコード方式・ヘッダ名 をサンプルコードや公式ドキュメントと突き合わせる。
- 「Bitbank側に問題」と断定する前に、**クライアント側の再現テスト(最小コードでHMAC生成 → curl投げ)」を必ず実施する。
2. ゴールデンテスト導入
- 一度通った署名パターン(nonce, path, suffix, 署名結果hex)を固定ベクタにして単体テスト化。
- これによりリファクタや言語移植(Python→Rust)でも再発を防げる。
3. 取引所ごとの署名モジュール分離
- bitbank_signer, bybit_signer, binance_signer … と明示的に分ける。
- 各モジュールは「署名対象文字列の構成ルール」「エンコード方式」「ヘッダ名」を閉じ込める。
- 取引所追加時のリスクを最小化。
4. プリフライトチェックの標準化
- Bot起動時に必ず
/balance
や/time
を叩く。 - 成功 (
success:1
) しなければ 即起動中止+エラーログ(raw文字列、署名先頭16桁、レスポンス)。 - これで「20001状態のまま稼働して無仕事」は避けられる。
5. ログ・デバッグ用の出力強化
- 「nonce」「署名対象文字列」「署名結果(先頭16桁)」をデバッグログに常時出力できるオプションを追加。
- 実際のHTTPリクエストと突き合わせやすくする。
6. 言語移植時の注意
- 言語依存の落とし穴は「文字列処理・エンコード・JSON整形」。
- 実送信文字列をそのまま署名対象にするという意識を徹底。
- テスト時は Python と Rust で同じnonce/rawを与え、署名結果が一致するかクロスチェック。
🎯 改善後の標準フロー
- 仕様確認
- 公式Docs+既存実績コードを確認
- 署名アルゴリズム・対象文字列・エンコード方式を明文化
- 最小コードテスト
- Pythonやcurlで一発テスト
success:1
を確認してからBot実装へ反映
- ゴールデンベクタ登録
- nonce/path/suffix → 署名 → hex結果 を固定テスト化
- Bot実装
- 言語ごとのAPIクライアントに組み込み
- プリフライト実行
- 起動時に
/balance
で認証成功を確認
- 起動時に
- 本番稼働
- ログに署名・レスポンス概要を残す
✅ 最終まとめ
- 20001はクライアント実装差が原因(Base64 vs hex)。
- 開発フローの問題は「切り分けの順序」と「仕様をモジュール化・テスト化してなかったこと」。
- 改善策は:
- クライアント側要因を潰すチェックリスト化
- ゴールデンテスト導入
- 取引所ごとに署名モジュール化
- プリフライトチェック標準化