【システム運用検証②】Python自動売買のブラックボックス化を防ぐ「ログ出力」設計

前回は、通信エラーや予期せぬ例外からシステムを守り、24時間稼働を維持するための「メインループ設計とエラーハンドリング」について解説しました。
しかし、プログラムが止まらなくなったからといって、そのまま放置して良いわけではありません。

今回は、動き続ける自動売買システムの中身を可視化し、運用者が安心を手に入れるための「ロギング(ログ出力)設計」について検証していきます。

自動売買において「ログ」が最強の武器になる理由

初心者の方が自動売買のコードを書く際、画面に print() で結果を表示して満足してしまうことがよくあります。
しかし実運用において、ターミナル(黒い画面)に文字を流すだけの設計は非常に危険です。なぜなら、画面を閉じた瞬間、あるいはシステムが再起動した瞬間に「過去にシステムがどう動いたか」という証拠が残らなくなってしまうためです。

ログをテキストファイル等に永続的に記録(ロギング)することは、単なるエラーチェックの枠を超え、システム運用において以下のような「最強の武器」となります。

  • 障害時の「原因特定と復旧」を爆速化する(どこで、なぜエラーが起きたか証拠が残る)
  • システムの「健康状態」を証明する(正常に監視ループが回っているか確認できる)
  • ロジックの「改善点」を見つけるデータになる(約定のタイミングやスリップの確認)

ログがない自動売買システムは、計器を持たずに夜間飛行をするようなものです。

実運用で必須となる「3層のログ構造」

では、具体的に何を記録すべきなのでしょうか?
実運用に耐えうるシステムを構築するためには、ログを以下の「3つの役割」に分けて出力・管理する設計が推奨されます。

  1. 取引ログ(Result): 「〇〇円で買い約定」「〇〇円で利確注文送信」など、実際の資金増減に関わる結果の記録。
  2. エラーログ(Health): 「APIタイムアウト(60秒リトライ)」「JSON解析エラー」など、前回の記事で実装した例外処理の稼働記録。
  3. 状態ログ(State): 「定期監視実行中」「保有ポジション:3口(未決済)」など、システムが現在どのような認識で動いているかの記録。

Python標準モジュールを用いたロギング実装コード

Pythonには、こうしたログ管理を簡単かつ強力に行うための logging モジュールが標準で用意されています。
これを前回のメインループに組み込むための、基礎的な設定コードを紹介します。

import logging
import os
from datetime import datetime

def setup_logger():
    """日別のログファイルを自動生成するロガー設定"""
    log_dir = "logs"
    os.makedirs(log_dir, exist_ok=True) # logsフォルダが無ければ作成

    # 今日の日付をファイル名にする(例:system_20260509.log)
    date_str = datetime.now().strftime("%Y%m%d")
    log_file = f"{log_dir}/system_{date_str}.log"

    # ロガーの基本設定(INFOレベル以上を記録)
    # ※basicConfigは一度しか有効にならないため、同一プロセスでの再実行時は注意が必要です
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s [%(levelname)s] %(message)s',
        handlers=[
            logging.FileHandler(log_file, encoding='utf-8'), # ファイルに保存
            logging.StreamHandler()                          # 画面にも表示
        ]
    )
    return logging.getLogger(__name__)

# ロガーの初期化
logger = setup_logger()

# 実際の組み込みイメージ
def run_trading_cycle():
    logger.info("--- [状態] 定期ポジション監視を開始 ---")

    # (実際にはここに売買ロジックを実装) 買い条件を満たした場合
    # logger.info("[取引] 1329 ETFを5000円で買い注文送信")

    # (同上) エラーが発生した場合
    # logger.error("[異常] API接続タイムアウト発生。60秒待機します。")

if __name__ == "__main__":
    logger.info("=== 自動売買システム起動 ===")
    run_trading_cycle()

「可視化」の先にある、自動売買最大の壁

ログを実装することで、システムが過去に何を行い、今どのような健康状態にあるのかを運用者が把握できるようになります(可視化の完了)。

しかし、ここでシステム開発において最も難易度が高く、かつ運用成績を左右する「最後の壁」に直面します。
それは、人間(運用者)がログを見て状況を把握するだけでなく、「システム自身に、過去の自分の行動と現在の状態を記憶・把握させること」です。

例えば、ログファイルに「10:00に5,000円で買い約定した」と記録されていても、システム自体がその情報をリアルタイムに参照・理解できる構造になっていなければ、「その5,000円の保有ポジションに対して、利確の売り注文を出したのかどうか」が分からず、二重発注や放置のミスを犯してしまいます。

つまり、「ログ出力(過去の記録)」と並行して、約定単位での整合性を維持するための「状態管理(ステータスのトラッキング)」を行う仕組みが不可欠なのです。
この「止めない設計(ループ)」「可視化(ログ)」、そして「状態管理」の3つが完全に噛み合って初めて、資金を預けるに足る本物の自動売買システムが完成します。

ここまでの連載で、自動売買を構成する「目(取得)」「手(発注)」「脳(ループと可視化)」の各パーツの検証が完了しました。
次回は、この「状態管理」の概念設計と、実運用に向けたシステム全体の統合について考察します。

【免責事項】
自動売買およびシステムトレードは利益を保証するものではなく、相場の急変やシステム障害・ネットワーク不具合などにより想定外の損失が発生する可能性があります。本記事のコードは検証を目的としたものであり、最終的な運用と投資判断は必ずご自身の責任で行ってください。