第 20 課:本番運用

目標:あなたがいなくてもシステムが正しく動作し、問題が発生したときに迅速に通知されるようにする。


典型的なシナリオ(例示)

注:以下は一般的な現象を説明するための架空の例です。数値は説明のためのものであり、特定の個人/アカウントに対応するものではありません。

2022年、あるクオンツトレーダーが6ヶ月間丹念に改良した自動取引システムをローンチしました。バックテストは完璧で、ペーパートレーディングは3ヶ月間安定して稼働しました。彼は自信を持って50万ドルを実取引に投入しました。

最初の2週間はシステムは正常に動作していました。3週目の月曜日、彼はテキストメッセージで起こされました:口座残高不足。

調査の結果、判明したこと:金曜日の取引終了後、データソースのAPIが更新され、戻り値の形式が変更されていました。システムは解析に失敗し、例外をスローしましたが、その例外は黙って飲み込まれました。週末の間、システムはログ出力がありませんでした(彼は週末は取引がないので気にしませんでした)。月曜日の開場時、システムは再接続しましたが、状態が混乱しており、一連の不合理な注文を実行し、大規模なショートポジションを含んでいました。

彼がそれに気づいたときには、口座は40%の損失を被っていました。

何が間違っていたのか?

  1. ヘルスチェックがない:データソースの障害が検出されなかった
  2. 例外が飲み込まれた:エラーが報告されなかった
  3. 監視アラートがない:2日間ログがゼロで誰も知らなかった
  4. Circuit Breakerがない:状態が異常なときに取引を停止しなかった

これが「コードが動く」と「システムが信頼できる」が2つの異なることである理由です。運用は後付けではなく、システム設計の一部です。


20.1 監視システム

監視の4つのレベル

Four Levels of Monitoring System

主要な監視メトリクス

レベルメトリクス閾値の例アラートレベル
インフラストラクチャサーバーの生存ハートビートタイムアウト30秒Critical
ネットワークレイテンシ>200msWarning
サービスCPU使用率>80% for 5分間Warning
メモリ使用率>90%Critical
ディスク容量< 10GBWarning
アプリケーションデータソース接続切断 >1分Critical
API成功率< 95%Warning
タスクキューのバックログ>100項目Warning
Agentレスポンスレイテンシ>5秒Warning
ビジネス日次ドローダウン>3%Warning
週次ドローダウン>5%Critical
異常取引単一取引 >10%ポジションCritical
取引頻度平均から3倍の偏差Warning

ヘルスチェック設計

Health Check Checklist

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 アラートシステム

アラート設計原則

原則説明
アラートは実行可能でなければならないアラートを受け取ったときに何をすべきか知っている
アラート疲労を避けるアラートが多すぎる = アラートなし
階層化された処理異なるレベルは異なるチャネルを使用
コンテキストを含むアラート情報は問題を診断するのに十分

アラートチャネル

レベルチャネル応答時間要件
LowEmail、日次サマリー翌日
MediumSlack/Teamsメッセージ1時間以内
HighSMS + 電話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プロセスがクラッシュ部分的な機能喪失自動再起動
ネットワーク障害ネットワーク停止完全な障害復旧を待つ、手動で状態を検証
データエラー異常な価格ジャンプ誤った意思決定異常を検出、処理を一時停止

復旧フロー

Disaster Recovery Flow

状態一貫性チェック

復旧後に検証する必要があること:

チェック項目方法不一致の処理
ポジションの一貫性システム記録とブローカーを比較ブローカーを真実のソースとして使用、ローカルを更新
注文ステータスすべての保留注文をクエリキャンセルまたは確認
現金残高計算値と実際を比較再計算
データの完全性欠落している市場データをチェック欠落データをバックフィル

20.5 日次運用チェックリスト

市場前チェック(毎日必須)

Pre-Market Checklist

市場時間の自動化

最も見落とされている信頼性要件の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、など)。

これが重要な理由:手動起動を必要とするシステムは、日々のリスクとして人為的ミスを導入します。ボラティリティの高いオープン中に忘れた朝が、このレッスンの冒頭の物語で説明された種類の状態混乱災害を引き起こす可能性があります。ライフサイクルを自動化し、手動介入を例外として扱います。

市場後チェック(毎日必須)

Post-Market Checklist

週次/月次チェック

頻度チェック項目目的
週次戦略パフォーマンスレビュー異常なトレンドを特定
システムリソース使用トレンドリソース枯渇を防ぐ
アラートサマリー分析システム的な問題を発見
月次完全な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

