RenkoChartStrategy ist eine direkte Konvertierung des ursprünglichen RenkoChart.mq5-Experten. Anstatt Orders zu platzieren, konzentriert sich die Strategie darauf, den benutzerdefinierten Renko-Symbol-Workflow innerhalb von StockSharp zu recreieren. Sie abonniert Tick-Daten, erzeugt einen Renko-Kerzenstrom mit konfigurierbarer Stein-Größe und exponiert ihn über die Plattform, sodass er visualisiert oder an andere Komponenten weitergeleitet werden kann. Jeder abgeschlossene Stein wird mit dem letzten Tick protokolliert, der ihn ausgelöst hat, was dem Operator ermöglicht, die generierte Serie gegen die MQL-Implementierung zu validieren.
Zuordnung vom MQL-Expert
StartDateTime → StartTime: der anfängliche Zeitstempel, der beim Setzen der Renko-Historie verwendet wird.
BaseSymbol → Strategy.Security: StockSharp weist das Basisinstrument bereits zu, daher wurde der Parameter ersetzt, indem auf das ausgewählte Wertpapier vertraut wird. Die Strategie setzt dem generierten Streamnamen weiterhin RenkoPrefix voran, um die "Renko-<symbol>"-Namenskonvention nachzuahmen.
Mode (Bid/Last) → UseBidTicks: schaltet um, ob Bid-Updates oder Trade-Ticks den Live-Monitoring-Feed antreiben.
Range → BrickSizeSteps: Anzahl der Preisschritte, die einen Renko-Stein bilden. Die Strategie multipliziert den Wert mit dem PriceStep des Wertpapiers, um die absolute Boxgröße zu erhalten.
Parameter
Name
Typ
Standard
Beschreibung
StartTime
DateTimeOffset
2018‑08‑01 09:00:00 UTC
Steine mit einer Öffnungszeit vor diesem Moment werden ignoriert und entsprechen dem ursprünglichen Warmup-Verhalten.
BrickSizeSteps
int
5
Renko-Steingröße ausgedrückt in Preisschritten. Wird in absoluten Preis umgerechnet, wenn die Renko-Serie erstellt wird.
UseBidTicks
bool
false
Wenn false lauscht die Strategie auf Trade-Ticks, wenn true lauscht sie auf Bid-Updates um den MQL-Bid-Modus zu emulieren.
RenkoPrefix
string
"Renko-"
Präfix zu den Protokollnachrichten hinzugefügt, damit der Streamname der benutzerdefinierten Symbol-Namenskonvention entspricht.
Hinweis: die berechnete BrickSize-Eigenschaft exponiert die absolute Boxgröße und kann nützlich sein, wenn die Strategie mit anderen Komponenten verdrahtet wird, die ein Preis-Delta anstelle von Schrittanzahlen erwarten.
Datenfluss
GetWorkingSecurities konfiguriert ein Renko-Kerzen-Abonnement mit RenkoBuildFrom.Points und der berechneten Boxgröße.
OnStarted startet das Renko-Abonnement, abonniert entweder Trade- oder Bid-Ticks (abhängig von UseBidTicks) und zeichnet den Renko-Stream auf dem Chart, falls einer verfügbar ist.
ProcessTrade / ProcessLevel1 speichern den neuesten Tick-Preis und Zeitstempel für Protokollierungszwecke.
ProcessCandle ignoriert unfertige Steine, filtert Daten vor StartTime heraus und protokolliert jeden abgeschlossenen Stein mit den vorherigen und neuen Schlussniveaus sowie den neuesten Tick-Informationen.
Verwendungshinweise
Hängen Sie die Strategie an ein beliebiges Instrument an, das entweder Trades oder Level-1-Updates bereitstellt. Der Renko-Stream erscheint im Standard-Chartbereich mit dem konfigurierten Präfix.
Da die Implementierung keine Orders sendet, kann sie parallel zu anderen Trading-Strategien ausgeführt werden, um eine synchronisierte Renko-Ansicht des Marktes zu liefern.
Die Protokolleinträge enthalten sowohl die Steinrichtung als auch den auslösenden Tick. Dies ist praktisch beim Vergleich der Ausgabe mit historischen Daten, die aus MetaTrader exportiert wurden.
Unterschiede zur MQL-Version
StockSharp verwaltet Symbole bereits, daher wurde die explizite benutzerdefinierte Symbolerstellung durch Protokollierungs- und Chartausgabe ersetzt.
Alle Berechnungen verwenden Dezimalarithmetik anstelle von Arrays und stützen sich auf den integrierten Renko-Kerzen-Builder.
Die Strategie übernimmt das Abonnementmodell und den Schutzhelfer von StockSharp, wodurch sie bereit ist, bei Bedarf mit Handelslogik erweitert zu werden.
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()