Открыть на GitHub

Стратегия Freeman ATR MA RSI Grid

Общее описание

Стратегия переносит советника MetaTrader «freeman» на высокоуровневый API StockSharp. Она наращивает сетку рыночных позиций, пока направление, заданное наклоном скользящей средней, подтверждается фильтром RSI. Все расстояния до входов и выходов задаются в пунктах и автоматически переводятся в ценовые значения через минимальный шаг цены инструмента, что позволяет воспроизвести поведение оригинальной форекс-версии.

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

  1. Подписка на один поток свечей (настраиваемый таймфрейм) и обновление индикаторов ATR, MA и RSI на каждой закрытой свече.
  2. Формирование торгового сигнала при выполнении условий:
    • Наклон скользящей средней положительный или отрицательный по сравнению с предыдущей свечой (опциональный трендовый фильтр).
    • Цена находится на заданном расстоянии от скользящей средней, чтобы избежать входов непосредственно на линии.
    • RSI пересекает верхний или нижний порог, если включён фильтр RSI. Полностью сохранена оригинальная логика MetaTrader, включая особенность, когда сигнал на продажу возвращает -11, поэтому одновременное включение обоих фильтров приводит к преимущественному открытию длинных позиций.
  3. Соблюдение максимального количества одновременно открытых позиций. Дополнительные входы по направлению выполняются только если цена ушла против последней сделки на требуемое количество пунктов, что создаёт сетку усреднений.
  4. Каждая сделка получает стоп-лосс и тейк-профит, рассчитанные на основе ATR. Трейлинг-стоп подтягивает защитный уровень после прохождения ценой суммы «трейлинг + шаг трейлинга».
  5. Выход осуществляется рыночной встречной заявкой при достижении свечой стоп-уровня, цели или обновлённого трейлинг-стопа.

Управление рисками

  • Множители ATR определяют фиксированный стоп-лосс и тейк-профит. Значение 0 отключает соответствующий уровень.
  • Трейлинг-стоп настраивается двумя параметрами в пунктах: собственно расстоянием и дополнительным шагом перед очередным переносом стопа.
  • Для расчёта объёма используется базовое свойство Volume; автоматическое управление капиталом не применяется, кроме ограничения по количеству позиций.

Параметры

Название Описание
CandleType Таймфрейм свечей для расчёта индикаторов.
MaxPositions Максимальное суммарное количество открытых длинных и коротких позиций.
DistancePips Минимальное расстояние в пунктах между последовательными входами в одном направлении.
AtrPeriod Период усреднения индикатора ATR.
AtrStopLossMultiplier Множитель ATR для стоп-лосса. 0 отключает стоп.
AtrTakeProfitMultiplier Множитель ATR для тейк-профита. 0 отключает цель.
UseTrendFilter Включение трендового фильтра по скользящей средней.
DistanceFromMaPips Минимальное расстояние между ценой и MA при активном трендовом фильтре.
MaPeriod, MaShift, MaMethod, MaPriceType Настройки скользящей средней, соответствующие параметрам советника в MetaTrader.
UseRsiFilter Включение фильтра RSI.
RsiLevelUp, RsiLevelDown, RsiPeriod, RsiPriceType Параметры RSI и тип используемой цены.
TrailingStopPips, TrailingStepPips Расстояние и шаг трейлинг-стопа в пунктах.
CurrentBarOffset Смещение при чтении значений индикаторов, аналог параметра CurrentBar в советнике.

Примечания

  • Перевод пунктов в цену умножает PriceStep на 10 для инструментов с 3 или 5 знаками после запятой, что повторяет корректировку point→pip в MetaTrader.
  • Используется неттинговая модель: при появлении обратного сигнала текущая позиция закрывается и только потом открывается позиция нового направления.
  • В OnStarted активируется StartProtection, чтобы защитить открытую позицию от внезапных переподключений до начала торговли.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class FreemanAtrMaRsiGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _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 FreemanAtrMaRsiGridStrategy()
	{
		_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(); }
	}
}