【Python】損切り・リスク管理の自動化|トレーリングストップの実装
「エントリーはできるようになった。でも損切りどうすれば...」
自動売買で最も重要なのはリスク管理です。
どんなに優秀なエントリーロジックでも、損切りが適切でなければ一発退場もありえます。
この記事では、Pythonで損切り・利確を自動化する方法を解説します。
損切りの種類
| 種類 | 説明 | メリット | デメリット |
|---|---|---|---|
| 固定損切り | エントリー価格から一定pips | シンプル | 相場のボラに合わない |
| トレーリングストップ | 利益方向に追従 | 利益を伸ばせる | 設定が難しい |
| ブレイクイーブン | 一定利益で損切りを建値に | 負けをゼロに | 早期決済されやすい |
| ATRベース | ボラティリティに応じて調整 | 相場に適応 | 計算が複雑 |
1. 固定損切り
最もシンプル。エントリー価格から30pipsなど固定。
GMOコインでの実装
GMOコインの外国為替FX APIでは、注文時に損切り(losscutPrice)を指定できます。
def place_order_with_stoploss(symbol, side, size, stoploss_pips=30): """ 損切り付き成行注文
Args: symbol: 通貨ペア side: "BUY" または "SELL" size: 注文数量 stoploss_pips: 損切り幅(pips) """ # 現在価格を取得 ticker = get_ticker(symbol) current_price = float(ticker["ask"]) if side == "BUY" else float(ticker["bid"])
# 損切り価格を計算 if side == "BUY": stoploss_price = current_price - (stoploss_pips * 0.01) # ドル円の場合 else: stoploss_price = current_price + (stoploss_pips * 0.01)
# 注文 body = { "symbol": symbol, "side": side, "executionType": "MARKET", "size": str(size), "timeInForce": "FAK", "losscutPrice": str(round(stoploss_price, 3)) # 損切り価格 }
result = private_request("POST", "/v1/order", body)
if result["status"] == 0: print(f"✅ 注文成功: {side} @ {current_price}") print(f" 損切り: {stoploss_price}") return result["data"] else: print(f"❌ エラー: {result}") return None2. トレーリングストップ
価格が有利な方向に動いたら、損切りラインも追従させる。
仕組み
- エントリー: 150.00円で買い、損切り149.70円(-30pips)
- 価格が150.50円に上昇 → 損切りを150.20円に引き上げ
- 価格が151.00円に上昇 → 損切りを150.70円に引き上げ
- 価格が150.50円に下落 → 損切りは150.70円のまま(下げない)
- 150.70円に到達 → 決済(+70pips利益確定)
実装
class TrailingStopManager: """トレーリングストップ管理クラス"""
def __init__(self, trailing_pips=30): self.trailing_pips = trailing_pips self.positions = {} # {position_id: {"side": "BUY", "highest": 150.00, "stoploss": 149.70}}
def register_position(self, position_id, side, entry_price): """新規ポジションを登録""" if side == "BUY": stoploss = entry_price - (self.trailing_pips * 0.01) self.positions[position_id] = { "side": side, "entry": entry_price, "highest": entry_price, "stoploss": stoploss } else: # SELL stoploss = entry_price + (self.trailing_pips * 0.01) self.positions[position_id] = { "side": side, "entry": entry_price, "lowest": entry_price, "stoploss": stoploss }
print(f"📝 ポジション登録: {position_id}") print(f" {side} @ {entry_price}, SL: {stoploss}")
def update(self, position_id, current_price): """ 価格更新時にトレーリングストップを調整
Returns: True: 損切りに到達(決済すべき) False: 継続 """ if position_id not in self.positions: return False
pos = self.positions[position_id]
if pos["side"] == "BUY": # 高値更新したらストップを引き上げ if current_price > pos["highest"]: pos["highest"] = current_price new_stoploss = current_price - (self.trailing_pips * 0.01)
if new_stoploss > pos["stoploss"]: print(f"📈 トレーリング更新: SL {pos['stoploss']:.3f} → {new_stoploss:.3f}") pos["stoploss"] = new_stoploss
# 損切りチェック if current_price <= pos["stoploss"]: print(f"🔴 損切り到達: {current_price} <= {pos['stoploss']}") return True
else: # SELL # 安値更新したらストップを引き下げ if current_price < pos["lowest"]: pos["lowest"] = current_price new_stoploss = current_price + (self.trailing_pips * 0.01)
if new_stoploss < pos["stoploss"]: print(f"📉 トレーリング更新: SL {pos['stoploss']:.3f} → {new_stoploss:.3f}") pos["stoploss"] = new_stoploss
# 損切りチェック if current_price >= pos["stoploss"]: print(f"🔴 損切り到達: {current_price} >= {pos['stoploss']}") return True
return False
def remove_position(self, position_id): """ポジション削除""" if position_id in self.positions: del self.positions[position_id]使用例
# 初期化trailing_manager = TrailingStopManager(trailing_pips=30)
# エントリー時position_id = place_order("USD_JPY", "BUY", 100)trailing_manager.register_position(position_id, "BUY", 150.00)
# メインループ内で定期的に更新while True: current_price = float(get_ticker("USD_JPY")["bid"])
for pos_id in list(trailing_manager.positions.keys()): if trailing_manager.update(pos_id, current_price): # 損切り到達 → 決済 close_position(pos_id) trailing_manager.remove_position(pos_id)
time.sleep(1)3. ブレイクイーブン(建値決済)
一定の利益が出たら、損切りラインを建値(エントリー価格)に移動。
これで「負けをゼロにする」ことができます。
class BreakevenManager: """ブレイクイーブン管理"""
def __init__(self, trigger_pips=20, buffer_pips=2): """ Args: trigger_pips: 何pips利益が出たらブレイクイーブンに移動するか buffer_pips: 建値からさらに何pipsバッファを持たせるか """ self.trigger_pips = trigger_pips self.buffer_pips = buffer_pips self.positions = {}
def register_position(self, position_id, side, entry_price, initial_stoploss): self.positions[position_id] = { "side": side, "entry": entry_price, "stoploss": initial_stoploss, "breakeven_triggered": False }
def update(self, position_id, current_price): """ブレイクイーブンチェック""" if position_id not in self.positions: return False
pos = self.positions[position_id]
# すでにブレイクイーブン済みならスキップ if pos["breakeven_triggered"]: # 通常の損切りチェック if pos["side"] == "BUY" and current_price <= pos["stoploss"]: return True if pos["side"] == "SELL" and current_price >= pos["stoploss"]: return True return False
# ブレイクイーブントリガーチェック profit_pips = 0 if pos["side"] == "BUY": profit_pips = (current_price - pos["entry"]) * 100 else: profit_pips = (pos["entry"] - current_price) * 100
if profit_pips >= self.trigger_pips: # ブレイクイーブンに移動 if pos["side"] == "BUY": pos["stoploss"] = pos["entry"] + (self.buffer_pips * 0.01) else: pos["stoploss"] = pos["entry"] - (self.buffer_pips * 0.01)
pos["breakeven_triggered"] = True print(f"✅ ブレイクイーブン発動! SL → {pos['stoploss']:.3f}")
return False4. ATRベース損切り
ATR(Average True Range)を使って、相場のボラティリティに応じた損切り幅を設定。
ATRとは?
「平均的な1本のローソク足の値幅」を示す指標。ボラが高いと大きく、低いと小さくなります。
実装
import pandas_ta as ta
def calculate_atr_stoploss(df, atr_period=14, atr_multiplier=2.0): """ ATRベースの損切り幅を計算
Args: df: ローソク足データ(high, low, close必須) atr_period: ATR期間 atr_multiplier: ATRの何倍を損切り幅にするか
Returns: 損切り幅(価格単位) """ # ATRを計算 df["atr"] = ta.atr(df["high"], df["low"], df["close"], length=atr_period)
current_atr = df["atr"].iloc[-1] stoploss_distance = current_atr * atr_multiplier
print(f"ATR({atr_period}): {current_atr:.4f}") print(f"損切り幅: {stoploss_distance:.4f} ({atr_multiplier}倍)")
return stoploss_distance
def place_order_with_atr_stoploss(symbol, side, size, df, atr_multiplier=2.0): """ATRベースの損切り付き注文"""
# ATRから損切り幅を計算 stoploss_distance = calculate_atr_stoploss(df, atr_multiplier=atr_multiplier)
# 現在価格 ticker = get_ticker(symbol) current_price = float(ticker["ask"]) if side == "BUY" else float(ticker["bid"])
# 損切り価格 if side == "BUY": stoploss_price = current_price - stoploss_distance else: stoploss_price = current_price + stoploss_distance
print(f"エントリー: {current_price}") print(f"損切り: {stoploss_price} (ATR x {atr_multiplier})")
# 注文実行 # ...ATRの利点
- ボラティリティが高い時:損切り幅が広がる → ノイズで狩られにくい
- ボラティリティが低い時:損切り幅が狭まる → リスクを限定
5. 複合リスク管理
実際のボットでは、複数のリスク管理を組み合わせます。
class RiskManager: """統合リスク管理クラス"""
def __init__( self, max_daily_loss_pct=5.0, # 1日の最大損失率 max_positions=3, # 同時ポジション数 trailing_pips=30, # トレーリングストップ breakeven_trigger_pips=20 # ブレイクイーブントリガー ): self.max_daily_loss_pct = max_daily_loss_pct self.max_positions = max_positions self.trailing_pips = trailing_pips self.breakeven_trigger_pips = breakeven_trigger_pips
self.daily_pnl = 0.0 self.initial_balance = None self.positions = {}
def can_open_position(self): """新規ポジションを開けるかチェック"""
# 最大ポジション数チェック if len(self.positions) >= self.max_positions: print("⚠️ 最大ポジション数に達しています") return False
# 日次損失チェック if self.initial_balance: loss_pct = (self.daily_pnl / self.initial_balance) * 100 if loss_pct <= -self.max_daily_loss_pct: print(f"⚠️ 日次損失上限 ({self.max_daily_loss_pct}%) に達しました") return False
return True
def update_daily_pnl(self, pnl): """日次損益を更新""" self.daily_pnl += pnl print(f"📊 日次損益: {self.daily_pnl:+.2f}")
def reset_daily(self, current_balance): """日次リセット(毎日実行)""" self.daily_pnl = 0.0 self.initial_balance = current_balance print(f"🔄 日次リセット: 開始残高 {current_balance}")リスク管理のベストプラクティス
1. 1トレードあたりのリスクを限定
def calculate_position_size(balance, risk_pct, stoploss_pips): """ リスクベースのポジションサイズ計算
Args: balance: 口座残高 risk_pct: 1トレードでリスクにさらす割合(例: 2%) stoploss_pips: 損切り幅
Returns: 適切なポジションサイズ """ risk_amount = balance * (risk_pct / 100) pip_value = 100 # ドル円1万通貨の1pip = 100円(概算) lot_size = risk_amount / (stoploss_pips * pip_value)
return round(lot_size, 2)
# 例: 100万円口座、2%リスク、30pips損切りsize = calculate_position_size(1000000, 2.0, 30)# → 0.67ロット(6,700通貨)2. 相関のある通貨ペアに注意
ドル円とユーロ円を同時にロングすると、実質的にドル安リスクが2倍。
3. 週末・重要指標前のポジション
週末や重要指標(FOMC、雇用統計)前はポジションを閉じるか縮小。
まとめ
| 損切り手法 | 用途 |
|---|---|
| 固定損切り | シンプル、初心者向け |
| トレーリングストップ | 利益を伸ばしたい時 |
| ブレイクイーブン | 負けを減らしたい時 |
| ATRベース | ボラに適応したい時 |
最も重要なこと:損切りを設定しないトレードは絶対にしない。
エントリーより損切りの方が大事です。どんなに勝率が高くても、1回の大損で全てを失う可能性があります。
🎉 おめでとうございます!
これで10記事シリーズ完走です!
- MQL4/MT4でEAを作る方法
- Pythonでボットを作る方法
- クラウドで24時間稼働させる方法
- リスク管理の自動化
ここまで学んだあなたは、もう「業者のツールを選ぶだけ」の人ではありません。
自分でシステムを作れる人です。
これからも、自分だけの戦略を形にしていきましょう。応援しています! 🚀
🎁おすすめツール・サービス
※上記リンクにはプロモーション(広告)が含まれています
量子相場謀略|ホソノP
ブログでは書けない本音のトレード戦略とEA開発の裏側を公開。 データに基づいた検証で、再現性のある手法だけをお届けします。