【システム運用検証①】Python自動売買の強制終了を回避する「メインループ」設計

前回までは、kabuステーションAPIを通じた「情報の取得(目)」と「注文の発注(手)」の各機能を作成してきました。
今回からは【システム運用検証】として、これらのパーツを組み合わせて「自動売買システムとして継続稼働させるための設計」に入ります。

自動売買システムの「メインループ」とは

単体のプログラムは、上から下へ処理を実行して終わりますが、自動売買システムは市場が開いている間、常に相場を監視し続ける必要があります。
Pythonでこれを実現する最も基本的な形が、while True:(無限ループ)を用いたメインループ構造です。

しかし、ただ無限ループの中で「価格取得」と「発注」を繰り返すだけのコードを書くと、実運用では数時間〜数日以内に停止するケースがほとんどです。

システムを殺す「予期せぬエラー」の恐怖

実運用においてプログラムが停止する原因の大部分は、ロジックのミスではなく「外部要因によるエラー」です。

  • 一瞬のネットワーク断線による通信タイムアウト
  • 証券会社のAPIサーバーの高負荷による「503 Unavailable」エラー
  • APIからのレスポンス遅延や、予期せぬHTMLデータの返却(JSONデコード失敗)

無限ループの中でこれらの通信エラーが一度でも発生し、プログラム側で適切に処理(キャッチ)されていないと、その瞬間にPythonスクリプト自体がエラーを吐いて完全に停止してしまいます。システムトレードにおいて「監視の目が停止する」ことは、保有リスクの放置に直結するため絶対に避けなければなりません。

強制終了を極力回避する設計の検証コード

上記のリスクを踏まえ、当システムでベースとしている「エラーハンドリング(例外処理)」を組み込んだメインループの骨格コードを紹介します。

import time
import requests
import traceback

def run_trading_cycle():
    """1回分の取引サイクル(情報取得〜発注判定)"""
    # 実際にはここに、これまでの連載で作った関数群を組み込みます
    # 1. 残高・ポジションの取得
    # 2. 現在値の取得
    # 3. 買い・売りの条件判定と発注
    # 4. 状態の記録(ロギング)
    print("--- 定期チェックを実行中 ---")
    pass

def main():
    print("自動売買システムの稼働を開始します...")

    # 停止フラグ(is_running等)で安全にループを抜けられる設計にしておくとより実運用向きです
    while True:
        # ループごとに状態を初期化しておくと、例外発生後の不整合を防げる
        try:
            # メインの取引ロジックを実行
            run_trading_cycle()

            # 【重要】APIのレート制限(Rate Limit)を考慮し、呼び出し頻度は必ず制御する
            time.sleep(60) 

        except requests.exceptions.RequestException as e:
            print(f"【通信エラー】APIとの接続に失敗しました: {e}")
            print("60秒後にリトライします...")
            time.sleep(60)

        except ValueError as e:
            print(f"【データエラー】APIからのレスポンス解析に失敗しました: {e}")
            print("60秒後にリトライします...")
            time.sleep(60)

        except Exception as e:
            # 想定外のあらゆるエラーをキャッチしてシステム停止を防ぐ
            print(f"【致命的エラー】予期せぬエラーが発生しました:\n{traceback.format_exc()}")
            print("安全のため、300秒(5分)待機してからリトライします...")
            time.sleep(300)

if __name__ == "__main__":
    main()

一段レベルを上げる「運用者」の視点

このコードでは、except Exception as e: を用いて未知のエラーでもプログラムが止まらないよう設計しています。※ただし、開発段階では例外を安易に握り潰さず、エラーログを詳細に確認して根本原因を特定することが重要です。

さらに実運用レベルへと昇華させるための重要な考え方をいくつか紹介します。

  • 再試行(リトライ)戦略: 本検証コードでは一律で60秒待機としていますが、実運用ではエラーの種類や連続発生回数に応じて待機時間を段階的に伸ばす「エクスポネンシャルバックオフ」を採用することで、APIへの負荷と復旧速度のバランスを最適化できます。
  • ループの分離: なお、本格運用では「監視処理」「発注処理」「状態更新処理」を分離する設計(ワーカーモデル:非同期処理や並列処理)にすることで、さらに安定性を高めることが可能です。

運用上の最大の課題:「状態管理」の必要性

このループ構造に、これまで作成したAPIの関数を当てはめれば自動売買は動き出します。しかし、実運用ではもう一つ、絶対に乗り越えなければならない高い壁があります。それが「状態(ステータス)の管理」です。

この「状態管理」は単なるフラグ管理ではなく、実運用では“約定単位での整合性”を維持する必要があります。この“約定単位での整合性”を崩さずに運用し続けることが、自動売買において最も難易度が高く、かつ最も重要なポイントになります。

プログラムが例外エラーから復帰してループを再開した際、「今の状態は、すでに売り注文を出して待機中なのか?」「前回のエラーで注文が通っていなかったのか?」をシステム自身が正確に記憶・判定できなければ、二重発注や意図しない決済のループに陥ります。
当システムでは、注文ごとのステータスを外部で一意に管理する仕組みを導入し、このループの中で厳密なチェックを行っています。

この「止めない設計」と「状態管理」が組み合わさって初めて、自動売買は“実運用レベル”に到達します。

次回は、このループの中で日々の取引結果をどのように記録し、日次レポートとして残していくか(ロギングの実装)について検証していきます。

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