【システム実装検証④】Pythonで自動売買の注文を発注する(kabuステーションAPI)

前回までで、APIトークンの取得から、買付余力(残高)、そして保有ポジションの取得まで、システムが現在の状況を把握するための「目」となる機能の実装が完了しました。
今回はいよいよシステムの「手」となる核心部分、Pythonプログラム経由で実際に注文(発注)を送信するテストを行います。

【最重要】発注テストは必ず「検証環境」で行う

発注プログラムの検証に入る前に、システム運用者として絶対に守るべき鉄則があります。それは、「コードのテスト段階では、絶対に本番環境(実際のお金)を使わないこと」です。

プログラムの記述ミス(ゼロを一つ多く書いてしまった、無限ループで発注を繰り返してしまった等)は、即座に致命的な資金の喪失に直結します。
kabuステーションAPIには、架空の資金で安全にテストができる「検証環境」が標準で用意されています。今回のテストプログラムでは、config.py のポート番号を必ず「18081(検証環境用)」に設定し、kabuステーションアプリも検証環境で起動した状態で実行してください。

※本APIはローカルPC上のkabuステーション経由で実行されるため、kabuステーションが起動していない場合は通信エラー(接続拒否)となりますのでご注意ください。
※発注方法としてSOR(Exchange=9)を利用することも可能ですが、本記事ではシンプルな東証指定(1)で解説しています。

新規発注(指値注文)のPython検証コード

以下が、指定した価格で買い注文(指値)を入れる検証用のプログラムです。
現物取引に不要なパラメータ(FundType等)は安全のために省略し、APIの仕様に厳密に準拠した型(数値)でリクエストを構築しています。

import requests
import config

def test_send_order():
    """検証環境にて、1329(日経平均ETF)の買い指値注文をテスト発注する"""
    print("発注テストを開始します(※検証環境であることを確認してください)")

    try:
        with open(config.KABU_TOKEN_PATH, 'r', encoding='utf-8') as f:
            token = f.read().strip()
    except FileNotFoundError:
        print("エラー: トークンファイルが見つかりません。")
        return None

    # 検証環境のポート(18081)を指定したURL
    url = f"http://localhost:{config.KABU_PORT}/kabusapi/sendorder"
    headers = {'X-API-KEY': token, 'Content-Type': 'application/json'}

    # 注文内容の定義
    order_data = {
        "Password": config.KABU_ORDER_PASSWORD, # 注文用パスワード
        "Symbol": "1329",                       # 銘柄コード
        "Exchange": 1,                          # 1: 東証(国内株・ETFは基本1でOK)
        "SecurityType": 1,                      # 1: 株式(ETF含む)
        "Side": 2,                              # 2: 買(※必ず数値で指定)
        "CashMargin": 1,                        # 1: 現物
        "DelivType": 2,                         # 2: お預り金(現物買いは基本2でOK)
        "AccountType": 4,                       # 4: 特定口座
        "Qty": 1,                               # 注文数量(※銘柄によって単位が異なるため注意)
        "Price": 5000,                          # 指値価格
        "ExpireDay": 0,                         # 0: 本日中(当日限り)
        "FrontOrderType": 20                    # 20: 指値
    }

    try:
        # POSTリクエストで注文データを送信
        response = requests.post(url, headers=headers, json=order_data, timeout=5)
        response.raise_for_status()
        result = response.json()

        # 業務エラーの検知(API異常時の型崩れも防ぐ堅牢な判定)
        if not isinstance(result, dict) or result.get('Code', 0) != 0:
            if isinstance(result, dict):
                print(f"発注エラー: [Code:{result.get('Code')}] {result.get('Message')}")
            else:
                print("発注エラー: APIから予期せぬデータ形式が返却されました。")
            return None

        # 成功時は注文番号(OrderId)が返ってくる
        order_id = result.get('OrderId')
        print(f"通信成功!注文を受け付けました。 [注文番号: {order_id}]")
        return order_id

    except requests.exceptions.RequestException as e:
        print(f"API通信エラーが発生しました: {e}")
        return None

