Ver en GitHub

Estrategia del comerciante Doji

Esta estrategia convierte el asesor experto MQL4 "DojiTrader" en una muestra de StockSharp C#. Busca velas doji recientes y negocia una ruptura del rango doji durante las principales sesiones europeas y estadounidenses.

Lógica comercial

  • La estrategia procesa solo velas terminadas del período de tiempo seleccionado (velas de 30 minutos por defecto).
  • Sólo se permite operar entre las 08:00 y las 17:00, hora de la plataforma.
  • Aunque está plano, mira hacia atrás hasta tres velas completadas y recuerda el doji más reciente (el precio de apertura es igual al precio de cierre).
  • Cuando la vela que sigue inmediatamente al doji se cierra por encima del máximo del doji, se arma una ruptura larga. Si cierra por debajo del mínimo doji, se arma una breve ruptura.
  • Tan pronto como una vela posterior cierra más allá del precio de armado, la estrategia envía una orden de mercado en la dirección de ruptura.
  • Después de la entrada, el rango del doji se conserva para el control de salida. La posición se cierra cuando:
    • La vela anterior vuelve a cerrar dentro del rango (larga: cierra por debajo del mínimo doji, corta: cierra por encima del máximo doji).
    • Los extremos de las velas alcanzan niveles de stop loss sintéticos o toma de ganancias que imitan las salidas de punto fijo originales MQL4.

Parámetros

  • Volumen de orden – volumen utilizado para órdenes de mercado.
  • Take de ganancias (pasos) – distancia al objetivo de ganancias medida en pasos de precio.
  • Stop loss (pasos) – distancia hasta el stop de protección en pasos de precio.
  • Tipo de vela: período de tiempo de las velas utilizadas para la detección de señales.

Los cálculos de stop-loss y take-profit se basan en el paso del precio del valor, emulando el EA original que utilizaba distancias de pips fijas. Cuando no hay ningún doji válido dentro de las últimas tres velas, el estado de ruptura se borra y se reinicia la búsqueda.

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;
	}
}