2025-11-03

自動売買への道 (2025-11-03)

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

デイトレ用自作アプリ

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

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

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

現在、強化学習を利用して、取引モデルを育成中です。

報酬設計の評価 2025-11-03

条件を変えながら報酬設計を試しているうちに、モデルの推論パフォーマンスが落ちてきて、遂に収益がマイナスばかりになってしまいました。そこで、一旦シンプルな報酬設計に戻して、ひとつひとつ変更を確認してそれを簡単にまとめながら進めることにしました。

強化学習のチューニングの話題は、現在のところ、自分のためだけの備忘録と化してしまっています。🙇🏻

推論に使用するティックデータ : ticks_20251019.xlsx, 7011

推論に使用するティックデータは 9:00:00 から 15:24:50(ランチタイムを除く)までの 19,490 ステップ(最大)のティックデータです。実際には寄り付いてからのデータになります。

今のところ、推論に使用する過去のティックデータは以下 (ticks_20251019.xlsx, 7011) に固定しています。

含み損にペナルティを付与 ①

前回の評価で、いつも同じようなタイミングで大きめの損失が出ていることが気になりました。そこで、含み損が出ている時の保持回数をカウントし、下記のようなロジックでペナルティを付与してみました。

\[ if\quad{PnL}_{unrealized} \lt 0\quad{:}\\[2mm] \quad{reward} \mathrel{+}= {PnL}_{unrealized} \times (1 + {count}_{HOLD} \times {ratio}) \]

動作確認のため ticks_20251019.xlsx, 7011 で学習および推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                    注文日時 銘柄コード        売買  約定単価  約定数量   損益
0    2025-09-19 09:01:22  7011        売建  3719     1  NaN
1    2025-09-19 09:01:27  7011        買埋  3720     1 -1.0
2    2025-09-19 09:01:36  7011        売建  3718     1  NaN
3    2025-09-19 09:01:56  7011        買埋  3717     1  1.0
4    2025-09-19 09:02:50  7011        買建  3711     1  NaN
..                   ...   ...       ...   ...   ...  ...
285  2025-09-19 15:16:12  7011        買埋  3686     1 -3.0
286  2025-09-19 15:17:12  7011        売建  3685     1  NaN
287  2025-09-19 15:18:40  7011        買埋  3687     1 -2.0
288  2025-09-19 15:18:50  7011        売建  3685     1  NaN
289  2025-09-19 15:24:59  7011  買埋(強制返済)  3689     1 -4.0

[290 rows x 6 columns]
一株当りの損益 : 25.0 円
モデルへの報酬分布
n: 19387, mean: 0.001, stdev: 0.005
観測数 : 9

報酬分布

観測値のトレンド

含損益のトレンドは、含み益が出る方向を示しているように見えます。

含み損にペナルティを付与 ②

過去 51 日分のティックデータで順番に学習したモデルに対して ticks_20251019.xlsx, 7011 のデータで推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                    注文日時 銘柄コード  売買  約定単価  約定数量   損益
0    2025-09-19 09:04:04  7011  売建  3722     1  NaN
1    2025-09-19 09:04:16  7011  買埋  3717     1  5.0
2    2025-09-19 09:04:44  7011  売建  3723     1  NaN
3    2025-09-19 09:04:46  7011  買埋  3720     1  3.0
4    2025-09-19 09:06:51  7011  売建  3728     1  NaN
..                   ...   ...  ..   ...   ...  ...
295  2025-09-19 15:11:40  7011  買埋  3681     1  2.0
296  2025-09-19 15:11:43  7011  売建  3683     1  NaN
297  2025-09-19 15:11:44  7011  買埋  3683     1  0.0
298  2025-09-19 15:11:57  7011  売建  3683     1  NaN
299  2025-09-19 15:12:00  7011  買埋  3681     1  2.0

[300 rows x 6 columns]
一株当りの損益 : 61.0 円
モデルへの報酬分布
n: 19387, mean: -0.000, stdev: 0.002
観測数 : 9

総収益は確かにプラスにはなっていますが、13 時過ぎに大きめの損失が出ています。ただし、スケールを考慮すると対して大きな損失ではありません。むしろ小さな収益を頻繁に重ねているのが気になります。

報酬分布

学習を重ねると、平均値が 0 になり標準偏差が小さくなり、対数軸ではありますが、まるで正規分布に回帰してしまっているみたいです。

観測値のトレンド

