Открыть на GitHub

Стратегия Doji Trader

Стратегия представляет собой конвертацию эксперта MQL4 "DojiTrader" в пример на C# для StockSharp. Она ищет свежие свечи-доджи и торгует пробой их диапазона в основные европейские и американские часы.

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

  • Обрабатываются только завершённые свечи выбранного таймфрейма (по умолчанию 30 минут).
  • Открытие сделок разрешено только с 08:00 до 17:00 по времени площадки.
  • Находясь вне позиции, стратегия анализирует до трёх последних завершённых свечей и запоминает самую свежую свечу-доджи (открытие равно закрытию).
  • Если следующая за доджи свеча закрывается выше максимума доджи, готовится пробой вверх. Если она закрывается ниже минимума доджи, готовится пробой вниз.
  • Когда последующая свеча закрывается за ценой пробоя, отправляется рыночная заявка в сторону пробоя.
  • После входа диапазон доджи сохраняется для контроля выхода. Позиция закрывается, когда:
    • Предыдущая свеча закрывается обратно в диапазоне (для лонга – закрытие ниже минимума доджи, для шорта – выше максимума).
    • Экстремумы свечи достигают синтетических уровней стоп-лосса или тейк-профита, имитирующих фиксированные пункты оригинального советника.

Параметры

  • Order volume – объём рыночных заявок.
  • Take profit (steps) – расстояние до тейк-профита в шагах цены.
  • Stop loss (steps) – расстояние до стоп-лосса в шагах цены.
  • Candle type – таймфрейм свечей для расчётов.

Стоп-лосс и тейк-профит рассчитываются через шаг цены инструмента, повторяя логику исходного MQL4-советника с фиксированным количеством пунктов. Если в последних трёх свечах нет подходящего доджи, состояние пробоя сбрасывается и поиск начинается заново.

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>
/// Doji Trader breakout strategy.
/// Detects doji candles and enters on breakout of doji range.
/// Uses SMA as trend filter for direction.
/// </summary>
public class DojiTraderBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<decimal> _dojiRatio;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _prevWasDoji;
	private bool _hasPrev;

	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
	public decimal DojiRatio { get => _dojiRatio.Value; set => _dojiRatio.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public DojiTraderBreakoutStrategy()
	{
		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetDisplay("SMA Period", "SMA period for trend filter", "Indicators");

		_dojiRatio = Param(nameof(DojiRatio), 0.25m)
			.SetDisplay("Doji Ratio", "Max body/range ratio for doji detection", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevHigh = 0m; _prevLow = 0m; _prevWasDoji = false; _hasPrev = false; }

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

		_hasPrev = false;
		_prevWasDoji = false;

		var sma = new SimpleMovingAverage { Length = SmaPeriod };

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

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

		var range = candle.HighPrice - candle.LowPrice;
		var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
		var isDoji = range > 0 && body / range < DojiRatio;

		if (_hasPrev && _prevWasDoji)
		{
			// Bullish breakout above doji high with SMA confirmation
			if (candle.ClosePrice > _prevHigh && candle.ClosePrice > sma && Position <= 0)
			{
				if (Position < 0)
					BuyMarket();
				BuyMarket();
			}
			// Bearish breakout below doji low with SMA confirmation
			else if (candle.ClosePrice < _prevLow && candle.ClosePrice < sma && Position >= 0)
			{
				if (Position > 0)
					SellMarket();
				SellMarket();
			}
		}

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
		_prevWasDoji = isDoji;
		_hasPrev = true;
	}
}