Открыть на GitHub

Стратегия Forex Profit System

Стратегия переносит классический советник MetaTrader «Forex Profit System» в высокоуровневый API StockSharp. Она использует три экспоненциальные скользящие средние по медианной цене свечи (EMA 10, 25 и 50) вместе с фильтром Parabolic SAR. Такое сочетание позволяет ловить кратковременные импульсы, возникающие в момент, когда быстрая средняя пробивает медленную, а Parabolic SAR уже успел перейти на сторону нового тренда.

Логика торговли

  1. Индикаторы
    • Для всех индикаторов используется медианная цена завершённой свечи, что повторяет режим PRICE_MEDIAN в MetaTrader.
    • Быстрая EMA (10) реагирует на краткосрочный импульс.
    • Средняя EMA (25) и медленная EMA (50) задают фильтр направления.
    • Parabolic SAR со шагом 0.02 и максимумом 0.2 подтверждает факт пробоя цены.
  2. Вход в длинную позицию
    • EMA(10) выше EMA(25) и EMA(50).
    • На предыдущей закрытой свече EMA(10) находилась ниже EMA(50), то есть произошёл «пробой вверх».
    • Значение Parabolic SAR располагается ниже цены закрытия свечи.
    • Открытых позиций нет и торговля разрешена (стратегия подключена и не заблокирована по лимитам).
  3. Вход в короткую позицию
    • EMA(10) ниже EMA(25) и EMA(50).
    • На предыдущей свече EMA(10) была выше EMA(50) — подтверждение пробоя вниз.
    • Parabolic SAR расположен выше цены закрытия.
  4. Сопровождение позиции
    • Сразу после открытия выставляются жёсткие стоп-лосс и тейк-профит с отдельными настройками для покупок и продаж.
    • Как только цена проходит заданное расстояние в прибыльную сторону, включается трейлинг-стоп, подтягивающий защиту к текущей цене на фиксированное количество пунктов.
    • Дополнительный ранний выход происходит, если EMA(10) разворачивается в обратную сторону (для лонга — опускается ниже своего предыдущего значения, для шорта — поднимается выше), и накопленная прибыль превышает минимальный порог.

Значения параметров по умолчанию

Параметр Значение Описание
CandleType Таймфрейм 15 минут Тип свечей, которые обрабатывает стратегия.
FastEmaLength 10 Период быстрой EMA.
MediumEmaLength 25 Период средней EMA.
SlowEmaLength 50 Период медленной EMA.
SarStep 0.02 Начальный шаг Parabolic SAR.
SarMax 0.2 Максимальный шаг Parabolic SAR.
Volume 0.1 Торговый объём в лотах/контрактах.
LongTakeProfitPoints 50 Размер тейк-профита для покупок (в пунктах).
ShortTakeProfitPoints 50 Размер тейк-профита для продаж (в пунктах).
LongStopLossPoints 30 Размер стоп-лосса для покупок (в пунктах).
ShortStopLossPoints 30 Размер стоп-лосса для продаж (в пунктах).
LongTrailingStopPoints 10 Дистанция включения трейлинг-стопа для покупок.
ShortTrailingStopPoints 10 Дистанция включения трейлинг-стопа для продаж.
LongProfitTriggerPoints 10 Минимальная прибыль (в пунктах) для закрытия лонга по развороту EMA.
ShortProfitTriggerPoints 5 Минимальная прибыль (в пунктах) для закрытия шорта по развороту EMA.

Особенности реализации

  • Используются подписки на свечи и связывание индикаторов через высокоуровневый API StockSharp, что избавляет от необходимости работать с низкоуровневой книгой заявок.
  • Все дистанции управления риском переводятся из пунктов в реальные ценовые величины с помощью PriceStep. Если шаг цены не задан, стратегия применяет указанные значения напрямую, чтобы не терять работоспособность.
  • Защитные уровни (SetStopLoss, SetTakeProfit) выставляются на итоговую позицию, получающуюся после отправки рыночного ордера, что учитывает возможные частичные исполнения.
  • Хранится цена последнего входа по каждой стороне, благодаря чему трейлинг и выход по EMA рассчитывают фактический прогресс.
  • Обработка ведётся только на завершённых свечах, поэтому стратегия не «перерисовывается» и повторяет поведение исходного советника MetaTrader, работавшего в функции start().

Рекомендации по применению

  • Наиболее комфортно стратегия работает на ликвидных валютных парах во внутридневном режиме (базовый таймфрейм — 15 минут).
  • Для инструментов с иным шагом цены или волатильностью подберите подходящие значения пунктовых параметров (StopLoss, TakeProfit, TrailingStop, ProfitTrigger).
  • При работе на площадках с расширяющимся спредом рассмотрите добавление фильтров по сессиям или спреду: стратегия ориентирована на относительно узкий спред и быстрое исполнение.
using System;



using StockSharp.Algo.Indicators;

using StockSharp.Algo.Strategies;

using StockSharp.BusinessEntities;

using StockSharp.Messages;



namespace StockSharp.Samples.Strategies;



public class ForexProfitSystemStrategy : Strategy

{

	private readonly StrategyParam<int> _fastPeriod;

	private readonly StrategyParam<int> _slowPeriod;

	private readonly StrategyParam<DataType> _candleType;



	private decimal _prevFast; private decimal _prevSlow; private bool _hasPrev;

	private int _cooldown;



	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }

	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }



	public ForexProfitSystemStrategy()

	{

		_fastPeriod = Param(nameof(FastPeriod), 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 25).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");

	}



	/// <inheritdoc />

	protected override void OnReseted()

	{

		base.OnReseted();

		_prevFast = default;

		_prevSlow = default;

		_hasPrev = default;

		_cooldown = default;

	}



	/// <inheritdoc />

	protected override void OnStarted2(DateTime time)

	{

		base.OnStarted2(time);

		_hasPrev = false;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };

		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);

		subscription.Bind(fast, slow, ProcessCandle).Start();

	}



	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)

	{

		if (candle.State != CandleStates.Finished) return;

		if (!IsFormedAndOnlineAndAllowTrading()) return;

		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldown > 0)

		{

			_cooldown--;

			_prevFast = fast; _prevSlow = slow;

			return;

		}



		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)

		{

			var volume = Volume + Math.Abs(Position);

			BuyMarket(volume);

			_cooldown = 2;

		}

		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)

		{

			var volume = Volume + Math.Abs(Position);

			SellMarket(volume);

			_cooldown = 2;

		}

		_prevFast = fast; _prevSlow = slow;

	}

}