2026-01-07

自動売買への道 (2026-01-07)

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

今日の日経平均株価

現在値 51,961.98 -556.10 -1.06% 15:30
前日終値 52,518.08 01/06 高値 52,404.11 10:26
始値 52,144.64 09:00 安値 51,830.40 14:05

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

【関連ニュース】

デイトレ用自作アプリ

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

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

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

リアルタイムの取引シミュレーション (7011)

本日のパラメータ
パラメータ 設定値
PERIOD_MA_1 60 sec
PERIOD_MA_2 600 sec
PERIOD_SLOPE 5 sec
THRESHOLD_SLOPE 0.1 -
LOSSCUT_1 -25

年初から気になっていた売買ロジックをデバッグした結果、2 つの移動平均線がクロスした時の MA1 の傾きを選別する THRESHOLD_SLOPE および THRESHOLD_SLOPE が想定どおりに効いていませんでした。

不具合を修正後、THRESHOLD_SLOPE をひとまず妥当と考えられる値に変更しました。

以下は、本日のリアルタイム取引シミュレーション (Simulated Trade) による取引結果です。


本日のリアルタイムの取引シミュレーション (Simulated Trade)

本日のリアルタイムの取引シミュレーション (Simulated Trade) の取引明細(100 株単位)

注文番号 注文日時 銘柄コード 売買 約定単価 約定数量 損益 備考
1 2026-01-07 09:01:46 7011 買建 4210.0 100
2 2026-01-07 09:03:46 7011 売埋 4195.0 100 -1500.0
3 2026-01-07 09:03:47 7011 売建 4195.0 100
4 2026-01-07 09:11:22 7011 買埋 4199.0 100 -400.0
5 2026-01-07 09:11:23 7011 買建 4200.0 100
6 2026-01-07 09:13:42 7011 売埋 4184.0 100 -1600.0
7 2026-01-07 09:19:50 7011 売建 4185.0 100
8 2026-01-07 09:20:55 7011 買埋 4194.0 100 -900.0
9 2026-01-07 09:20:56 7011 買建 4194.0 100
10 2026-01-07 09:32:32 7011 売埋 4200.0 100 600.0
11 2026-01-07 09:33:08 7011 買建 4204.0 100
12 2026-01-07 09:34:00 7011 売埋 4200.0 100 -400.0
13 2026-01-07 09:39:51 7011 買建 4200.0 100
14 2026-01-07 09:49:04 7011 売埋 4200.0 100 0.0
15 2026-01-07 13:24:32 7011 買建 4147.0 100
16 2026-01-07 13:40:30 7011 売埋 4146.0 100 -100.0
合計損益 -4300.0

オフラインの取引シミュレーション (7011)

年末年始に売買ロジックを変更した後、過去データによる DOE 実施を急いだことで、バグを看過してしまいました。

本日収集したティックデータによる事後シミュレーションをまとめました。

本日の事後の取引シミュレーションの取引明細(100 株単位)

注文番号 注文日時 銘柄コード 売買 約定単価 約定数量 損益 備考
1 2026-01-07 09:01:46 7011 買建 4210 100
2 2026-01-07 09:03:46 7011 売埋 4195 100 -1500
3 2026-01-07 09:03:47 7011 売建 4195 100
4 2026-01-07 09:11:22 7011 買埋 4199 100 -400
5 2026-01-07 09:11:23 7011 買建 4200 100
6 2026-01-07 09:13:42 7011 売埋 4184 100 -1600
7 2026-01-07 09:19:50 7011 売建 4185 100
8 2026-01-07 09:20:55 7011 買埋 4194 100 -900
9 2026-01-07 09:20:56 7011 買建 4194 100
10 2026-01-07 09:32:32 7011 売埋 4200 100 600
11 2026-01-07 09:33:08 7011 買建 4204 100
12 2026-01-07 09:34:00 7011 売埋 4200 100 -400
13 2026-01-07 09:39:51 7011 買建 4200 100
14 2026-01-07 09:49:04 7011 売埋 4200 100 0
15 2026-01-07 13:24:32 7011 買建 4147 100
16 2026-01-07 13:40:30 7011 売埋 4146 100 -100
合計損益 -4300

リアルタイムとオフラインのシミュレーション結果を較べると、いつもビミョーにタイミングがズレていたので、取引明細が完全に一致することはあまり無いと思っていました。しかし今回はぴったり一致しました。ちょっと不思議です。🤔

ともあれ短周期と長周期、2 つの単純移動平均 MA1, MA2 のベストな周期の組み合わせを探索する実験計画 (DOE) を再開できそうです。今週末の連休に実施できるよう準備を進めます。

テクニカル指標の時系列トレンド