Model Deployment 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 testsAgent協力が正常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 Deployment

Shadow Mode実行基準:

メトリクス合格基準チェック頻度
シグナルの一貫性新旧シグナルの相関 >0.9または明確な改善リアルタイム
レイテンシ新しいModelレイテンシ < ProductionModel x 1.2毎時
リソース使用CPU/メモリが予算内5分ごと
異常シグナル極端なシグナルなし(>3標準偏差)リアルタイム
実行期間少なくとも5取引日-

ステージ4:Prod(Production)

段階的リリース戦略:

戦略適用シナリオリスクコントロール
Canary新しいModelに小さな資本を最初に5% ->25% ->50% ->100%
Blue-Green即座に切り替え、ロールバック機能を維持いつでも古いバージョンに切り替え可能
RollingAgentインスタンスを段階的に置き換え一度に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_idsignal_v2.3.1一意の識別子
created_at2024-01-15 10:30:00作成時刻
created_byauto_train_pipeline作成者(人またはPipeline)
metrics{"sharpe": 1.5, "drawdown": 0.08}検証メトリクス
statusstaging / production / retired現在のステータス
artifact_paths3://models/signal_v2.3.1.pklストレージ場所
config_hasha1b2c3d4...設定ファイルハッシュ
data_hashe5f6g7h8...トレーニングデータハッシュ(再現性)

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の役割

Monitor Agent Role

Agent間のヘルス協力

AgentMonitorに報告Monitorから受信
Signal Agentシグナル生成レイテンシ、成功率一時停止/再開
Risk Agentリスクトリガー数、ステータス強制Circuit Breaker
Execution Agent注文ステータス、実行品質保留注文をキャンセル
Regime Agent検出レイテンシ、信頼度デフォルト状態に切り替え
Data Agentデータ更新時刻、品質データソースを切り替え

合格基準

このレッスンを完了した後、以下の基準を使用して学習を検証してください:

基準標準自己テスト方法
監視レベルを理解4つの監視レベルの内容を説明できる各レベルの主要メトリクスをリスト
ログ形式を設計構造化された取引ログを設計できる完全な取引ログJSONを書く
アラートルールを設計アラートレベルとチャネルを区別できるあなたのシステムのアラートマトリクスを設計
復旧フローを理解障害復旧ステップを説明できる復旧フロー図を描く
日次チェックリストをマスター市場前/後のチェック項目をリストできるあなたのチェックリストを作成

総合演習

あなたの運用システムを設計

  1. 監視する必要がある主要メトリクスをリスト(少なくとも10)
  2. ログ形式を設計(必要なフィールドを含む)
  3. アラートルールを設計(メトリクス、閾値、レベル、チャネル)
  4. 市場前チェックリストを書く
  5. 障害シナリオの復旧フローを設計

レッスン成果物

このレッスンを完了すると、以下が得られます:

  1. 4層監視フレームワーク - インフラストラクチャ/サービス/アプリケーション/ビジネス
  2. ログ標準テンプレート - 構造化された取引ログ形式
  3. アラート設計ガイドライン - レベル、チャネル、抑制戦略
  4. 運用チェックリスト - 市場前/後のチェック項目
  5. CI/CD Deployment Pipeline - Build、test、shadow mode、段階的リリース

重要なポイント

  • 監視の4つのレベルとその主要メトリクスを理解
  • 構造化されたログ設計原則をマスター
  • アラートシステム設計の要点を理解
  • 障害復旧フローと状態一貫性チェックをマスター
  • 日次運用チェックの習慣を確立
  • 安全なModel deploymentのためのCI/CD Pipelineを設計

さらなる読み物


次回レッスンプレビュー

レッスン21:Project Implementation

理論はここで終わります。次のレッスンでは、完全なMulti-Agent Trading Systemをゼロから構築します - 最初の20レッスンのすべての知識を統合し、アーキテクチャ設計からコード実装、Backtest検証から本番デプロイメントまで。

この章を引用する
Zhang, Wayland (2026). 第 20 課:本番運用. In AIクオンツ取引:ゼロからイチへ. https://waylandz.com/quant-book-ja/Lesson-20-Production-Operations
@incollection{zhang2026quant_Lesson_20_Production_Operations,
  author = {Zhang, Wayland},
  title = {第 20 課:本番運用},
  booktitle = {AIクオンツ取引:ゼロからイチへ},
  year = {2026},
  url = {https://waylandz.com/quant-book-ja/Lesson-20-Production-Operations}
}