取引回数が 300 回程度と、それほど大きくないのに、含損益のトレンドの起伏がほとんどありません。学習を重ねると、損失がでないが収益も上がらない方向に学習が進んでしまっているようにも見えます。

まとめ

よくよく考えてみると、含み損にペナルティを与えるだけでは、含みがある時に長く建玉を持つようには学習しません。いっそのこと建玉を保持している時に損益に応じて報酬・ペナルティを与えることを評価してみます。


🎯 建玉保持に報酬・ペナルティ付与

建玉を保持している間、損益の符号に応じて報酬・ペナルティを付与した場合のモデルの挙動についてまとめました。

いままでの評価では、過去の複数データで学習を重ねると、対数軸とは言え、報酬分布がなんとなく報酬 0 を中心とする正規分布に回帰してしまっているように見えて不満だったのですが、今回は顕著な差を確認できました。そのため、今後のチューニング材料にするために備忘録として残します。

以下のようなロジックで確認しました。

\[ if\quad{PnL}_{unrealized} \gt 0\quad{:}\\[1mm] \quad{reward} \mathrel{+}= {PnL}_{unrealized} + {count}_{HOLD} \times {ratio}\\[3mm] if\quad{PnL}_{unrealized} \lt 0\quad{:}\\[1mm] \quad{reward} \mathrel{+}= {PnL}_{unrealized} - {count}_{HOLD} \times {ratio} \]

建玉を持っていることで含み益であれば報酬を、含み損であればペナルティを付与しますが、持てば持つほど報酬あるいはペナルティが比例的に増えるという設定です。現時点では、含み損益の大きさに関係なく、保持時間(回数)に応じて算出した報酬・ペナルティを付与しています。

なお、含み益の大きさにも対応させるには、

\[ {reward} \mathrel{+}= {PnL}_{unrealized} \times (1 + {count}_{HOLD} \times {ratio}) \]

とすれば良いのですが、シンプルさを優先したかったので、今回は見送りました。今後の課題とします。

このような報酬・ペナルティは、ややもすると、モデルが建玉をずっと持ち続けてしまう状態になってしまう可能性があります。

数式で示したロジックの countHOLDratio に相当する部分の設定です。

"""
含み損益の保持のカウンター
含み損益のインセンティブ・ペナルティ比率
"""
self.count_unreal_profit = 0
self.ratio_unreal_profit = 0.0001

self.ratio_unreal_profit0.000001, 0.00001, 0.0001 と増やして確認しましたが、下記の条件での確認結果を残しました。

  1. self.ratio_unreal_profit = 0.00001
    • 1 個のファイルの初期学習で分布がプラス側に偏っている。
    • 51 個の複数ファイルでの学習では報酬分布が収束した
  2. self.ratio_unreal_profit = 0.0001
    • 1 個のファイルの初期学習で分布がプラス側に偏っている。
    • 51 個の複数ファイルでの学習でも報酬分布が収束しなかった

建玉保持に報酬・ペナルティ付与 1. self.ratio_unreal_profit = 0.00001

self.ratio_unreal_profit = 0.00001 は、ザラ場中(最大 19,490 ステップ前提)に株価が単調に上昇あるいは下降している局面で、ひたすら報酬・ペナルティ付与し続けることになっても、1 ステップあたりの報酬・ペナルティの絶対値が 1 を超えない比率です。

※ 報酬の基本設計は 1 ステップの報酬の絶対値が 1 を超えないようにしています。

まず ticks_20251019.xlsx, 7011 で学習および推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                   注文日時 銘柄コード        売買  約定単価  約定数量   損益
0   2025-09-19 09:01:09  7011        売建  3714     1  NaN
1   2025-09-19 09:01:44  7011        買埋  3717     1 -3.0
2   2025-09-19 09:01:50  7011        買建  3716     1  NaN
3   2025-09-19 09:02:19  7011        売埋  3713     1 -3.0
4   2025-09-19 09:02:27  7011        売建  3711     1  NaN
..                  ...   ...       ...   ...   ...  ...
93  2025-09-19 15:22:44  7011        買埋  3685     1  4.0
94  2025-09-19 15:22:45  7011        売建  3685     1  NaN
95  2025-09-19 15:24:47  7011        買埋  3689     1 -4.0
96  2025-09-19 15:24:51  7011        売建  3689     1  NaN
97  2025-09-19 15:24:59  7011  買埋(強制返済)  3689     1  0.0

[98 rows x 6 columns]
一株当りの損益 : 21.0 円
モデルへの報酬分布
n: 19387, mean: 0.017, stdev: 0.023
観測数 : 9

