第 20 課:本番運用
目標:あなたがいなくてもシステムが正しく動作し、問題が発生したときに迅速に通知されるようにする。
典型的なシナリオ(例示)
注:以下は一般的な現象を説明するための架空の例です。数値は説明のためのものであり、特定の個人/アカウントに対応するものではありません。
2022年、あるクオンツトレーダーが6ヶ月間丹念に改良した自動取引システムをローンチしました。バックテストは完璧で、ペーパートレーディングは3ヶ月間安定して稼働しました。彼は自信を持って50万ドルを実取引に投入しました。
最初の2週間はシステムは正常に動作していました。3週目の月曜日、彼はテキストメッセージで起こされました:口座残高不足。
調査の結果、判明したこと:金曜日の取引終了後、データソースのAPIが更新され、戻り値の形式が変更されていました。システムは解析に失敗し、例外をスローしましたが、その例外は黙って飲み込まれました。週末の間、システムはログ出力がありませんでした(彼は週末は取引がないので気にしませんでした)。月曜日の開場時、システムは再接続しましたが、状態が混乱しており、一連の不合理な注文を実行し、大規模なショートポジションを含んでいました。
彼がそれに気づいたときには、口座は40%の損失を被っていました。
何が間違っていたのか?
- ヘルスチェックがない:データソースの障害が検出されなかった
- 例外が飲み込まれた:エラーが報告されなかった
- 監視アラートがない:2日間ログがゼロで誰も知らなかった
- Circuit Breakerがない:状態が異常なときに取引を停止しなかった
これが「コードが動く」と「システムが信頼できる」が2つの異なることである理由です。運用は後付けではなく、システム設計の一部です。
20.1 監視システム
監視の4つのレベル
主要な監視メトリクス
| レベル | メトリクス | 閾値の例 | アラートレベル |
|---|---|---|---|
| インフラストラクチャ | サーバーの生存 | ハートビートタイムアウト30秒 | Critical |
| ネットワークレイテンシ | >200ms | Warning | |
| サービス | CPU使用率 | >80% for 5分間 | Warning |
| メモリ使用率 | >90% | Critical | |
| ディスク容量 | < 10GB | Warning | |
| アプリケーション | データソース接続 | 切断 >1分 | Critical |
| API成功率 | < 95% | Warning | |
| タスクキューのバックログ | >100項目 | Warning | |
| Agentレスポンスレイテンシ | >5秒 | Warning | |
| ビジネス | 日次ドローダウン | >3% | Warning |
| 週次ドローダウン | >5% | Critical | |
| 異常取引 | 単一取引 >10%ポジション | Critical | |
| 取引頻度 | 平均から3倍の偏差 | Warning |
ヘルスチェック設計
20.2 ログシステム
ログのゴールデンルール
ログは製品であり、副産物ではない。
| 原則 | 説明 | アンチパターン |
|---|---|---|
| 構造化 | JSON形式で簡単にクエリと分析 | フリーテキスト「buy successful」 |
| トレース可能 | すべてのログにtrace_idが含まれる | 同じ取引のログを関連付けられない |
| レベル分け | DEBUG/INFO/WARN/ERROR | すべてprint()を使用 |
| コンテキスト | 時刻、シンボル、価格、数量を含む | ただ「Error occurred」 |
| 不変 | 書き込み後に変更できない | ログがローカルに保存され編集可能 |
ログレベル
| レベル | 使用法 | 例 |
|---|---|---|
| DEBUG | 開発デバッグ、本番では無効 | 「Calculating RSI for AAPL...」 |
| INFO | 正常なビジネスフロー | 「Order submitted: BUY AAPL 100@$180」 |
| WARN | 異常だが回復可能 | 「API rate limited, retrying in 5s」 |
| ERROR | 異常で注意が必要 | 「Order rejected: insufficient margin」 |
| CRITICAL | システムレベルの障害 | 「Database connection lost」 |
標準取引ログ形式
{
"timestamp": "2024-01-15T09:30:00.123Z",
"level": "INFO",
"service": "execution_agent",
"trace_id": "tx_20240115_001",
"event": "order_submitted",
"data": {
"symbol": "AAPL",
"side": "BUY",
"quantity": 100,
"price": 180.50,
"order_type": "LIMIT",
"order_id": "ORD_12345"
},
"context": {
"signal_id": "sig_20240115_001",
"signal_strength": 0.75,
"regime": "trending",
"portfolio_value": 1000000
}
}
キーフィールド:
trace_id:シグナルから実行までの完全なチェーンを接続event:統計分析のための標準化されたイベント名context:事後帰属のための意思決定根拠
20.3 アラートシステム
アラート設計原則
| 原則 | 説明 |
|---|---|
| アラートは実行可能でなければならない | アラートを受け取ったときに何をすべきか知っている |
| アラート疲労を避ける | アラートが多すぎる = アラートなし |
| 階層化された処理 | 異なるレベルは異なるチャネルを使用 |
| コンテキストを含む | アラート情報は問題を診断するのに十分 |
アラートチャネル
| レベル | チャネル | 応答時間要件 |
|---|---|---|
| Low | Email、日次サマリー | 翌日 |
| Medium | Slack/Teamsメッセージ | 1時間以内 |
| High | SMS + 電話 | 5分以内 |
| Critical | 自動Circuit Breaker + 電話 | 即座 |
アラートテンプレート
[CRITICAL] Trading Systemアラート
Time: 2024-01-15 10:30:15 EST
Service: Risk Agent
Event: Drawdownが管理ラインをトリガー
詳細:
- 現在のドローダウン: 10.2%
- トリガー閾値: 10%
- 今日のP&L: -$52,000
- 口座エクイティ: $948,000
実行されたアクション:
- 新規ポジションを停止
- デレバレッジングプロセスを開始
あなたがする必要があること:
- 異常取引をチェック
- 手動介入が必要かどうか確認
Dashboard: https://dashboard.example.com/alerts/12345
アラート抑制
| 問題 | 解決策 |
|---|---|
| 同じ問題の繰り返しアラート | 集約:同じタイプのアラートは5分ごとに1つのみ |
| 瞬間的なジッターがアラートをトリガー | 期間:閾値はN分持続しなければアラートにならない |
| 夜の非取引時間 | 静寂期間:非取引時間は低優先度にダウングレード |
| 既知のメンテナンスウィンドウ | 抑制:事前設定されたメンテナンス期間中はアラートなし |
20.4 災害復旧
障害分類
| 障害タイプ | 例 | 影響 | 復旧戦略 |
|---|---|---|---|
| データソース障害 | APIが利用不可 | 相場を取得できない | バックアップソースに切り替え |
| 取引インターフェース障害 | ブローカーのメンテナンス | 注文を出せない | 取引を一時停止、保留注文をログ |
| ローカルサービス障害 | Agentプロセスがクラッシュ | 部分的な機能喪失 | 自動再起動 |
| ネットワーク障害 | ネットワーク停止 | 完全な障害 | 復旧を待つ、手動で状態を検証 |
| データエラー | 異常な価格ジャンプ | 誤った意思決定 | 異常を検出、処理を一時停止 |
復旧フロー
状態一貫性チェック
復旧後に検証する必要があること:
| チェック項目 | 方法 | 不一致の処理 |
|---|---|---|
| ポジションの一貫性 | システム記録とブローカーを比較 | ブローカーを真実のソースとして使用、ローカルを更新 |
| 注文ステータス | すべての保留注文をクエリ | キャンセルまたは確認 |
| 現金残高 | 計算値と実際を比較 | 再計算 |
| データの完全性 | 欠落している市場データをチェック | 欠落データをバックフィル |
20.5 日次運用チェックリスト
市場前チェック(毎日必須)
市場時間の自動化
最も見落とされている信頼性要件の1つは、市場時間に関する自動化されたスケジューリングです。本番システムは、人間が毎朝システムを起動することを覚えていることに依存すべきではありません。
自動化スケジュール(US Equities、Eastern Time):
09:15 ET 自動起動:データ接続、ヘルスチェック、ポジション照合
09:25 ET 市場前検証:データフィードがライブであることを確認、リスクパラメータがロードされていることを確認
09:30 ET 市場開場:取引ロジックがアクティブ
15:50 ET 日終わり:新規ポジションエントリーを停止、クローズオンリーモードを開始
16:00 ET 市場閉場:最終ポジションスナップショット
16:05 ET 閉場後:P&L計算、ログ集約、アラートサマリー
16:30 ET 自動停止:非必須プロセスの優雅なシャットダウン
平日のみ:市場カレンダー認識を備えたcronまたはsystemdタイマーを使用。
休日をスキップ(Martin Luther King Day、Thanksgiving、など)。
これが重要な理由:手動起動を必要とするシステムは、日々のリスクとして人為的ミスを導入します。ボラティリティの高いオープン中に忘れた朝が、このレッスンの冒頭の物語で説明された種類の状態混乱災害を引き起こす可能性があります。ライフサイクルを自動化し、手動介入を例外として扱います。
市場後チェック(毎日必須)
週次/月次チェック
| 頻度 | チェック項目 | 目的 |
|---|---|---|
| 週次 | 戦略パフォーマンスレビュー | 異常なトレンドを特定 |
| システムリソース使用トレンド | リソース枯渇を防ぐ | |
| アラートサマリー分析 | システム的な問題を発見 | |
| 月次 | 完全なP&L帰属 | 戦略評価 |
| Model drift検出 | 失敗したシグナルを特定 | |
| インフラストラクチャ評価 | コストとパフォーマンスの最適化 | |
| 災害復旧訓練 | 復旧プロセスを検証 |
20.6 Provider抽象化
システムが成熟するにつれて、データプロバイダーを切り替えたり、実行会場を追加したり、複数のブローカーで実行したりすることは避けられません。コアロジックが特定のベンダーのAPIに密接に結合されている場合、各変更は書き直しになります。
解決策は、安定した契約の背後にベンダー固有の詳細を分離するクリーンなプロバイダーインターフェースです:
Data Provider Interface:
Connect(config) -> connection
Subscribe(symbols) -> stream
Stream() -> MarketDataEvent
Execution Venue Interface:
SubmitOrder(order) -> OrderAck
CancelOrder(id) -> CancelAck
GetPositions() -> []Position
各ベンダーは、このインターフェースを実装する薄いアダプターを取得します。Signal Agent、Risk Agent、Monitor Agentは、インターフェースの背後にどのブローカーやデータソースがあるかを知ることも気にすることもありません。このパターンは、マルチ会場取引、バックアップデータソースへのフェイルオーバー、モックプロバイダーを使用したクリーンなテストを可能にします - すべてコアロジックに触れることなく。
設計原則:すべての外部依存関係(データ、実行、アラート)をインターフェースの背後にある交換可能なモジュールとして扱います。最初のベンダー切り替えは、抽象化コストを何倍も回収します。
20.7 Model DeploymentとCI/CD
20.7.1 取引システムがCI/CDを必要とする理由
すべてのデプロイメントはリスクイベントです。CI/CDはこのリスクを制御可能にします。
従来のアプローチの問題:
| 問題 | 結果 |
|---|---|
| 手動デプロイメント | ステップを見逃しやすい、設定エラー |
| バージョン追跡なし | 問題が発生したときに既知の良いバージョンにロールバックできない |
| 一貫性のない環境 | 「私のマシンでは動作する」が本番では失敗 |
| 不十分なテスト | 新しいコードがバグを導入、デプロイ後にのみ発見 |
| Model更新記録なし | いつ、なぜModelが更新されたか分からない |
20.7.2 取引システムのCI/CD Pipeline
20.7.3 ステージの詳細
ステージ1:Build
# 例:GitHub Actions設定
build:
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install dependencies
run: pip install -r requirements.txt
- name: Type checking
run: mypy src/ --strict
- name: Code formatting
run: ruff check src/
- name: Package model
run: |
python -m src.models.package \
--model-path models/signal_v3.pkl \
--output artifacts/
ステージ2:Test
| テストタイプ | 内容 | 合格基準 |
|---|---|---|
| Unit tests | 関数ロジックが正しい | 100%合格 |
| Integration tests | Agent協力が正常 | 100%合格 |
| Backtest検証 | 履歴データでのパフォーマンス | Sharpe > 閾値、drawdown < 閾値 |
| Sanityチェック | 明らかなオーバーフィッティングなし | Out-of-sample Sharpe > In-sample x 0.7 |
# Backtest検証の例
def test_model_performance():
"""新しいModelがバックテストで最低基準を満たすことを確認"""
results = run_backtest(
model='models/signal_v3.pkl',
start_date='2022-01-01',
end_date='2023-12-31'
)
assert results['sharpe'] >= 1.0, f"Sharpe ratioが不十分: {results['sharpe']}"
assert results['max_drawdown'] <= 0.15, f"Drawdownが大きすぎる: {results['max_drawdown']}"
assert results['win_rate'] >= 0.45, f"Win rateが不十分: {results['win_rate']}"
# オーバーフィッティングチェック
in_sample_sr = results['in_sample_sharpe']
out_sample_sr = results['out_sample_sharpe']
assert out_sample_sr >= in_sample_sr * 0.7, "Out-of-sampleパフォーマンスの減衰が大きすぎる、オーバーフィッティングの可能性"
Quality Gate: Dual-Layer Backtest Validation
堅牢なCI/CD Pipelineは、デプロイメント前に2層のBacktest検証を要求すべきです:
1. 高速ベクトル化Backtest -- 純粋なシグナルロジック(ファクターリターン、IC、ターンオーバー)を数秒でテスト。アルファ生成の回帰を迅速にキャッチ。2. OMS統合Backtest -- シグナルを完全なオーダー管理パス(リスクチェック、オーダー分割、スリッページを伴うシミュレーションフィル)を通じてルーティング。ベクトル化テストが見逃す実行現実のギャップをキャッチ。両方の層が合格する必要があります。ベクトル化テストでは利益が出ているように見えても、現実的な実行モデリング後に失敗するシグナルはデプロイ可能ではありません。これを必須のCIゲートにすることで、最も一般的なクラスの本番障害を防ぎます:理論的には機能するが、摩擦で損失を出す戦略。
ステージ3:Stage(Pre-Release)
Shadow Mode:
Shadow Mode実行基準:
| メトリクス | 合格基準 | チェック頻度 |
|---|---|---|
| シグナルの一貫性 | 新旧シグナルの相関 >0.9または明確な改善 | リアルタイム |
| レイテンシ | 新しいModelレイテンシ < ProductionModel x 1.2 | 毎時 |
| リソース使用 | CPU/メモリが予算内 | 5分ごと |
| 異常シグナル | 極端なシグナルなし(>3標準偏差) | リアルタイム |
| 実行期間 | 少なくとも5取引日 | - |
ステージ4:Prod(Production)
段階的リリース戦略:
| 戦略 | 適用シナリオ | リスクコントロール |
|---|---|---|
| Canary | 新しいModelに小さな資本を最初に | 5% ->25% ->50% ->100% |
| Blue-Green | 即座に切り替え、ロールバック機能を維持 | いつでも古いバージョンに切り替え可能 |
| Rolling | Agentインスタンスを段階的に置き換え | 一度に1つを置き換え |
class CanaryDeployment:
"""Canary deploymentコントローラー"""
def __init__(self, old_model, new_model):
self.old_model = old_model
self.new_model = new_model
self.canary_weight = 0.05 # 5%から開始
def get_signal(self, market_data: dict) -> dict:
# 重みでトラフィックを分散
if random.random() < self.canary_weight:
signal = self.new_model.predict(market_data)
signal['model_version'] = 'canary'
else:
signal = self.old_model.predict(market_data)
signal['model_version'] = 'stable'
return signal
def promote_canary(self, new_weight: float):
"""Canary重みを増やす、段階的に拡大"""
if new_weight > self.canary_weight:
log.info(f"Promoting canary weight: {self.canary_weight:.0%} -> {new_weight:.0%}")
self.canary_weight = new_weight
def rollback(self):
"""安定バージョンにロールバック"""
log.warning("Canary rollback! Switching to stable version")
self.canary_weight = 0.0
20.7.4 Modelバージョン管理
バージョン命名規則:
Modelバージョン形式: v{major}.{minor}.{patch}-{timestamp}
例:
v2.3.1-20240115 # 2024年1月15日のバージョンv2.3.1
バージョンルール:
major: Modelアーキテクチャの変更(例:XGBoostからニューラルネットワークへ)
minor: 特徴またはパラメータの調整
patch: バグ修正
Model Registry:
| フィールド | 例 | 説明 |
|---|---|---|
model_id | signal_v2.3.1 | 一意の識別子 |
created_at | 2024-01-15 10:30:00 | 作成時刻 |
created_by | auto_train_pipeline | 作成者(人またはPipeline) |
metrics | {"sharpe": 1.5, "drawdown": 0.08} | 検証メトリクス |
status | staging / production / retired | 現在のステータス |
artifact_path | s3://models/signal_v2.3.1.pkl | ストレージ場所 |
config_hash | a1b2c3d4... | 設定ファイルハッシュ |
data_hash | e5f6g7h8... | トレーニングデータハッシュ(再現性) |
20.7.5 自動ロールバック
class AutoRollback:
"""自動ロールバックコントローラー"""
def __init__(self, rollback_thresholds: dict):
self.thresholds = rollback_thresholds
self.metrics_buffer = []
def check_and_rollback(self, current_metrics: dict) -> bool:
"""ロールバックが必要かどうかチェック"""
# 即座のロールバック条件(単一トリガー)
if current_metrics.get('error_rate', 0) > self.thresholds['max_error_rate']:
self.trigger_rollback("Error rateが高すぎる")
return True
if current_metrics.get('latency_p99', 0) > self.thresholds['max_latency']:
self.trigger_rollback("Latencyが高すぎる")
return True
# 累積ロールバック条件(トレンド判断)
self.metrics_buffer.append(current_metrics)
if len(self.metrics_buffer) >= 10: # 十分なサンプル
recent_sharpe = np.mean([m['sharpe'] for m in self.metrics_buffer[-10:]])
if recent_sharpe < self.thresholds['min_sharpe']:
self.trigger_rollback(f"Sharpeが低下: {recent_sharpe:.2f}")
return True
return False
def trigger_rollback(self, reason: str):
"""ロールバックを実行"""
log.error(f"自動ロールバックをトリガー: {reason}")
# 1. 最後の安定バージョンに切り替え
model_registry.activate('last_stable')
# 2. アラートを送信
alert_system.send(
level='critical',
title='Model自動ロールバック',
message=f'理由: {reason}'
)
# 3. ロールバックイベントを記録
audit_log.record('rollback', {'reason': reason})
20.7.6 CI/CD実装チェックリスト
+-------------------------------------------------------------+
| CI/CD実装チェックリスト |
+-------------------------------------------------------------+
| |
| [ ] バージョンコントロール |
| +-- すべてのコードがGitに |
| +-- Modelファイルにバージョン番号 |
| +-- 設定がコードから分離 |
| +-- トレーニングデータにスナップショット |
| |
| [ ] 自動化されたテスト |
| +-- Unit testがコアロジックをカバー |
| +-- BacktestがCIの一部 |
| +-- パフォーマンスベンチマークテスト |
| +-- オーバーフィッティング検出 |
| |
| [ ] Deploymentプロセス |
| +-- ワンクリックデプロイメント(手動ステップなし) |
| +-- Shadow mode検証 |
| +-- 段階的リリースメカニズム |
| +-- ワンクリックロールバック |
| |
| [ ] Observability |
| +-- デプロイメントイベントログ |
| +-- バージョンとパフォーマンスの相関 |
| +-- 自動トリガーロールバック |
| +-- 変更監査トレイル |
| |
+-------------------------------------------------------------+
20.8 Multi-Agent視点
Monitor Agentの役割
Agent間のヘルス協力
| Agent | Monitorに報告 | Monitorから受信 |
|---|---|---|
| Signal Agent | シグナル生成レイテンシ、成功率 | 一時停止/再開 |
| Risk Agent | リスクトリガー数、ステータス | 強制Circuit Breaker |
| Execution Agent | 注文ステータス、実行品質 | 保留注文をキャンセル |
| Regime Agent | 検出レイテンシ、信頼度 | デフォルト状態に切り替え |
| Data Agent | データ更新時刻、品質 | データソースを切り替え |
合格基準
このレッスンを完了した後、以下の基準を使用して学習を検証してください:
| 基準 | 標準 | 自己テスト方法 |
|---|---|---|
| 監視レベルを理解 | 4つの監視レベルの内容を説明できる | 各レベルの主要メトリクスをリスト |
| ログ形式を設計 | 構造化された取引ログを設計できる | 完全な取引ログJSONを書く |
| アラートルールを設計 | アラートレベルとチャネルを区別できる | あなたのシステムのアラートマトリクスを設計 |
| 復旧フローを理解 | 障害復旧ステップを説明できる | 復旧フロー図を描く |
| 日次チェックリストをマスター | 市場前/後のチェック項目をリストできる | あなたのチェックリストを作成 |
総合演習
あなたの運用システムを設計:
- 監視する必要がある主要メトリクスをリスト(少なくとも10)
- ログ形式を設計(必要なフィールドを含む)
- アラートルールを設計(メトリクス、閾値、レベル、チャネル)
- 市場前チェックリストを書く
- 障害シナリオの復旧フローを設計
レッスン成果物
このレッスンを完了すると、以下が得られます:
- 4層監視フレームワーク - インフラストラクチャ/サービス/アプリケーション/ビジネス
- ログ標準テンプレート - 構造化された取引ログ形式
- アラート設計ガイドライン - レベル、チャネル、抑制戦略
- 運用チェックリスト - 市場前/後のチェック項目
- CI/CD Deployment Pipeline - Build、test、shadow mode、段階的リリース
重要なポイント
- 監視の4つのレベルとその主要メトリクスを理解
- 構造化されたログ設計原則をマスター
- アラートシステム設計の要点を理解
- 障害復旧フローと状態一貫性チェックをマスター
- 日次運用チェックの習慣を確立
- 安全なModel deploymentのためのCI/CD Pipelineを設計
さらなる読み物
- レッスン19:Execution System - 実行の監視フォーカス
- 背景知識:Execution Simulator Implementation - CI/CDテストのための実行シミュレーション
- レッスン17:Online LearningとStrategy Evolution - Model drift検出の実装詳細
- 付録A:Live Trading Logging Standards - 詳細なログ仕様
次回レッスンプレビュー
レッスン21:Project Implementation
理論はここで終わります。次のレッスンでは、完全なMulti-Agent Trading Systemをゼロから構築します - 最初の20レッスンのすべての知識を統合し、アーキテクチャ設計からコード実装、Backtest検証から本番デプロイメントまで。