Стратегия повторяет эксперт PZ Parabolic SAR. Она использует два индикатора Parabolic SAR с различными параметрами шага и максимального ускорения. "Торговый" SAR определяет направление тренда для входа, а "стоповый" SAR идёт ближе к цене и служит сигналом выхода при смене тренда.
Контроль риска реализуется через индикатор Average True Range (ATR). При открытии позиции рассчитывается первоначальный стоп на основе ATR. Опционально может включаться трейлинг‑стоп на основе ATR, который подтягивает защитный уровень при движении цены в прибыльную сторону. Также поддерживается частичное закрытие: когда прибыль превышает первоначальный стоп, половина позиции закрывается и стоп переносится в безубыток.
Стратегия работает как в длинную, так и в короткую сторону и обрабатывает только завершённые свечи. Используются рыночные заявки без установки реальных стоп‑заявок.
Детали
Условия входа: цена выше/ниже торгового SAR, а стоповый SAR показывает то же направление.
Позиции: длинные и короткие.
Условия выхода: пересечение цены со стоповым SAR или срабатывание ATR трейлинг‑стопа.
Стопы: стоп по ATR, опциональный трейлинг и безубыток.
Значения по умолчанию:
TradeStep = 0.002
TradeMax = 0.2
StopStep = 0.004
StopMax = 0.4
AtrPeriod = 30
AtrMultiplier = 2.5
UseTrailing = false
TrailingAtrPeriod = 30
TrailingAtrMultiplier = 1.75
PartialClosing = true
PercentageToClose = 0.5
BreakEven = true
LotSize = 0.1
CandleType = TimeFrame(5m)
Фильтры:
Категория: Trend
Направление: Оба
Индикаторы: Parabolic SAR, ATR
Стопы: ATR, Trailing
Сложность: Средняя
Таймфрейм: Внутридневной (5m)
Сезонность: Нет
Нейросети: Нет
Дивергенции: Нет
Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR crossover strategy.
/// </summary>
public class PzParabolicSarEaStrategy : Strategy
{
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMax;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevSar;
private bool _hasPrev;
public decimal SarStep { get => _sarStep.Value; set => _sarStep.Value = value; }
public decimal SarMax { get => _sarMax.Value; set => _sarMax.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public PzParabolicSarEaStrategy()
{
_sarStep = Param(nameof(SarStep), 0.02m)
.SetDisplay("SAR Step", "Acceleration step", "Indicators");
_sarMax = Param(nameof(SarMax), 0.2m)
.SetDisplay("SAR Max", "Maximum acceleration", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevSar = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sar = new ParabolicSar { AccelerationStep = SarStep, AccelerationMax = SarMax };
SubscribeCandles(CandleType)
.Bind(sar, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sarVal)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevClose = close;
_prevSar = sarVal;
_hasPrev = true;
return;
}
var crossUp = _prevClose <= _prevSar && close > sarVal;
var crossDown = _prevClose >= _prevSar && close < sarVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevClose = close;
_prevSar = sarVal;
}
}
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.Indicators import ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class pz_parabolic_sar_ea_strategy(Strategy):
def __init__(self):
super(pz_parabolic_sar_ea_strategy, self).__init__()
self._sar_step = self.Param("SarStep", 0.02) .SetDisplay("SAR Step", "Acceleration step", "Indicators")
self._sar_max = self.Param("SarMax", 0.2) .SetDisplay("SAR Max", "Maximum acceleration", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) .SetDisplay("Candle Type", "Candle type", "General")
self._prev_close = 0.0
self._prev_sar = 0.0
self._has_prev = False
@property
def sar_step(self):
return self._sar_step.Value
@property
def sar_max(self):
return self._sar_max.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pz_parabolic_sar_ea_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sar = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(pz_parabolic_sar_ea_strategy, self).OnStarted2(time)
sar = ParabolicSar()
sar.AccelerationStep = self.sar_step
sar.AccelerationMax = self.sar_max
self.SubscribeCandles(self.candle_type).Bind(sar, self.process_candle).Start()
def process_candle(self, candle, sar_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
sv = float(sar_val)
if not self._has_prev:
self._prev_close = close
self._prev_sar = sv
self._has_prev = True
return
cross_up = self._prev_close <= self._prev_sar and close > sv
cross_down = self._prev_close >= self._prev_sar and close < sv
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_sar = sv
def CreateClone(self):
return pz_parabolic_sar_ea_strategy()