Стратегия представляет собой перенос экспертного советника MetaTrader «PSAR Trader EA» на платформу StockSharp. Алгоритм отслеживает взаимодействие цены со значениями индикатора Parabolic SAR и реагирует только в момент смены положения точек относительно тела свечи. В переносе сохранена оригинальная логика управления капиталом: можно торговать фиксированным объёмом или автоматически пересчитывать лот в зависимости от баланса, используются фиксированные уровни стоп-лосса и тейк-профита, а также подключается трейлинг-стоп после накопления заданной прибыли.
Логика входа и выхода
Строится Parabolic SAR с пользовательскими параметрами ускорения и максимального ускорения на выбранном таймфрейме (по умолчанию 30-минутные свечи).
Бычий разворот фиксируется, когда точки SAR переходят из области над свечой под свечу. Если позиция отсутствует — открывается покупка. Если есть короткая позиция — сначала закрываем шорт и ждём следующего сигнала для входа в лонг.
Медвежий разворот фиксируется при переходе точек SAR из-под свечи наверх. При отсутствии позиции открывается шорт. Если есть лонг — позиция закрывается, а вход выполняется только после следующего сигнала.
На каждой закрытой свече контролируются открытые сделки: если текущий максимум или минимум достигает защитных уровней (стоп, тейк или трейлинг), позиция закрывается полностью.
Управление рисками
Стоп-лосс задаётся в пунктах (ценовых шагах). Для покупок стоп устанавливается ниже цены входа, для продаж — выше.
Тейк-профит также задаётся в пунктах. Уровень зеркально отражает стоп-лосс в противоположную сторону и закрывает позицию при достижении.
Трейлинг-стоп активируется после прохождения ценой заданного расстояния в прибыль. Стоп подтягивается только в сторону прибыли, что воспроизводит режим «только ужесточать стопы» из оригинального советника.
Управление объёмом
Фиксированный лот — при отключенном авто-лоте заявки отправляются с заданным объёмом.
Автолотовый режим — при включении параметра объём рассчитывается как (Баланс / 1000) * LotsPerThousand, затем приводится к шагу объёма и минимальному лоту инструмента.
Параметры и значения по умолчанию
SarStep — шаг ускорения Parabolic SAR. По умолчанию 0.02.
SarMaximum — максимальное ускорение Parabolic SAR. По умолчанию 0.2.
CandleType — таймфрейм анализа. По умолчанию 30-минутные свечи.
UseAutoLot — включение авто-расчёта объёма. По умолчанию false.
FixedLot — объём заявки при отключённом авто-лоте. По умолчанию 0.1.
LotsPerThousand — множитель для расчёта авто-лота. По умолчанию 0.05.
StopLossPoints — расстояние до стоп-лосса в пунктах. По умолчанию 500.
TakeProfitPoints — расстояние до тейк-профита в пунктах. По умолчанию 1000.
TrailingStartPoints — порог прибыли для запуска трейлинг-стопа. По умолчанию 500.
TrailingDistancePoints — расстояние трейлинга после активации. По умолчанию 100.
Дополнительные замечания
Стратегия работает как в лонг, так и в шорт, но удерживает не более одной позиции одновременно.
Защитные уровни контролируются по закрытым свечам. На реальном рынке внутрисвечные всплески меньше выбранного таймфрейма могут влиять на точность исполнения.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR Cross strategy: PSAR crossover.
/// Buys when close crosses above PSAR. Sells when close crosses below PSAR.
/// </summary>
public class ParabolicSarCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ParabolicSarCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sar = new ParabolicSar { Acceleration = 0.02m, AccelerationStep = 0.02m, AccelerationMax = 0.2m };
decimal? prevSar = null;
decimal? prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sar, (candle, sarVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevSar.HasValue && prevClose.HasValue)
{
var crossUp = prevClose.Value <= prevSar.Value && close > sarVal;
var crossDown = prevClose.Value >= prevSar.Value && close < sarVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevSar = sarVal;
prevClose = close;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class parabolic_sar_cross_strategy(Strategy):
def __init__(self):
super(parabolic_sar_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(parabolic_sar_cross_strategy, self).OnReseted()
self._prev_sar = None
self._prev_close = None
def OnStarted2(self, time):
super(parabolic_sar_cross_strategy, self).OnStarted2(time)
self._prev_sar = None
self._prev_close = None
sar = ParabolicSar()
sar.Acceleration = 0.02
sar.AccelerationStep = 0.02
sar.AccelerationMax = 0.2
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sar, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sar_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if self._prev_sar is not None and self._prev_close is not None:
cross_up = self._prev_close <= self._prev_sar and close > sar_val
cross_down = self._prev_close >= self._prev_sar and close < sar_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_sar = sar_val
self._prev_close = close
def CreateClone(self):
return parabolic_sar_cross_strategy()