ホーム
/
戦略のサンプル
GitHub で見る
ストップロス・テイクプロフィット戦略
このポートは MetaTrader のエキスパートアドバイザー「Stop Loss Take Profit」を複製します。戦略は口座がフラットのときにコインを投げ、選択した方向に成行注文をオープンします。各ポジションはすぐに pip ベースのストップロスとテイクプロフィット注文を受け取ります。ストップにヒットした場合、次のトレードはそのサイズを倍増させます(有価証券のボリューム制限によって制限される)。テイクプロフィットはボリュームを初期量にリセットします。このふるまいは StockSharp の高レベル API を使用しながら、元のマーチンゲール スタイルのポジションサイジングを反映します。
取引ロジック
市場データ : CandleType パラメーター(デフォルト:1 分足時間軸)を使用して意思決定ポイントを駆動します。
エントリールール :
Position == 0 でエントリー注文が保留中でない場合、戦略は疑似ランダムなブール値を生成します。
true は BuyMarket(volume) でロングポジションをオープンします;false は SellMarket(volume) でショートをオープンします。
エグジットルール :
保護的なストップロスとテイクプロフィット注文は、エントリーのフィルが受け取られるとすぐに配置されます。
ストップ出口は次のトレードのサイズを倍増させ、テイクプロフィットはそれをリセットします。
ストップまたはテイクプロフィットの距離が 0 に設定されている場合、それぞれの保護注文はスキップされます。
マネー管理 :
InitialVolume はベース注文サイズを定義します。
損失トレードの後、サイズは倍増しますが、その値が利用可能な場合は Security.MaxVolume に切り取られます。
ボリュームは注文が有効なままになるよう商品の VolumeStep、MinVolume、MaxVolume に正規化されます。
Pip 処理 :
デフォルトでは、戦略は商品の PriceStep と Decimals から pip を推測します(5 桁の FX シンボルは 0.0001 にマップされます)。
自動 pip サイズ検出を上書きするには PipSize を正の値に設定します。
パラメーター
名前
デフォルト
説明
CandleType
1 分ローソク足
コイン投げとエントリーに使用される時間軸。
StopLossPips
1
pips で表現されたストップロス距離。0 でストップを無効化。
TakeProfitPips
1
pips で表現されたテイクプロフィット距離。0 でテイクプロフィットを無効化。
InitialVolume
0.01
開始取引ボリューム。ストップロスイベント後に倍増、勝利後にリセット。
PipSize
0 (自動)
絶対価格単位でのオプション pip サイズ上書き。
使用上の注意
ロングとショートの両サイドで機能し、意図的に方向中立です。
保護注文はポジションがクローズされるたびにキャンセルされ、古い注文を避けます。
ランダムジェネレーターは Environment.TickCount でシードされます。つまり、各セッションは異なるトレードシーケンスを生成します。
追加のリスクコントロールなしに本番取引のためではなく、リスクレイヤリングとマーチンゲール行動のデモンストレーションに適しています。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Random direction strategy with pip-based stop loss and take profit that doubles the volume after losses.
/// </summary>
public class StopLossTakeProfitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossDistance;
private readonly StrategyParam<decimal> _takeProfitDistance;
private readonly StrategyParam<decimal> _initialVolume;
private decimal _currentVolume;
private decimal _entryPrice;
private int _tradeCount;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal StopLossDistance
{
get => _stopLossDistance.Value;
set => _stopLossDistance.Value = value;
}
public decimal TakeProfitDistance
{
get => _takeProfitDistance.Value;
set => _takeProfitDistance.Value = value;
}
public decimal InitialVolume
{
get => _initialVolume.Value;
set => _initialVolume.Value = value;
}
public StopLossTakeProfitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for evaluating entries", "General");
_stopLossDistance = Param(nameof(StopLossDistance), 5m)
.SetDisplay("Stop Loss Distance", "Stop loss distance in price units", "Risk");
_takeProfitDistance = Param(nameof(TakeProfitDistance), 5m)
.SetDisplay("Take Profit Distance", "Take profit distance in price units", "Risk");
_initialVolume = Param(nameof(InitialVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Initial Volume", "Starting order volume", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_currentVolume = 0;
_entryPrice = 0;
_tradeCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_currentVolume = InitialVolume;
_entryPrice = 0m;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Check SL/TP for open position
if (Position != 0 && _entryPrice > 0)
{
if (Position > 0)
{
var hitStop = StopLossDistance > 0 && candle.LowPrice <= _entryPrice - StopLossDistance;
var hitTake = TakeProfitDistance > 0 && candle.HighPrice >= _entryPrice + TakeProfitDistance;
if (hitStop)
{
SellMarket();
HandleStopLoss();
return;
}
if (hitTake)
{
SellMarket();
HandleTakeProfit();
return;
}
}
else if (Position < 0)
{
var hitStop = StopLossDistance > 0 && candle.HighPrice >= _entryPrice + StopLossDistance;
var hitTake = TakeProfitDistance > 0 && candle.LowPrice <= _entryPrice - TakeProfitDistance;
if (hitStop)
{
BuyMarket();
HandleStopLoss();
return;
}
if (hitTake)
{
BuyMarket();
HandleTakeProfit();
return;
}
}
}
// Enter new position when flat
if (Position == 0)
{
_tradeCount++;
// Use candle direction as a deterministic signal
if (candle.ClosePrice < candle.OpenPrice)
{
SellMarket();
}
else
{
BuyMarket();
}
_entryPrice = candle.ClosePrice;
}
}
private void HandleStopLoss()
{
// Double volume on loss (martingale)
_currentVolume *= 2m;
var maxVol = Security?.MaxVolume;
if (maxVol.HasValue && maxVol.Value > 0 && _currentVolume > maxVol.Value)
_currentVolume = maxVol.Value;
Volume = _currentVolume;
_entryPrice = 0m;
}
private void HandleTakeProfit()
{
// Reset volume on profit
_currentVolume = InitialVolume;
Volume = _currentVolume;
_entryPrice = 0m;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class stop_loss_take_profit_strategy(Strategy):
"""Candle-direction entries with pip-based SL/TP and martingale volume doubling on losses."""
def __init__(self):
super(stop_loss_take_profit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for evaluating entries", "General")
self._stop_loss_distance = self.Param("StopLossDistance", 5.0) \
.SetDisplay("Stop Loss Distance", "Stop loss distance in price units", "Risk")
self._take_profit_distance = self.Param("TakeProfitDistance", 5.0) \
.SetDisplay("Take Profit Distance", "Take profit distance in price units", "Risk")
self._initial_volume = self.Param("InitialVolume", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Initial Volume", "Starting order volume", "Risk")
self._current_volume = 0.0
self._entry_price = 0.0
self._trade_count = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def StopLossDistance(self):
return self._stop_loss_distance.Value
@property
def TakeProfitDistance(self):
return self._take_profit_distance.Value
@property
def InitialVolume(self):
return self._initial_volume.Value
def OnStarted2(self, time):
super(stop_loss_take_profit_strategy, self).OnStarted2(time)
self._current_volume = float(self.InitialVolume)
self._entry_price = 0.0
self._trade_count = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
sl = float(self.StopLossDistance)
tp = float(self.TakeProfitDistance)
# Check SL/TP for open position
if self.Position != 0 and self._entry_price > 0:
if self.Position > 0:
hit_stop = sl > 0 and float(candle.LowPrice) <= self._entry_price - sl
hit_take = tp > 0 and float(candle.HighPrice) >= self._entry_price + tp
if hit_stop:
self.SellMarket()
self._handle_stop_loss()
return
if hit_take:
self.SellMarket()
self._handle_take_profit()
return
elif self.Position < 0:
hit_stop = sl > 0 and float(candle.HighPrice) >= self._entry_price + sl
hit_take = tp > 0 and float(candle.LowPrice) <= self._entry_price - tp
if hit_stop:
self.BuyMarket()
self._handle_stop_loss()
return
if hit_take:
self.BuyMarket()
self._handle_take_profit()
return
# Enter new position when flat
if self.Position == 0:
self._trade_count += 1
close = float(candle.ClosePrice)
o = float(candle.OpenPrice)
if close < o:
self.SellMarket()
else:
self.BuyMarket()
self._entry_price = close
def _handle_stop_loss(self):
self._current_volume *= 2.0
self._entry_price = 0.0
def _handle_take_profit(self):
self._current_volume = float(self.InitialVolume)
self._entry_price = 0.0
def OnReseted(self):
super(stop_loss_take_profit_strategy, self).OnReseted()
self._current_volume = 0.0
self._entry_price = 0.0
self._trade_count = 0
def CreateClone(self):
return stop_loss_take_profit_strategy()