報酬分布

報酬分布は、平均値 (mean) が示すとおり、プラス側に偏っています。

観測値のトレンド

建玉保持に報酬・ペナルティ付与 1. self.ratio_unreal_profit = 0.00001

過去 51 日分のティックデータで順番に学習したモデルに対して ticks_20251019.xlsx, 7011 のデータで推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                     注文日時 銘柄コード        売買  約定単価  約定数量   損益
0     2025-09-19 09:01:04  7011        売建  3719     1  NaN
1     2025-09-19 09:01:05  7011        買埋  3719     1  0.0
2     2025-09-19 09:01:06  7011        売建  3718     1  NaN
3     2025-09-19 09:01:08  7011        買埋  3714     1  4.0
4     2025-09-19 09:01:12  7011        売建  3713     1  NaN
...                   ...   ...       ...   ...   ...  ...
8269  2025-09-19 15:24:42  7011        買埋  3687     1  2.0
8270  2025-09-19 15:24:48  7011        買建  3688     1  NaN
8271  2025-09-19 15:24:49  7011        売埋  3688     1  0.0
8272  2025-09-19 15:24:59  7011        買建  3689     1  NaN
8273  2025-09-19 15:24:59  7011  売埋(強制返済)  3689     1  0.0

[8274 rows x 6 columns]
一株当りの損益 : -173.0 円
モデルへの報酬分布
n: 19387, mean: -0.001, stdev: 0.004
観測数 : 9

学習を重ねるた結果、売買頻度が増えてしまいました。建玉を保持している時間(ステップ数)に比例して付与する報酬・ペナルティが、学習するには小さすぎるのかもしれません。

報酬分布

学習を重ねると報酬分布は、平均値 (mean) が示すとおり、0 近辺に戻って、標準偏差 (stdev) も小さくなってしまいました。

観測値のトレンド

取引頻度が増加に反比例するかのように、含損益の起伏が少なくなってしまいました。


建玉保持に報酬・ペナルティ付与 2. self.ratio_unreal_profit = 0.0001

self.ratio_unreal_profit = 0.0001 は、ザラ場中(最大 19,490 ステップ前提)に株価が単調に上昇あるいは下降している局面で、ひたすら報酬・ペナルティ付与し続けると、1 ステップあたりの報酬・ペナルティの絶対値が 10,000 秒(≈ 166 分)で 1 を超えてしまう比率です。

※ 報酬の基本設計は 1 ステップの報酬の絶対値が 1 を超えないようにしています。

まず ticks_20251019.xlsx, 7011 で学習および推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                    注文日時 銘柄コード        売買  約定単価  約定数量   損益
0    2025-09-19 09:01:12  7011        売建  3713     1  NaN
1    2025-09-19 09:01:21  7011        買埋  3717     1 -4.0
2    2025-09-19 09:01:22  7011        売建  3719     1  NaN
3    2025-09-19 09:01:32  7011        買埋  3718     1  1.0
4    2025-09-19 09:01:38  7011        売建  3719     1  NaN
..                   ...   ...       ...   ...   ...  ...
367  2025-09-19 15:18:09  7011        買埋  3688     1 -2.0
368  2025-09-19 15:18:11  7011        売建  3688     1  NaN
369  2025-09-19 15:19:55  7011        買埋  3688     1  0.0
370  2025-09-19 15:19:56  7011        売建  3688     1  NaN
371  2025-09-19 15:24:59  7011  買埋(強制返済)  3689     1 -1.0

[372 rows x 6 columns]
一株当りの損益 : 27.0 円
モデルへの報酬分布
n: 19387, mean: 0.104, stdev: 0.151
観測数 : 9

報酬分布

報酬分布は、平均値 (mean) が示すとおり、プラス側に偏っていて、形状もいびつです。

観測値のトレンド

建玉保持に報酬・ペナルティ付与 2. self.ratio_unreal_profit = 0.0001

過去 51 日分のティックデータで順番に学習したモデルに対して ticks_20251019.xlsx, 7011 のデータで推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                    注文日時 銘柄コード        売買  約定単価  約定数量    損益
0    2025-09-19 09:02:29  7011        買建  3710     1   NaN
1    2025-09-19 09:02:32  7011        売埋  3712     1   2.0
2    2025-09-19 09:02:43  7011        買建  3710     1   NaN
3    2025-09-19 09:02:50  7011        売埋  3711     1   1.0
4    2025-09-19 09:02:53  7011        買建  3710     1   NaN
..                   ...   ...       ...   ...   ...   ...
473  2025-09-19 13:19:15  7011        売埋  3598     1  -6.0
474  2025-09-19 13:19:16  7011        買建  3596     1   NaN
475  2025-09-19 13:19:17  7011        売埋  3596     1   0.0
476  2025-09-19 13:19:19  7011        買建  3597     1   NaN
477  2025-09-19 15:24:59  7011  売埋(強制返済)  3689     1  92.0

