Открыть на GitHub

Стратегия Two MA One RSI

Эта стратегия переносит советник MetaTrader 5 «Two MA one RSI» на платформу StockSharp. Используется пересечение быстрой и медленной скользящих средних, подтверждённое значением RSI на предыдущей закрытой свече. Набор булевых параметров позволяет быстро инвертировать каждое сравнение без правок кода.

Подробности

  • Условия входа:
    • Для покупок требуется, чтобы две свечи назад быстрая MA находилась ниже медленной, на последней закрытой свече — выше, а RSI предыдущей свечи оказался выше верхнего уровня. Любое сравнение можно инвертировать соответствующим флагом.
    • Продажи зеркально проверяют обратные отношения скользящих средних и падение RSI ниже нижней границы.
    • Обе MA используют один тип сглаживания; период медленной всегда равен FastMaPeriod * SlowPeriodMultiplier. Дополнительные сдвиги по горизонтали полностью повторяют MT5-логику чтения значений несколько баров назад.
  • Направление: Торговля ведётся в обе стороны. Параметр CloseOppositePositions задаёт, нужно ли закрывать противоположную позицию перед открытием новой сделки.
  • Условия выхода:
    • Фиксированный стоп-лосс и тейк-профит в пипсах.
    • Опциональный трейлинг, который переносит стоп только после движения минимум на TrailingStopPips + TrailingStepPips от цены входа.
    • ProfitClose отслеживает плавающий результат (через стоимость шага цены) и закрывает все позиции при достижении целевой прибыли в валюте счёта.
  • Стопы: Если StopLossPips = 0, стратегия опирается исключительно на модуль трейлинг-стопа. При включённом трейлинге обязательно положительное значение TrailingStepPips, как и в оригинальном советнике.
  • Параметры по умолчанию:
    • FastMaPeriod = 10, SlowPeriodMultiplier = 2.
    • FastMaShift = 3, SlowMaShift = 0.
    • RsiPeriod = 10, RsiUpperLevel = 70, RsiLowerLevel = 30.
    • StopLossPips = 50, TakeProfitPips = 150, TrailingStopPips = 15, TrailingStepPips = 5.
    • MaxPositions = 10, ProfitClose = 100, TradeVolume = 1.
  • Фильтры: Шесть булевых переключателей (BuyPreviousFastBelowSlow, BuyCurrentFastAboveSlow, BuyRequiresRsiAboveUpper, SellPreviousFastAboveSlow, SellCurrentFastBelowSlow, SellRequiresRsiBelowLower) задают направление каждого сравнения.

Параметры

Имя Описание
CandleType Тип свечей (таймфрейм), используемый в расчётах.
MaType Вид скользящей средней (SMA, EMA, Smoothed, WMA, VWMA).
FastMaPeriod Период быстрой MA.
SlowPeriodMultiplier Множитель периода медленной MA (slow = fast * multiplier).
FastMaShift, SlowMaShift Горизонтальные сдвиги, имитирующие параметр shift в MT5.
RsiPeriod Период RSI (значение берётся с предыдущей закрытой свечи).
RsiUpperLevel, RsiLowerLevel Пороговые значения RSI для лонга и шорта.
BuyPreviousFastBelowSlow, BuyCurrentFastAboveSlow, BuyRequiresRsiAboveUpper Флаги, задающие условия входа в лонг.
SellPreviousFastAboveSlow, SellCurrentFastBelowSlow, SellRequiresRsiBelowLower Аналогичные флаги для входа в шорт.
StopLossPips, TakeProfitPips Стоп-лосс и тейк-профит в пипсах (пип определяется по шагу цены инструмента).
TrailingStopPips, TrailingStepPips Дистанция и минимальный шаг трейлинг-стопа.
MaxPositions Максимальное число одновременных позиций на направление (0 — без ограничения).
ProfitClose Целевой размер плавающей прибыли для принудительного закрытия всех сделок.
CloseOppositePositions Закрывать ли встречные позиции перед новым входом.
TradeVolume Базовый торговый объём; синхронизируется со свойством Volume стратегии.

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

  • Все решения принимаются только на закрытых свечах, что соответствует «работе на новом баре» в MT5.
  • Пип вычисляется как шаг цены инструмента. Для инструментов с дробными пипами необходимо настроить параметры инструмента, чтобы добиться поведения как в оригинале (digits_adjust).
  • Трейлинг активируется только после движения цены на TrailingStopPips + TrailingStepPips и далее держит стоп на расстоянии TrailingStopPips, обновляя его лишь при улучшении минимум на TrailingStepPips.
  • ProfitClose рассчитывает прибыль с использованием PriceStep и StepPrice. Убедитесь, что эти величины заданы корректно.
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>
/// Two MA one RSI strategy (simplified).
/// EMA crossover filtered by RSI levels.
/// </summary>
public class TwoMaOneRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	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 int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public TwoMaOneRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

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

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI length", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal prevFast = 0, prevSlow = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		// Use Bind with fast, slow - RSI computed separately via cross-feed
		subscription
			.Bind(fast, slow, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					return;
				}

				// Golden cross + RSI not overbought
				if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
				{
					BuyMarket();
				}
				// Death cross + RSI not oversold
				else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
				{
					SellMarket();
				}

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}
}