FX自動売買で「利益が出ているポジションを早く利確しすぎる」問題に悩んでいないだろうか。固定のTP(テイクプロフィット)では、トレンドが継続している局面で利益の大部分を取りこぼしてしまう。
一方で「TP を外して放置する」のは、含み益が全て消えるリスクがある。必要なのは「ある程度利益が乗ったら、SL(ストップロス)を建値以上に引き上げて、利益を確保しながらトレンドに追随する」仕組みだ。
本記事では、BEP(Break Even Point、損益分岐点)トリガー60% + 追随80%の状態機械(State Machine)でトレーリングストップを実装し、92テスト全PASSで本番稼働させた過程を記録する。
固定TP/SLの問題
典型的な設定
エントリー: 150.000
SL: 149.500(-50pips)
TP: 150.200(+20pips)
RR比: 0.4(リスク > リワード)
この設定では勝率が高くてもRR比が悪く、連敗で一気に資産が減る。
逆にTPを大きく設定すると:
エントリー: 150.000
SL: 149.500(-50pips)
TP: 152.000(+200pips)
RR比: 4.0(リワード >> リスク)
RR比は良くなるが、TPに到達する前に反転して損切りになるケースが増え、勝率が大幅に下がる。
根本的な問題: 固定TPは「相場がどこまで動くか」を事前に決め打ちしている。しかし相場の動きは事前に分からない。
トレーリングストップとは
トレーリングストップ(Trailing Stop)は、ポジションの含み益が増えるに従って、SL(ストップロス)を利益方向に自動的に引き上げる手法だ。
エントリー: 150.000(Buy)
初期SL: 149.500(-50pips)
価格が150.300に上昇 → SLを149.800に引き上げ(追随)
価格が150.600に上昇 → SLを150.100に引き上げ(利益確保)
価格が150.400に反転 → SLは150.100のまま(下げない)
価格が150.100に到達 → SLに到達して決済(+10pips確保)
ポイントは「SLは上方向にしか動かない」ことだ。一度引き上げたSLは、価格が反転しても下げない。これにより「最低限の利益を確保しながらトレンドに追随する」動作を実現する。
状態機械(State Machine)による設計
トレーリングストップの動作を「状態」で管理する設計にした。状態機械(State Machine)とは、システムが取りうる状態を明示的に定義し、状態間の遷移条件を厳密に管理するパターンだ。
3つの状態
[INITIAL] ──(含み益 ≥ 60%)──→ [BEP_TRIGGERED] ──(含み益 ≥ 80%)──→ [TRAILING]
│ │ │
│ 含み益 < 60% │ SLに到達 │ SLに到達
└─→ 通常SL/TPで決済 └─→ BEP近辺で決済 └─→ 追随SLで決済
INITIAL(初期状態):
- 通常のSL/TPで管理
- 含み益がTP目標の60%に到達したら次の状態へ遷移
BEP_TRIGGERED(BEPトリガー状態):
- SLを建値(BEP)+ スプレッド分に引き上げ
- TPを解除(利益の上限を外す)
- 含み益がTP目標の80%に到達したら次の状態へ遷移
TRAILING(追随状態):
- 価格の動きに追随してSLを引き上げ続ける
- 追随幅はATR(Average True Range)の一定倍数
なぜ60%と80%なのか
60%(BEPトリガー): TP目標の60%まで到達すれば、「この方向のトレンドはある程度信頼できる」と判断できる。ここでSLを建値に引き上げることで「最悪でも損失ゼロ」を確保する。
80%(トレーリング開始): TP目標の80%に到達すれば、トレンドが十分に強いと判断できる。ここからTPを外してトレーリングに切り替えることで、トレンドの続く限り利益を伸ばす。
バックテストのグリッドサーチで40%〜80%の範囲を5%刻みで検証した結果、60%/80%の組み合わせがシャープ比(リスクあたりのリターン)最大となった。
実装のポイント
ATRベースの追随幅
追随中のSLは「現在価格 - ATR × multiplier」で計算する。ATR(Average True Range、平均的な値動き幅)を使うことで、ボラティリティに応じた適切な追随幅を自動設定できる。
def calc_trailing_sl(
current_price: float,
direction: str, # "buy" or "sell"
atr: float,
trailing_multiplier: float = 1.0,
) -> float:
distance = atr * trailing_multiplier
if direction == "buy":
return current_price - distance
else:
return current_price + distance
trailing_multiplier=1.0は「ATR 1本分」を追随幅とする設定で、通常のボラティリティなら適切な距離感だ。値を小さくするとSLがタイトになり、トレンドの小さな押し戻しで決済されやすくなる。
状態遷移のログ
状態が遷移したタイミングをログとSlackに通知する。これにより「いつ、なぜ、どの状態に遷移したか」を運用中に追跡できる。
[TRAILING-STOP] EUR_JPY BUY: INITIAL → BEP_TRIGGERED
含み益: +32pips (TP目標 +50pips の 64%)
SL変更: 149.500 → 150.005 (BEP + スプレッド)
TP解除: 150.500 → なし
[TRAILING-STOP] EUR_JPY BUY: BEP_TRIGGERED → TRAILING
含み益: +41pips (82%)
SL変更: 150.005 → 150.210 (追随開始)
monitor統合
既存のポジション監視モジュール(monitor)に状態機械を統合した。monitorは一定間隔でポジションを監視するループ処理で、各ループで以下を実行する。
- 現在の状態を確認
- 遷移条件を判定
- 条件を満たせば状態遷移 + SL/TP変更のAPIリクエスト
- ログ出力
バックテストでの効果
検証結果
トレーリングストップの有無でバックテスト結果を比較した。
| 指標 | 固定TP/SL | トレーリングストップ |
|---|---|---|
| 平均利益 | +20pips | +35pips |
| 勝率 | 63% | 58% |
| RR比 | 0.8 | 1.4 |
| シャープ比 | 0.72 | 0.95 |
| 最大DD | -12% | -10% |
勝率は若干下がるが(TPを外す分、反転での決済が増える)、1トレードあたりの平均利益が大幅に改善する。結果としてシャープ比が向上し、リスクあたりのリターンが改善した。
学んだこと
1. 「利益を伸ばす」は心理的に難しいことをシステムが解決する
裁量トレードでは「含み益が出ると早く確定したくなる」のが人間の心理だ(プロスペクト理論の損失回避バイアス)。状態機械で機械的にTPを解除し、追随に切り替えることで、心理的なバイアスを排除できる。
2. 状態機械は複雑な条件分岐をシンプルにする
if-elseの入れ子で書くと、状態の組み合わせ爆発でバグが生まれやすい。状態機械にすることで「現在の状態」と「遷移条件」が明確になり、テストも書きやすくなる(92テスト全PASS)。
3. パラメータは感覚ではなくグリッドサーチで決める
BEPトリガー60%、追随開始80%——これらの値は「なんとなく」で決めたのではなく、バックテストのグリッドサーチで最適化した結果だ。感覚で決めたパラメータは運用中に自信が持てなくなるが、データに裏付けられた値は精神的な安定感が違う。
まとめ
トレーリングストップの設計で重要なのは以下の3点だ。
- 状態機械で管理: INITIAL → BEP_TRIGGERED → TRAILING の3状態。遷移条件が明確でバグが少ない
- ATRベースの追随幅: ボラティリティに応じた適切な距離感を自動設定
- BEP確保 → 利益追随の2段階: まず損失ゼロを確保し、その後にトレンド追随で利益を伸ばす
固定TPでは「相場がどこまで動くか」を予測する必要がある。トレーリングストップは「予測しない」設計だ。トレンドが続く限り追随し、終わったら利益を確定する。この「予測を放棄する」発想が、実は最も合理的なポジション管理だと学んだ。