2026-02-11

自動売買への道 (2026-02-11)

楽天証券の口座でデイトレの自動売買に挑戦しようと Windows / Excel 上で利用できる マーケットスピード II RSS を活用して Python であれこれ取り組んでいます。この「自動売買への道」のトピックでは、プログラミングの話題にも踏み込んで、日々の活動をまとめています。

デイトレ用自作アプリ

以下は株価・取引に関連する情報の流れを示しています。

株価データ・取引の流れ(Windows 11)

楽天証券では、Python からネットワーク越しに直接取引できるような API が提供されていないので、マーケットスピード II RSS を介して取引をする構成を取っています。

開発中の取引アプリに信用売買の注文をする機能を実装したので試験運用を始めました。

取引アプリの概要を以下にまとめました。

現在のアプリは、エントリ:手動、エグジット:自動(+手動)の構成になっています。

収集したティックデータで 10 倍速での売買シミュレーション(Fedora Linux 43)

売買ロジックの調整 ─ Kabuto 0.3.13

昨年、強化学習モデルを利用して自動売買をしようと Kabuto と名付けたアプリの開発に取り組んできましが、強化学習に過大な期待をしてしまったため、成果を出せずに頓挫してしまいました。

一旦、強化学習の取り組みを止めて、将来の再挑戦に備えて強化学習モデルを扱う Gymnasium の環境クラスを残し、自分が設定したロジックを疑似モデルとしてアプリに組み込みました。疑似モデルは Maskable PPO のインターフェイス互換を目指しています。

現在のアプリでは、エントリを自動化することが難しかったので手動とし、エグジットのみ自動化(+手動)しています。

これだけでも、独りよがりな願望で損切りできない行動を阻止できます。

今回、クロス・シグナル時の売買アクションに修正を加えました。

下記のコードは、エグジットの判定をするロジックです(修正後)。メソッド名を predict としているのは、強化学習モデルのインターフェイスに合わせているためで、予測はしていません。

こういう時、if 文の入れ子が深くなろうとも、とにかく実現したいロジックを記述し、意図通り動作することを売買シミュレーションで確認してから、生成 AI にロジックの整理をしてもらいます。

最近は Microsoft Copilot に相談することが多いのですが、今回は時間に余裕があったので、Google Gemini, Mistral AI / Le ChatAnthropic Claude にも同じ質問をしてコンペを実施しました。その結果、最も見通しが良いコーディングだった Gemini の提案を採用しました。

    def predict(self, obs, masks) -> tuple[int, dict]:
        # --- 観測値の取り出し ---
        # 1. クロスシグナル 1 [-1, 0, 1]
        cross_1 = int(obs[self.idx_cross_1])
        # 2. ロスカット 1 [0, 1]
        losscut_1 = int(obs[self.idx_losscut_1])
        # 3. ロスカット 2 [0, 1]
        losscut_2 = int(obs[self.idx_losscut_2])
        # 4. 利確 1 [0, 1]
        takeprofit_1 = int(obs[self.idx_takeprofit_1])
        # 5. ポジション(建玉) [SHORT, NONE, LONG]
        position = PositionType(int(obs[self.idx_position]))

        # --- エグジット判定 ---
        # 1. 継続(HOLD)条件を先に判定して早期リターン(ガード句)
        # ポジションとシグナルが一致している場合は、何もしない(HOLD)
        if (position == PositionType.LONG and cross_1 > 0) or \
                (position == PositionType.SHORT and cross_1 < 0):
            return ActionType.HOLD.value, {}

        # 2. エグジット判定が必要なシグナルがあるか確認
        # いずれかのフラグが立っている場合のみ処理を続行
        has_signal = any((cross_1, losscut_1, losscut_2, takeprofit_1))
        if has_signal:
            exit_act = self.exit_action(position)
            # 有効なアクションかつ実行可能ならそのアクションを返す
            if exit_act and self.can_execute(exit_act, masks):
                return exit_act, {}

        # 3. デフォルトは HOLD
        return ActionType.HOLD.value, {}

余談ですが、Copilot に採用結果をコード付きで教えると、とてもフェアな回答が返ってきました。

ありがとう。でも、今回は Google Gemini が提案した下記のロジックを採用します。

def predict_old(self, obs, masks) -> tuple[int, dict]:
(以下省略)
了解です。
あなたが今回 Gemini が提案したロジックを採用するという判断、すごく良いと思います。
理由はシンプルで、あなたのコード全体のモチーフ ― 「最小限の変更で、既存の流れを壊さず、読み手の心理的負荷を下げる」 ― に非常に合っているからです。

そして、あなたが貼ってくれたロジックは あなたの既存の設計思想と整合性が高い

今のところ部分最適化を生成 AI にお願いすることが多いのですが、それだけでもコーディング時間を劇的に削減できています。面倒なロジックの整理を生成 AI に任せられるようになって助かっている反面、自分がどんどんおバカになってしまわないか心配です。😅

参考サイト

  1. マーケットスピード II RSS | 楽天証券のトレーディングツール
  2. マーケットスピード II RSS 関数マニュアル
  3. 注文 | マーケットスピード II RSS オンラインヘルプ | 楽天証券のトレーディングツール
  4. PythonでGUIを設計 | Qtの公式Pythonバインディング
  5. Python in Excel alternative: Open. Self-hosted. No limits.
  6. Book - xlwings Documentation
にほんブログ村 株ブログ 株日記へ
PVアクセスランキング にほんブログ村

0 件のコメント:

コメントを投稿