if __name__ == "__main__":
    test_send_order()

コードの検証とパラメータの重要ポイント

このプログラムを実行し、ターミナルに「通信成功!注文を受け付けました。[注文番号: 〇〇]」と表示され、kabuステーション(検証環境)の注文照会画面に実際の注文が載っていれば、発注テストは成功です。

今回のコードには、実運用でエラーや誤作動を防ぐための重要なノウハウをいくつか組み込んでいます。

  • 安全なテスト価格の指定: Price: 5000 としていますが、1329の現在価格から大きく乖離した「通常は約定しない安全な価格」をあえて指定しています(※フラッシュクラッシュ等の例外を除く)。
  • 最低売買単位(単元株数)の注意: 今回はETFのため Qty: 1(1口単位)で発注可能ですが、通常の日本株を対象とする場合は「100株単位」が基本となります。対象銘柄によって最低単位が異なる点には十分注意してください。
  • 厳格な型指定と不要項目の削除: Side(売買区分)は文字列ではなく公式仕様通り「数値(2)」で指定しています。また、現物取引では不要な MarginTradeType(信用区分)や、エラーの原因となりやすい FundType はパラメータから削除(省略)し、シンプルで堅牢な構成にしています。
  • 業務エラーの確実な捕捉: if not isinstance(result, dict) or result.get('Code', 0) != 0: と記述することで、将来的な仕様変更への対応だけでなく、API異常時に辞書型(dict)以外のデータが返ってきた際のエラー落ちも防ぐ設計にしています。

グリッドトレードにおける「約定管理」の考え方

発注API(sendorder)は単体で動かすのは簡単ですが、当システムのような自動売買(グリッドトレード)においては、「買い注文が約定した後、利益を乗せて売り注文を出す」という一連のサイクルをいかに安全に管理するかが問われます。

この管理方法については、大きく2つのアプローチが存在します。

  1. IFD(イフダン)注文を使うアプローチ
    「もし買えたら、自動的に売ってね」という条件付き注文をはじめから証券会社に投げてしまう方法です。APIコール数が減り、システム側での管理が非常に楽になります。
  2. プログラム内で状態を監視するアプローチ
    「単なる買い注文」を出し、システムが定期的に「約定したかどうか」をチェック。約定を確認した瞬間に、プログラム側から改めて「売り注文」を新規で送信する方法です。より複雑な条件分岐やリカバリ処理を組み込むことが可能になります。

【重要】発注後の確認と二重発注リスク
プログラムから発注を行う際は、通信エラー発生時に「リトライ(再試行)」を行った結果、意図せず同じ注文が重複して送信されてしまう「二重発注リスク」に細心の注意を払う必要があります(これを防ぐ設計を「冪等性(べきとうせい)の確保」と呼びます)。
また、発注APIを叩いた後は「データを送って終わり」ではありません。システムとして運用する以上、必ず注文一覧APIや約定照会APIと組み合わせて、「実際に注文が証券会社側のサーバーで受理され、市場に出たか」を確認するフェーズを設けることが不可欠です。

次回は、この「グリッド発注と約定管理のロジック」をPythonコードに落とし込み、利益確定の売り注文をどのように安全に実装・管理していくかのフェーズへと進んでいきます。

【ご注意】
本記事は、kabuステーションAPIの技術的な検証およびプログラム実装例を解説するものであり、特定の金融商品の売買や投資手法を推奨するものではありません。
株式投資および自動売買には価格変動リスクがあり、元本を保証するものではありません。市場状況やシステムの不具合等により損失が発生する可能性があります。
実際の投資判断はご自身の責任において行っていただきますようお願いいたします。
また、自動売買プログラムの運用においては、想定外の動作や通信障害等により意図しない注文が発生するリスクもあります。十分に検証を行った上でご利用ください。