楽天証券の口座でデイトレの自動売買に挑戦しようと Windows / Excel 上で利用できる マーケットスピード II RSS を活用して Python であれこれ取り組んでいます。この「自動売買への道」のトピックでは、プログラミングの話題にも踏み込んで、日々の活動をまとめていきます。
デイトレ用自作アプリ
以下は株価に関連する情報の流れを示しています。
楽天証券では、Python からネットワーク越しに直接取引できるような API が提供されていないので、マーケットスピード II RSS を介して取引をする構成を取っています。
現在、強化学習を利用して、取引モデルを育成中です。
報酬設計の評価 2025-11-03
条件を変えながら報酬設計を試しているうちに、モデルの推論パフォーマンスが落ちてきて、遂に収益がマイナスばかりになってしまいました。そこで、一旦シンプルな報酬設計に戻して、ひとつひとつ変更を確認してそれを簡単にまとめながら進めることにしました。
強化学習のチューニングの話題は、現在のところ、自分のためだけの備忘録と化してしまっています。🙇🏻
推論に使用するティックデータ : ticks_20251019.xlsx, 7011
推論に使用するティックデータは 9:00:00 から 15:24:50(ランチタイムを除く)までの 19,490 ステップ(最大)のティックデータです。実際には寄り付いてからのデータになります。
今のところ、推論に使用する過去のティックデータは以下 (ticks_20251019.xlsx, 7011) に固定しています。
含み損にペナルティを付与 ①
前回の評価で、いつも同じようなタイミングで大きめの損失が出ていることが気になりました。そこで、含み損が出ている時の保持回数をカウントし、下記のようなロジックでペナルティを付与してみました。
動作確認のため 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 を中心とする正規分布に回帰してしまっているように見えて不満だったのですが、今回は顕著な差を確認できました。そのため、今後のチューニング材料にするために備忘録として残します。
以下のようなロジックで確認しました。
建玉を持っていることで含み益であれば報酬を、含み損であればペナルティを付与しますが、持てば持つほど報酬あるいはペナルティが比例的に増えるという設定です。現時点では、含み損益の大きさに関係なく、保持時間(回数)に応じて算出した報酬・ペナルティを付与しています。
なお、含み益の大きさにも対応させるには、
\[ {reward} \mathrel{+}= {PnL}_{unrealized} \times (1 + {count}_{HOLD} \times {ratio}) \]とすれば良いのですが、シンプルさを優先したかったので、今回は見送りました。今後の課題とします。
このような報酬・ペナルティは、ややもすると、モデルが建玉をずっと持ち続けてしまう状態になってしまう可能性があります。
数式で示したロジックの countHOLD と ratio に相当する部分の設定です。
""" 含み損益の保持のカウンター 含み損益のインセンティブ・ペナルティ比率 """ self.count_unreal_profit = 0 self.ratio_unreal_profit = 0.0001
self.ratio_unreal_profit を 0.000001, 0.00001, 0.0001 と増やして確認しましたが、下記の条件での確認結果を残しました。
- self.ratio_unreal_profit = 0.00001
- 1 個のファイルの初期学習で分布がプラス側に偏っている。
- 51 個の複数ファイルでの学習では報酬分布が収束した。
- 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_profit の 0.00001 - 0.0001 という水準は、今後、より良い条件を探すためのチューニング材料として活用します。
全体のパラメータが固まっていないので、報酬設計についてはひとまずここまでとします。次のステップは、株価の観測値の改善に取り掛かります。
現在、株価は下記のような加工をしていますが、トレンドを見る限り [-1, 1] の間の動きは他の観測値に比べて随分穏やかに見えます。
\[ {Observation}_{price} = (\frac{{Price}_{current}}{{Price}_{first}} - 1.0) \times 10 \]株価の変動こそ最も重要な情報であるにもかかわらず、生成 AI が推奨するがままに放置してしまったので、あらためて観測値用に加工するアプローチを検討します。
参考サイト
- マーケットスピード II RSS | 楽天証券のトレーディングツール
- マーケットスピード II RSS 関数マニュアル
- 注文 | マーケットスピード II RSS オンラインヘルプ | 楽天証券のトレーディングツール
- Gymnasium Documentation
- Stable-Baselines3 Docs - Reliable Reinforcement Learning Implementations
- PyTorch documentation
- PythonでGUIを設計 | Qtの公式Pythonバインディング
- Python in Excel alternative: Open. Self-hosted. No limits.
- Book - xlwings Documentation





































