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
StartDateTime → StartTime: la marca de tiempo inicial utilizada al sembrar el historial Renko.
BaseSymbol → Strategy.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.
Range → BrickSizeSteps: 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
GetWorkingSecurities configura una suscripción de velas Renko usando RenkoBuildFrom.Points y el tamaño de caja calculado.
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.
ProcessTrade / ProcessLevel1 almacenan el precio y la marca de tiempo del tick más reciente para fines de registro.
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();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class renko_chart_strategy(Strategy):
def __init__(self):
super(renko_chart_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 7) \
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(renko_chart_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(renko_chart_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return renko_chart_strategy()