Открыть на GitHub

Стратегия Average Candle Cross

Стратегия повторяет эксперта MetaTrader «Average candle cross». Она ждёт закрытия бара, на котором предыдущая свеча пересекла скользящую среднюю, а два дополнительных фильтра из скользящих средних уже подтвердили направление тренда. Одновременно может быть открыта только одна позиция. Сразу после входа выставляются стоп-лосс и тейк-профит, расстояние между которыми рассчитывается из заданного стопа в пунктах, что полностью соответствует блочной логике оригинальной системы, срабатывающей раз в бар.

Все сигналы оцениваются только на завершённых свечах, без участия незакрытых тиков. Для длинных и коротких сделок используются отдельные наборы параметров сглаживания, поэтому можно задавать асимметричное поведение. Защитные уровни формируются из стоп- и лимитных заявок на расстоянии StopLossPips * PipSize от цены входа. Тейк-профит использует то же базовое расстояние и умножает его на указанный процент.

Подробности

  • Условия входа:
    • Лонг: на предыдущем баре обе трендовые средние для покупки возрастают (MA_fast1[1] > MA_slow1[1] и MA_fast2[1] > MA_slow2[1]), а предыдущая свеча закрылась выше своей средней при том, что свеча двумя барами ранее была ниже (Close[2] <= MA_cross[2] и Close[1] > MA_cross[1]).
    • Шорт: на предыдущем баре обе трендовые средние для продажи снижаются (MA_fast1[1] < MA_slow1[1] и MA_fast2[1] < MA_slow2[1]), а предыдущая свеча закрылась ниже своей средней при том, что свеча двумя барами ранее была выше (Close[2] >= MA_cross[2] и Close[1] < MA_cross[1]).
  • Направление: работает и в длинную, и в короткую сторону, но не одновременно.
  • Выход:
    • Позиции закрываются только срабатыванием защитного стоп-лосса или тейк-профита.
  • Стопы: Да. Стоп устанавливается на расстоянии StopLossPips * PipSize от цены входа, тейк-профит равен стопу, умноженному на параметр «% от SL».
  • Значения по умолчанию:
    • FirstTrendFastPeriod = 5, FirstTrendFastMethod = SMA.
    • FirstTrendSlowPeriod = 20, FirstTrendSlowMethod = SMA.
    • SecondTrendFastPeriod = 20, SecondTrendFastMethod = SMA.
    • SecondTrendSlowPeriod = 30, SecondTrendSlowMethod = SMA.
    • BullCrossPeriod = 5, BullCrossMethod = SMA.
    • BuyVolume = 0.01, BuyStopLossPips = 50, BuyTakeProfitPercent = 100.
    • FirstTrendBearFastPeriod = 5, FirstTrendBearFastMethod = SMA.
    • FirstTrendBearSlowPeriod = 20, FirstTrendBearSlowMethod = SMA.
    • SecondTrendBearFastPeriod = 20, SecondTrendBearFastMethod = SMA.
    • SecondTrendBearSlowPeriod = 30, SecondTrendBearSlowMethod = SMA.
    • BearCrossPeriod = 5, BearCrossMethod = SMA.
    • SellVolume = 0.01, SellStopLossPips = 50, SellTakeProfitPercent = 100.
    • PipSize = 0.0001.
  • Фильтры:
    • Категория: трендовая.
    • Направление: двусторонняя (лонг + шорт).
    • Индикаторы: несколько скользящих средних.
    • Стопы: фиксированный стоп в пунктах и пропорциональный тейк-профит.
    • Сложность: средняя.
    • Таймфрейм: любая выбранная серия свечей (по умолчанию 15 минут).
    • Сезонность: нет.
    • Нейросети: нет.
    • Дивергенции: нет.
    • Уровень риска: средний.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Average Candle Cross strategy: price crossover above/below SMA.
/// Buys when close crosses above SMA, sells when close crosses below SMA.
/// </summary>
public class AverageCandleCrossStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal _prevClose;
	private decimal _prevSma;
	private bool _hasPrev;

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

	public AverageCandleCrossStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_period = Param(nameof(Period), 20)
			.SetGreaterThanZero()
			.SetDisplay("Period", "SMA period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevSma = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var sma = new SimpleMovingAverage { Length = Period };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(sma, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevClose <= _prevSma && candle.ClosePrice > smaValue && Position <= 0)
				BuyMarket();
			else if (_prevClose >= _prevSma && candle.ClosePrice < smaValue && Position >= 0)
				SellMarket();
		}

		_prevClose = candle.ClosePrice;
		_prevSma = smaValue;
		_hasPrev = true;
	}
}