Стратегия "10 Pips"
Хеджирующая стратегия одновременно открывает длинную и короткую позиции. Для каждой позиции задаются фиксированные уровни тейк-профита и стоп-лосса в ценовых пунктах, а также возможна защита трейлинг-стопом. При закрытии одной из позиций стратегия немедленно открывает новую в том же направлении, поддерживая обе стороны активными.
Параметры
TakeProfitBuy– расстояние тейк-профита для длинных позиций.StopLossBuy– расстояние стоп-лосса для длинных позиций.TrailingStopBuy– расстояние трейлинг-стопа для длинных позиций.TakeProfitSell– расстояние тейк-профита для коротких позиций.StopLossSell– расстояние стоп-лосса для коротких позиций.TrailingStopSell– расстояние трейлинг-стопа для коротких позиций.Volume– объём заявок.
Особенности
- Открытие позиций происходит рыночными заявками.
- Защитные заявки регистрируются отдельно для каждого направления.
- Трейлинг-стоп переносится при движении цены в прибыльную сторону.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simple breakout strategy that enters on momentum moves
/// with fixed take profit and stop loss protection.
/// </summary>
public class TenPipsStrategy : Strategy
{
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _previousRoc;
private bool _hasPreviousRoc;
/// <summary>Take profit distance.</summary>
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
/// <summary>Stop loss distance.</summary>
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
/// <summary>Lookback period for momentum.</summary>
public int Lookback { get => _lookback.Value; set => _lookback.Value = value; }
/// <summary>Candle type.</summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public TenPipsStrategy()
{
_takeProfit = Param(nameof(TakeProfit), 500m)
.SetDisplay("Take Profit", "Take profit distance", "Risk")
.SetGreaterThanZero();
_stopLoss = Param(nameof(StopLoss), 300m)
.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
.SetGreaterThanZero();
_lookback = Param(nameof(Lookback), 30)
.SetDisplay("Lookback", "Momentum lookback period", "Indicators")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_previousRoc = 0m;
_hasPreviousRoc = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_previousRoc = 0m;
_hasPreviousRoc = false;
var roc = new RateOfChange { Length = Lookback };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(roc, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, roc);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rocValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var buySignal = _hasPreviousRoc && _previousRoc <= 4m && rocValue > 4m;
var sellSignal = _hasPreviousRoc && _previousRoc >= -4m && rocValue < -4m;
if (Position == 0)
{
if (buySignal)
{
BuyMarket();
_entryPrice = close;
}
else if (sellSignal)
{
SellMarket();
_entryPrice = close;
}
}
else if (Position > 0)
{
if (close >= _entryPrice + TakeProfit || close <= _entryPrice - StopLoss)
{
SellMarket(Math.Abs(Position));
}
}
else if (Position < 0)
{
if (close <= _entryPrice - TakeProfit || close >= _entryPrice + StopLoss)
{
BuyMarket(Math.Abs(Position));
}
}
_previousRoc = rocValue;
_hasPreviousRoc = true;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RateOfChange
from StockSharp.Algo.Strategies import Strategy
class ten_pips_strategy(Strategy):
def __init__(self):
super(ten_pips_strategy, self).__init__()
self._take_profit = self.Param("TakeProfit", 500.0)
self._stop_loss = self.Param("StopLoss", 300.0)
self._lookback = self.Param("Lookback", 30)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._entry_price = 0.0
self._previous_roc = 0.0
self._has_previous_roc = False
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def Lookback(self):
return self._lookback.Value
@Lookback.setter
def Lookback(self, value):
self._lookback.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ten_pips_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._previous_roc = 0.0
self._has_previous_roc = False
roc = RateOfChange()
roc.Length = self.Lookback
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(roc, self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle, roc_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
roc_val = float(roc_value)
buy_signal = self._has_previous_roc and self._previous_roc <= 4.0 and roc_val > 4.0
sell_signal = self._has_previous_roc and self._previous_roc >= -4.0 and roc_val < -4.0
tp = float(self.TakeProfit)
sl = float(self.StopLoss)
if self.Position == 0:
if buy_signal:
self.BuyMarket()
self._entry_price = close
elif sell_signal:
self.SellMarket()
self._entry_price = close
elif self.Position > 0:
if close >= self._entry_price + tp or close <= self._entry_price - sl:
self.SellMarket()
elif self.Position < 0:
if close <= self._entry_price - tp or close >= self._entry_price + sl:
self.BuyMarket()
self._previous_roc = roc_val
self._has_previous_roc = True
def OnReseted(self):
super(ten_pips_strategy, self).OnReseted()
self._entry_price = 0.0
self._previous_roc = 0.0
self._has_previous_roc = False
def CreateClone(self):
return ten_pips_strategy()