[478 rows x 6 columns]
一株当りの損益 : -13.0 円
モデルへの報酬分布
n: 19387, mean: 0.360, stdev: 0.270
観測数 : 9

13:00 前後で取引が頻繁になってしまっていることが残念です。

報酬分布

総収益はマイナスになってはいますが、報酬分布を見ると、分布幅が収束せずに複数の学習を経ても分布が極端に偏っているのが維持されています。

1 ステップの報酬は、tanh で [-1, 1] に収まるようにしていて、追加の「建玉保持に報酬・ペナルティ付与」を例外的にそのまま扱っています。そのため、報酬分布に 1 を超えたものがあります(最後の強制決済時の報酬)。今後、スケーリングの整合性を検討します。

観測値のトレンド

前述したように 13:00 前後で取引が頻繁になってしまっていることが残念でが、「含損益」のトレンドはおおむね期待通りにプラス側(含み益側)に偏っています。

建玉保持に報酬・ペナルティ付与 2. self.ratio_unreal_profit = 0.0001

念の為、さらに追加学習(強化学習)をして、報酬分布が想定外に収束してしまわないことを確認しました。

学習済みモデルに対して、さらに過去 51 日分のティックデータで順番に追加学習したモデルに対して ticks_20251019.xlsx, 7011 のデータで推論をしました。

推論結果(使用データ : ticks_20251019.xlsx, 7011)

過去データ ticks_20250919.xlsx の銘柄 7011 について推論します。
モデル models/ppo_7011.zip を読み込みます。
Wrapping the env in a DummyVecEnv.
                    注文日時 銘柄コード        売買  約定単価  約定数量    損益
0    2025-09-19 09:01:05  7011        買建  3719     1   NaN
1    2025-09-19 09:01:09  7011        売埋  3714     1  -5.0
2    2025-09-19 09:01:10  7011        買建  3715     1   NaN
3    2025-09-19 09:01:17  7011        売埋  3714     1  -1.0
4    2025-09-19 09:01:18  7011        買建  3716     1   NaN
..                   ...   ...       ...   ...   ...   ...
127  2025-09-19 13:19:14  7011        買埋  3598     1  -1.0
128  2025-09-19 13:19:17  7011        買建  3596     1   NaN
129  2025-09-19 13:19:18  7011        売埋  3597     1   1.0
130  2025-09-19 13:19:19  7011        買建  3597     1   NaN
131  2025-09-19 15:24:59  7011  売埋(強制返済)  3689     1  92.0

[132 rows x 6 columns]
一株当りの損益 : -55.0 円
モデルへの報酬分布
n: 19387, mean: 0.378, stdev: 0.298
観測数 : 9

報酬分布

再学習を重ねても、分布幅が収束せずに右側に偏ったままです。

観測値のトレンド

まとめと次のステップ

今回は報酬分布の形状を重視して、条件の水準を変えれば報酬がプラスに偏ったままになる境界を厳密ではありませんが確認できました。

学習を重ねると報酬分布が 0 を中心とした正規分布に近づくということは、試した評価が実はあまり効果がなかった証のように思うのですが、今回は学習を重ねても期待する方向に分布が偏ってくれました。効果の有無が確認できる領域を確認できたということが収穫です。

今回扱ったパラメータ self.ratio_unreal_profit0.00001 - 0.0001 という水準は、今後、より良い条件を探すためのチューニング材料として活用します。

全体のパラメータが固まっていないので、報酬設計についてはひとまずここまでとします。次のステップは、株価の観測値の改善に取り掛かります。

現在、株価は下記のような加工をしていますが、トレンドを見る限り [-1, 1] の間の動きは他の観測値に比べて随分穏やかに見えます。

\[ {Observation}_{price} = (\frac{{Price}_{current}}{{Price}_{open}} - 1.0) \times 10 \]

株価の変動こそ最も重要な情報であるにもかかわらず、生成 AI が推奨するがままに放置してしまったので、あらためて観測値用に加工するアプローチを検討します。

参考サイト

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

0 件のコメント:

コメントを投稿