ペーパーストラテジーを取引の途中で再起動したところ、再起動前とは異なる注文の流れになりました。市場データも、ストラテジーのバージョンも、口座残高も同じです。シグナルの計算結果も一致していました。違っていたのは、ポジションと未約定注文についてのストラテジーの記憶でした。
1日のリプレイ作業を通じて、この食い違いを追跡しました。得られた教訓はシンプルです。ソフトウェアにとって、再起動は市場イベントのようなものです。ストラテジーが状態をどう復元するかをテストしなければ、きれいなバックテストの陰で、保有状況を忘れてしまうペーパーシステムを見逃すことがあります。
09:10 — あえて地味なポジションを選ぶ
テスト用ストラテジーでは、流動性の高いパーペチュアルを取引しました。短期移動平均が長期移動平均を上抜けたらロングで入り、逆クロスで決済します。リプレイは、小さなポジションを保有し、その一部を減らす reduce-only 指値注文が出ている状態から始めました。これにより、復旧時に再構築すべき情報が2つできました。何を保有しているか、そして取引所にどの注文をすでに依頼しているかです。
チェックポイント時点で、口座は0.04コントラクトを保有していました。0.01の注文が未約定でした。ストラテジーのプロセスは両方の値をメモリにキャッシュしていましたが、起動時にはポジションしか取得していませんでした。キャッシュされていた注文は消えたものとして扱われました。
09:25 — 最初の重複注文が発生
再起動後、ストラテジーは既存のロングポジションを確認し、シグナル処理を実行して、さらに0.01の縮小注文を送信しました。ペーパー取引所には、2件の有効な注文が並びました。どちらも単独では問題のない注文です。しかし両方が約定すれば、意図した量の2倍を売ることになります。
最初はシグナルのループを疑いました。問題はループではなく、不完全なスナップショットにありました。ストラテジーは「どのポジションを持っているか」は確認しても、「どの注文がまだ有効か」は確認していなかったのです。
| 再起動後の状態 | プロセスが認識していた状態 | 口座の実際の状態 |
|---|---|---|
| ポジション | ロング 0.04 | ロング 0.04 |
| 未約定の縮小注文 | なし | 0.01の注文が2件 |
| 1件約定した後の想定エクスポージャー | ロング 0.03 | ロング 0.02になる可能性 |
10:00 — 復旧を直したら、今度はタイミングのずれが見つかった
新たな判断を有効にする前に、口座のポジションと未約定注文から状態を再構築するよう、起動処理を変更しました。これで重複注文は解消しました。次に、切断時の条件を少し複雑にしました。ストラテジーがオフラインの間に注文が約定し、その約定通知が再接続後に届くケースです。
口座スナップショットには、すでに約定が反映されていました。そこへ遅れて届いた通知を適用したため、ローカルのポジションがもう一度減りました。数秒間、口座は0.03を保有しているのに、ストラテジーは0.02だと思い込んでいました。次のリバランスは、実際には存在しない不足分をもとに行われるところでした。
そこで照合ルールを追加しました。口座スナップショットを初期状態として扱い、イベントIDを使って、すでにスナップショットに反映済みの約定を無視します。また、初回同期が終わるまでは注文を送信しないようにしました。通知は遅れて届くことも、二重に届くこともあります。復旧処理は、どちらにも対応できなければなりません。
13:40 — リプレイで見つかった、目立たない食い違い
元の実行と再起動後の実行で、同じ価格推移をリプレイしました。最終損益だけを比べていたら、問題を見逃していたでしょう。市場が反転した後、どちらも同じポジションで終わっていたからです。注文イベントを比較したことで、食い違いが明らかになりました。
ポジション、未約定注文、最後に処理した約定ID、シグナル値、ストラテジーのバージョンなど、各判断で参照した状態を記録しました。すると、最初に分岐したイベントの理由がわかりました。一方の実行では有効な注文が見えていたのに、もう一方では注文リストが空でした。その後、一方の実行では約定が2回適用されていました。
最終残高が一致していても、動作が一致した証拠にはなりません。判断と注文の流れを比較し、とくに復旧の前後を確認しましょう。
16:20 — 次回はこう進めたい
口座の状態遷移を確認する前に、価格データのリプレイに時間をかけすぎていました。次回はまず障害ケースを注入し、市場の値動きはほぼ横ばいに保ちます。そうすれば、値動きに診断を惑わされず、ソフトウェアの問題を簡単に見つけられます。
- ポジションと一部約定済みの注文がある状態で再起動する。
- 注文送信後に切断し、約定通知が届く前に再接続する。
- 同じ約定イベントを2回届け、状態が1回だけ変わることを確認する。
- ポジションと未約定注文の両方の照合が終わるまで、新規注文を止める。
- 中断なしの実行と再起動後の実行で、判断ログと注文ログを比較する。
さらに、ストラテジーのバージョンとイベントログに加えて、復旧時のスナップショットも保存するようにしました。これにより、正確な再接続の順序を誰かが覚えていることに頼らず、数分で障害を再現できました。
プロセスが動いている間だけ正しく振る舞うペーパーストラテジーは、十分なリハーサルを終えたとは言えません。ポジション保有中に再起動し、約定を遅れて届かせ、その後に送る注文をすべて確認してください。目指すのは、絶対に失敗しないと証明することではありません。ペーパー口座に不意打ちで同じ教訓を突きつけられる前に、復旧の動きを見えるようにすることです。
← 記事一覧


