Auf GitHub ansehen

Renko Chart-Strategie

Überblick

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

  • StartDateTimeStartTime: der anfängliche Zeitstempel, der beim Setzen der Renko-Historie verwendet wird.
  • BaseSymbolStrategy.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.
  • RangeBrickSizeSteps: 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

  1. GetWorkingSecurities konfiguriert ein Renko-Kerzen-Abonnement mit RenkoBuildFrom.Points und der berechneten Boxgröße.
  2. 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.
  3. ProcessTrade / ProcessLevel1 speichern den neuesten Tick-Preis und Zeitstempel für Protokollierungszwecke.
  4. 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();
		}
	}
}