2026-04-28

自動売買への道 (2026-04-28)

楽天証券の口座でデイトレの自動売買に挑戦しようと、Windows / Excel 上で動作する マーケットスピード II RSS を利用した Python アプリ (Kabuto) を開発しています。

今日の日経平均株価

現在値 59,917.46 -619.90 -1.02% 15:45
前日終値 60,537.36 04/27 高値 60,634.66 09:01
始値 60,531.78 09:00 安値 59,701.84 14:37

※ 右の 15 分足チャートは Yahoo! Finance のデータを yfinance で取得して作成しました。

【関連ニュース】

強化学習の沼

5 月の連休にゆっくりバックテストができそうなので、それまでにどれだけ強化学習モデルを育てられるかに挑んでいます。

学習環境 TrainingEnv(gymnasium.Env)

学習環境の概略です。

行動空間 Action Space
  1. HOLD : 何もしない
  2. BUY  : 「買建」または「返済」
  3. SELL : 「売建」または「返済」
「返済」を行動空間に加えると学習が進まなかったことを踏まえ「返済」は環境側で制御。ナンピン禁止を行動マスクで制御
PositionType に対する mask [HOLD, BUY, SELL]
  • WARMUP [True, False, False](寄り付き後、売買できない期間を設定)
  • NONE   [True, True,  True ]
  • LONG   [True, False, True ]
  • SHORT  [True, True,  False]
観測空間 Observation Space
株価、インジケータなど
  1. MA1 / 始値     : 短周期の移動平均
  2. MA2 / 始値     : 長周期の移動平均
  3. Momentum       : モメンタム
  4. Profit         : 含み損益
  5. ProfitMax      : 最大含み損益
  6. n_trade        : 約定回数
  7. count_negative : 含み損の継続カウンタ
  8. cost_contract  : 約定コスト
  9. dd_ratio       : ドローダウン率
クロス・オシレータ関連
  1. DiffMA   : MA乖離率 = (MA1 - MA2) / MA2
  2. DiffVWAP : VWAP乖離率 = (MA1 - VWAP) / VWAP
  3. RSI      : 相対力指数
ポジションを One-Hot エンコーディング
  1. SHORT [1. 0. 0.]
  2. NONE  [0. 1. 0.]
  3. LONG  [0. 0. 1.]
報酬 Rewards
  • 建玉なし    : ゴールデン/デッド クロス・シグナル近辺の報酬分布の一部をペナルティとして付与
  • 建玉保持    : 含み損益の一定割合を付与+前ステップの含み益からの増減の一定割合を付与
  • 返済時      : 直前の含み損益を付与
  • 約定コスト  : 建玉、返済時いずれも固定の約定コスト+α(前回約定時との時間差に応じて)をペナルティとして引く
  • 連続含み損  : 許容回数を超えたらペナルティを急激に増大
終了条件 Episode End
  1. terminated
    • "目的を達成した/失敗した" など、エージェント側の原因で終了
    • 終端として扱う(価値は 0)
    1. なし(「約定回数の上限で終了」を評価予定)
  2. truncated
    • 時間制限・ステップ制限・データ終端など “外的理由” で終了
    • 終端ではない(価値を bootstrap)
    1. ティックデータが最終行に達した時
      • 終了時、建玉があれば強制返済。報酬条件、約定コストは同じ
      • 約定回数に応じて報酬付与。現在は 25 回が極大になる式を適用(ただし約定回数は偶数)。

学習・推論用エージェント

エージェントで、環境のインスタンスに Stable-Baselines3 の環境ラッパーに、ログを取る Monitor と、特徴量のスケーリングをおまかせにしたくて VecNormalize ラッパーを適用していました。

graph LR
    subgraph make_env
        A[TrainingEnv] --> B[[Monitor]]
    end
    B --> C[[DummyVecEnv]]
    C --> D[[VecNormalize]]

今週になって気がついたことですが、学習時に「買建」「売建」の両方が出現しているにもかかわらず、推論時におけるモデルの挙動が「売建」だけになる(正確には BUY になるのは返済時だけ)という問題を確認しました。

本システムでは、行動空間を HOLD/BUY/SELL の 3 状態にして、建玉の状態との組み合わせで、マスクによるナンピン売買禁止下での建玉の返済をしています。

class ActionType(IntEnum):
    HOLD = 0
    BUY = 1
    SELL = 2


class PositionType(IntEnum):
    SHORT = 0
    NONE = 1
    LONG = 2

いろいろ試しても解決できず、よくわからないけれど VecNormalize ラッパーに問題がある、ということが切り分けられました。単に自分が VecNormalize ラッパーの使い方が間違っている可能性がありますが、生成 AI の助けを借りてもコード上のミスを見つけられなかったので、ひとまず VecNormalize ラッパーの使用を止めることにしました。

graph LR
    subgraph make_env
        A[TrainingEnv] --> B[[Monitor]]
    end
    B --> C[[DummyVecEnv]]

結局、特徴量のスケーリングは自力で調節するしかなさそうです。なお、Stable-Baselines3 の PPO はベクトル化を前提としているので DummyVecEnv は外せません。

今後の方針

gymnasium.Env を継承した学習用の環境 TrainingEnv を継承した InferenceEnv を推論用の環境として利用する体制が整いました。強化学習にすべてを委ねるのではなく、下記の処理を加えて実際に利用できる環境を整えています。

  • 利確ロジック ✅
  • ロスカット ✅
  • 取引時間帯による制約の調整(学習に盛り込む余地あり)
  • 頻繁なドテン売買の抑制(検討中)
  • エントリの妥当性チェック(検討中)

利確ロジックとロスカットは学習時にも盛り込んでいますが、推論では期待するような返済を実現できていないので、推論側でもあらためて処理を実装しています。

複数のティックデータで学習

構成が変わったので、過去 58 日分のティックデータで 1 エピソード分だけ学習させました。

過去データの学習 (1 episode / day) における報酬 (episord_reward)、損益 (pnl)、約定回数 (transactions) トレンド by TensorBoard

推論トレンド

学習に使用したティックデータ + 本日収集したティックデータを順番に推論しました。

収集したティックデータに対する推論トレンド

本日分の推論詳細を示しました。

本日分のティックデータに対する推論の詳細

もう少し学習を重ねたモデルで確認する必要はありますが、高頻度な売買を合理的に抑える方法を検討します。

参考サイト

  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アクセスランキング にほんブログ村