Ver en GitHub

Estrategia Renko Chart

Descripción general

RenkoChartStrategy es una conversión directa del asesor experto original RenkoChart.mq5. En lugar de colocar órdenes, la estrategia se enfoca en recrear el flujo de trabajo del símbolo Renko personalizado dentro de StockSharp. Se suscribe a datos de tick, produce un flujo de velas Renko con un tamaño de ladrillo configurable y lo expone a través de la plataforma para que pueda visualizarse o reenviarse a otros componentes. Cada ladrillo completado se registra con el último tick que lo activó, permitiendo al operador validar la serie generada contra la implementación MQL.

Mapeo desde el asesor experto MQL

  • StartDateTimeStartTime: la marca de tiempo inicial utilizada al sembrar el historial Renko.
  • BaseSymbolStrategy.Security: StockSharp ya asigna el instrumento base, por lo que el parámetro fue reemplazado confiando en el instrumento seleccionado. La estrategia sigue prefijando el nombre del flujo generado con RenkoPrefix para imitar la convención de nomenclatura "Renko-<symbol>".
  • Mode (Bid/Last)UseBidTicks: alterna si las actualizaciones de oferta o los ticks de operación impulsan el feed de monitoreo en vivo.
  • RangeBrickSizeSteps: número de pasos de precio que forman un ladrillo Renko. La estrategia multiplica el valor por el PriceStep del instrumento para obtener el tamaño absoluto de la caja.

Parámetros

Nombre Tipo Predeterminado Descripción
StartTime DateTimeOffset 2018‑08‑01 09:00:00 UTC Los ladrillos con un tiempo de apertura antes de este momento se ignoran, coincidiendo con el comportamiento de precalentamiento original.
BrickSizeSteps int 5 Tamaño del ladrillo Renko expresado en pasos de precio. Se convierte a precio absoluto cuando se crea la serie Renko.
UseBidTicks bool false Cuando es false la estrategia escucha ticks de operación, cuando es true escucha actualizaciones de oferta para emular el modo MQL Bid.
RenkoPrefix string "Renko-" Prefijo añadido a los mensajes de registro para que el nombre del flujo coincida con la convención de nomenclatura de símbolos personalizados.

Nota: la propiedad calculada BrickSize expone el tamaño absoluto de la caja y puede ser útil cuando se conecta la estrategia con otros componentes que esperan un delta de precio en lugar de conteos de pasos.

Flujo de datos

  1. GetWorkingSecurities configura una suscripción de velas Renko usando RenkoBuildFrom.Points y el tamaño de caja calculado.
  2. OnStarted lanza la suscripción Renko, se suscribe a ticks de operación o de oferta (dependiendo de UseBidTicks), y dibuja el flujo Renko en el gráfico si hay uno disponible.
  3. ProcessTrade / ProcessLevel1 almacenan el precio y la marca de tiempo del tick más reciente para fines de registro.
  4. ProcessCandle ignora ladrillos no terminados, filtra datos previos a StartTime y registra cada ladrillo completado con los niveles de cierre anterior y nuevo junto con la información del último tick.

Consejos de uso

  • Adjunta la estrategia a cualquier instrumento que proporcione operaciones o actualizaciones de nivel 1. El flujo Renko aparecerá en el área de gráfico estándar con el prefijo configurado.
  • Debido a que la implementación no envía órdenes, se puede ejecutar en paralelo con otras estrategias de trading para proporcionar una vista Renko sincronizada del mercado.
  • Las entradas de registro contienen tanto la dirección del ladrillo como el tick activador. Esto es útil al comparar la salida con datos históricos exportados desde MetaTrader.

Diferencias respecto a la versión MQL

  • StockSharp ya gestiona símbolos, por lo que la creación explícita de símbolos personalizados fue reemplazada por salida de registro y gráfico.
  • Todos los cálculos usan aritmética decimal en lugar de arreglos, confiando en el constructor de velas Renko integrado.
  • La estrategia adopta el modelo de suscripción y el auxiliar de protección de StockSharp, preparándola para ser extendida con lógica de trading si es necesario.
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>
/// Renko Chart strategy. Uses WMA crossover for trend detection.
/// </summary>
public class RenkoChartStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	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 RenkoChartStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
	}

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

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

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

		_prevFast = null;
		_prevSlow = null;

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

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

		if (!prevAbove && currAbove && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (prevAbove && !currAbove && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}