Открыть на GitHub

Стратегия Above Below MA

Стратегия Above Below MA повторяет логику советника MetaTrader Above Below MA (barabashkakvn's edition). Она оценивает, насколько далеко текущая цена находится по «неправильную» сторону от настраиваемой скользящей средней, и допускает сделки только если цена удалена от средней не меньше заданного порога и сама средняя разворачивается в ожидаемом направлении. Реализация использует высокоуровневый API StockSharp и работает исключительно по завершённым свечам.

Общая информация

  • Рынки: Инструменты, склонные возвращаться к скользящей средней перед продолжением тренда.
  • Инструменты: Любые, поддерживаемые подключением StockSharp. Наибольшую пользу получают валютные пары, так как исходная версия измеряла расстояние в пунктах.
  • Таймфрейм: Настраивается параметром Candle Type (по умолчанию минутные свечи).
  • Направления: Разрешены длинные и короткие позиции, но одновременно может существовать только одна чистая позиция.

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

  1. Рассчитывается скользящая средняя по выбранной серии свечей. Тип усреднения (SMA, EMA, SMMA, WMA), источник цены (close, open, high, low, median, typical, weighted) и смещение полностью повторяют параметры MetaTrader.
  2. Минимальная дистанция в пунктах переводится в цену через PriceStep инструмента. Если шаг цены недоступен, фильтр автоматически отключается.
  3. Для каждой завершённой свечи выполняются проверки:
    • Сигнал на покупку:
      • Цена открытия и закрытия свечи находятся не ближе заданной дистанции ниже смещённой средней.
      • Текущее значение средней выше предыдущего (средняя растёт).
    • Сигнал на продажу:
      • Открытие и закрытие располагаются минимум на заданную дистанцию выше смещённой средней.
      • Текущее значение средней ниже предыдущего (средняя снижается).
  4. Перед открытием новой сделки стратегия закрывает противоположную позицию и отправляет рыночный ордер в направлении сигнала.

Все решения принимаются только по закрытым свечам, чтобы исключить многократные входы внутри формирующегося бара. Заявки отправляются методами BuyMarket и SellMarket с установленным объёмом.

Параметры

Параметр Описание
MaPeriod Период скользящей средней. По умолчанию 6.
MaShift Смещение средней вперёд на n свечей. 0 — текущее значение, n — значение n свечей назад. По умолчанию 0.
MaMethod Тип средней: Simple, Exponential, Smoothed, Weighted. По умолчанию Exponential.
AppliedPrice Источник цены: close, open, high, low, median, typical или weighted. По умолчанию Typical.
MinimumDistancePips Минимальная дистанция в пунктах между ценой свечи и средней. Переводится через PriceStep. По умолчанию 5.
CandleType Тип свечей, по которым выполняются расчёты. По умолчанию минутные свечи.
TradeVolume Объём новой позиции. По умолчанию 1.

Дополнительные замечания

  • В стратегию не встроены стоп-лосс и тейк-профит. Управление рисками следует реализовывать отдельными механизмами.
  • Буфер для смещения средней хранит только необходимые значения и не нарушает требование «без собственных коллекций».
  • Если 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>
/// Above/Below MA strategy. Trades when price crosses above or below a moving average.
/// </summary>
public class AboveBelowMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private decimal? _prevClose;
	private decimal? _prevMa;

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

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public AboveBelowMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");
	}

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

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

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

		_prevClose = null;
		_prevMa = null;

		var sma = new SimpleMovingAverage { Length = MaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal maVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var close = candle.ClosePrice;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		if (_prevClose == null || _prevMa == null)
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		// Price crosses above MA → buy
		if (_prevClose.Value <= _prevMa.Value && close > maVal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Price crosses below MA → sell
		else if (_prevClose.Value >= _prevMa.Value && close < maVal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevMa = maVal;
	}
}