Открыть на GitHub

Стратегия JS MA SAR Trades

JS MA SAR Trades — это конвертация советника MetaTrader 5 «JS MA SAR Trades» на высокоуровневый API StockSharp. Стратегия ищет последовательности более высоких минимумов или более низких максимумов через упрощённый ZigZag, подтверждает импульс двумя скользящими средними и входит в сделку при пробое уровня Parabolic SAR. Позиции защищаются классическим стоп-лоссом, тейк-профитом, опциональным трейлинг-стопом и торговой сессией по времени.

Логика работы

  1. Структура свингов. Индикаторы Highest/Lowest с заданной глубиной повторяют поведение ZigZag. Хранятся последние два минимума и два максимума. Для покупки требуется, чтобы текущий минимум был выше предыдущего. Для продажи — последний максимум должен быть ниже предыдущего. Порог отклонения (в пунктах) и минимальный backstep (количество баров между пивотами) отсеивают шумовые развороты.
  2. Подтверждение скользящими средними. Обе средние используют один тип сглаживания и источник цены, совпадающие с оригиналом MT5, включая положительные сдвиги по барам. Для лонга сдвинутая быстрая средняя должна быть выше медленной; для шорта — наоборот.
  3. Триггер Parabolic SAR. После выполнения условий по свингам и средним сделка открывается только если свеча закрылась за уровнем SAR (выше — для лонга, ниже — для шорта). Переворот SAR закрывает текущую позицию даже вне торгового окна.
  4. Управление риском. Стоп-лосс и тейк-профит считаются в пунктах (пересчитываются через PriceStep). Трейлинг-стоп повторяет MT5: стоп переносится лишь после прохождения ценой расстояния TrailingStop + TrailingStep от цены входа.
  5. Временной фильтр. При включении заявки разрешены только между стартовым и конечным часами (включительно). Защитные проверки (стопы, трейлинг, переворот SAR) выполняются на каждой закрытой свече.

Правила входа и выхода

  • Вход в лонг: новый минимум выше предыдущего, SAR ниже цены закрытия, быстрая MA (со сдвигом) выше медленной, время внутри окна. Открывается объём OrderVolume + |Position|, чтобы закрыть шорт и открыть лонг.
  • Вход в шорт: новый максимум ниже предыдущего, SAR выше закрытия, быстрая MA ниже медленной, временной фильтр выполнен.
  • Выход из лонга:
    • Цена закрытия пересекает SAR сверху вниз;
    • Достигается стоп-лосс, трейлинг-стоп или тейк-профит.
  • Выход из шорта:
    • Цена закрытия пересекает SAR снизу вверх;
    • Срабатывает стоп-лосс, трейлинг-стоп или тейк-профит.

Параметры

Параметр Значение по умолчанию Описание
OrderVolume 1 Базовый объём заявки; к нему добавляется абсолютное значение текущей позиции при развороте.
StopLossPips 50 Расстояние от цены входа до стоп-лосса в пунктах (0 — отключить).
TakeProfitPips 50 Расстояние до тейк-профита в пунктах (0 — отключить).
TrailingStopPips 5 Дистанция трейлинг-стопа в пунктах. Работает вместе с TrailingStepPips.
TrailingStepPips 5 Дополнительный путь цены (в пунктах) для подтягивания трейлинг-стопа. Должен быть > 0 при включённом трейлинге.
UseTimeFilter true Включить торговое окно по времени.
StartHour 19 Начало торговой сессии (включительно, биржевое время).
EndHour 22 Окончание сессии (включительно).
FastMaPeriod 55 Период быстрой скользящей средней.
FastMaShift 3 Сдвиг (в барах) для быстрой средней.
SlowMaPeriod 120 Период медленной скользящей средней.
SlowMaShift 0 Сдвиг (в барах) для медленной средней.
MaType Smoothed Тип сглаживания (Simple, Exponential, Smoothed, Weighted).
AppliedPrice Median Источник цены (Close, Open, High, Low, Median, Typical, Weighted).
SarStep 0.02 Начальный коэффициент ускорения Parabolic SAR.
SarMax 0.2 Максимальный коэффициент ускорения Parabolic SAR.
ZigZagDepth 12 Глубина анализа свингов (количество баров).
ZigZagDeviation 5 Минимальная амплитуда разворота в пунктах.
ZigZagBackstep 3 Минимум баров между последовательными пивотами одного типа.
CandleType H1 Таймфрейм свечей.

Дополнительно

  • Защитные условия действуют всегда, поэтому позиции закрываются при стопах и развороте SAR даже вне торгового окна.
  • Логика трейлинг-стопа соответствует версии MT5: после движения на TrailingStop + TrailingStep стоп переносится к Close - TrailingStop (для шорта зеркально).
  • Скользящие средние считают выбранный источник цены, а сдвиг воспроизводит горизонтальное смещение индикатора в MT5.
  • Если у инструмента отсутствует корректный PriceStep, уровни в пунктах не будут рассчитаны.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// JS MA SAR Trades strategy. Uses EMA crossover (8/21).
/// </summary>
public class JsMaSarTradesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public JsMaSarTradesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}