環境内で管理している、売買シグナルのソースとなるテクニカル指標と含み損益のトレンドをプロットしました。

縦の赤線は、取引明細の時間から入れたもので、売買をしたタイミングになります。

移動平均系テクニカル指標の時系列トレンドと含み損益

今日は、THRESHOLD_SLOPE をひとまず妥当と考えられる値に設定したつもりでしたが、妥当ではありませんでした。

大きくない値動きの中で、ここぞというところで売買が有効になりませんでした。しかし、しきい値をあまり低くしてしまうと寄り付き直後の忙しい変動に追いついて行けず、損失を更に広げてしまうことになるかもしれません。

現在、寄り付き後の 60 秒間をウォームアップ期間で取引ができない設定をしていますが、これをもう少し長くするか、それとも、なにか指標を導入して、短時間に値動きが上下に大きく変動する時間帯はエントリができなくなるような制限を入れるか…、思案中です。

寄り付き直後のエントリについては、まだ積極的には手を付けていないのですが、しばらく試行錯誤を続ける予定です。

寄り付き直後の対応については、アイデアだけまとめておきます。

  • 寄り付き後のウォームアップ期間を調節
  • 明らかに短周期の移動平均線 MA1 が値動きに追いついていない!
    • 単純移動平均線 (SMA) の利用を止めて、指数平滑移動平均線 (EMA) を採用
    • 寄り付き直後からしばらくは短周期を固定せずに変動(可能か?)
  • 寄り付き直後の変動から、ある程度落ち着くまでを監視できる指標を導入してエントリ抑制に利用
    • RollingRange をクラスを評価中

移動平均線 MA1 の傾きについては、直近株価差分の平均を取るだけの簡易的な算出方法で代用していましたが、以下の単回帰で算出する方法に変更しようと考えています。

class RegressionSlope:
    """
    RegressionSlope:
    最新の点を原点とみなしたうえで、
    「原点を通る(切片0)」単回帰の傾きを逐次計算する軽量クラス。

    - x軸: 1秒間隔を仮定
    - 最新の点を (x=0, y=0) として扱う
    """

    def __init__(self, window_size: int):
        self.slope: Optional[float] = None
        self.queue_price = deque(maxlen=window_size)

    def clear(self):
        self.queue_price.clear()
        self.slope = None

    def getSlope(self) -> float:
        # 現在の傾きを返す(未計算の場合は 0.0)
        return self.slope if self.slope is not None else 0.0

    def update(self, value: float) -> float:
        """
        新しい価格を追加し、最新点を原点とする
        切片0の単回帰の傾きを計算して返す。
        """
        self.queue_price.append(value)

        n = len(self.queue_price)
        if n < 2:
            # 点が1つだけでは傾きは定義できないので0とする
            self.slope = 0.0
            return abs(self.slope)

        # 最新点を原点(0,0)とみなす
        p_last = self.queue_price[-1]

        # x = -(n-1), ..., -1, 0 となるように設定
        # y_i = p_i - p_last
        xs = [i - (n - 1) for i in range(n)]
        ys = [p - p_last for p in self.queue_price]

        sum_xy = sum(x * y for x, y in zip(xs, ys))
        sum_x2 = sum(x * x for x in xs)

        # 切片0の単回帰の傾き: m = Σ(xy) / Σ(x^2)
        self.slope = sum_xy / sum_x2 if sum_x2 != 0 else 0.0
        return abs(self.slope)

明日の取引時間に間に合えば、新しい THRESHOLD_SLOPE の設定値で、今日と同じような評価をする予定です。

売買ロジックへのインプット

売買ロジックは Maskable PPO 互換のインターフェイスを持った自作のアルゴリズムを備えた疑似モデルです。

なるべくシンプルなロジックで売買判断できることを目指しているため、現在のところ、[0, 1] あるいは [-1, 0, 1] といった離散的なシグナルをインプットするようにしています。

シグナル名は短縮してしまって意味が判りにくいので、それぞれの機能をまとめました。

  1. クロスS1
    • 移動平均 MA1, MA2 のクロスシグナル。デッドクロス、クロス無し、ゴールデンクロスを -1, 0, 1 としたシグナル。
  2. クロスS2
    • クロスS1の 1 秒遅れのシグナル。反対売買用。
  3. クロ強
    • MA1 の傾き(絶対値)が THRESHOLD_SLOPE より大きい場合に発生するクロス・シグナルの強さを示すシグナル。
  4. ロス1
    • 含み損益が LOSSCUT_1 を下回った時に発生するシグナル。
  5. 建玉
    • ポジション SHORT, NONE, LONG-1, 0, 1 としたシグナル。
売買ロジックにインプットしているシグナル

参考サイト

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

0 件のコメント:

コメントを投稿