Auf GitHub ansehen

Rnd Trade-Strategie

Übersicht

  • Konvertierung des MetaTrader 5-Expertenberaters RndTrade.mq5 in die StockSharp High-Level-Strategie-API.
  • Schließt jede bestehende Position in einem festen Zeitintervall und öffnet sofort eine neue Marktposition in einer zufällig gewählten Richtung.
  • Verwendet zeitbasierte Kerzenabonnements als deterministischen Ersatz für die ursprünglichen Timer-Callbacks.

Parameter

Name Typ Standard Beschreibung
IntervalMinutes int 60 Anzahl der Minuten zwischen dem Schließen der aktuellen Position und dem Öffnen einer neuen zufälligen Position. Muss größer als null sein.
Volume decimal 1 Positionsgröße für Markteinträge. Abgeleitet aus der Strategy-Basisklasse.

Daten-Abonnements

  • Abonniert Zeitrahmen-Kerzen, deren Länge IntervalMinutes entspricht (z.B. 60 → 60-Minuten-Kerzen).
  • Das Kerzen-Schließereignis (CandleStates.Finished) wird verwendet, um die Logik genau einmal pro Intervall auszulösen.

Handelslogik

  1. Warten auf den Abschluss jeder Intervallkerze.
  2. Verarbeitung überspringen, bis die Strategie gebildet, online und der Handel erlaubt ist.
  3. Jede in der vorherigen Periode eröffnete offene Position schließen.
  4. Einen Zufallswert generieren, um zwischen einem Long- oder Short-Einstieg zu entscheiden.
  5. Einen Marktauftrag (BuyMarket oder SellMarket) mit dem konfigurierten Volumen in der gewählten Richtung senden.

Implementierungshinweise

  • Basiert auf SubscribeCandles().Bind(ProcessCandle), um manuelles Polling von Indikatorwerten oder Sammlungen zu vermeiden.
  • Ruft StartProtection() beim Start auf, damit das integrierte Risikomodul aktiv ist, auch wenn kein expliziter Stop-Loss oder Take-Profit konfiguriert ist.
  • Verwendet Random aus der Standardbibliothek, um das MathRand()-Verhalten aus der ursprünglichen MQL-Strategie zu imitieren.
  • Der Code enthält englische Kommentare, die erklären, wie jeder Konvertierungsschritt auf StockSharp-Funktionen abgebildet wird.

Unterschiede zur ursprünglichen MQL-Strategie

  • Timer-Ereignisse (OnTimer) werden durch Kerzenabonnements anstelle der MetaTrader-Timer-API emuliert.
  • Das Schließen von Positionen wird mit ClosePosition() gehandhabt, anstatt Positionslisten zu durchlaufen und für jedes Ticket PositionClose aufzurufen.
  • Die StockSharp-Version stützt sich auf die integrierte Volume-Eigenschaft für die Positionsgrößenbestimmung anstelle der Abfrage des Mindest-Lots des Symbols.
  • Auftragserfüllungsregeln und Slippage-Einstellungen werden vom verbundenen Broker oder Simulator verwaltet, daher sind sie in der Strategie nicht explizit konfiguriert.

Verwendung

  1. Strategie einem Portfolio und einem Wertpapier in der StockSharp-Umgebung zuordnen.
  2. IntervalMinutes und Volume entsprechend der gewünschten Handelsfrequenz und -größe konfigurieren.
  3. Strategie starten. Sie wird automatisch Positionen abflachen und bei jedem Intervall wieder öffnen, ohne zusätzliche Eingaben.
  4. Keine Python-Implementierung ist derzeit verfügbar; nur die C#-Version ist erhältlich.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Random direction trading strategy converted from the MetaTrader RndTrade EA.
/// The strategy closes any open position on each interval and immediately opens a new random position.
/// </summary>
public class RndTradeStrategy : Strategy
{
	private readonly StrategyParam<int> _intervalMinutes;

	/// <summary>
	/// Interval in minutes between closing the current position and opening a new random one.
	/// </summary>
	public int IntervalMinutes
	{
		get => _intervalMinutes.Value;
		set => _intervalMinutes.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="RndTradeStrategy"/> class.
	/// </summary>
	public RndTradeStrategy()
	{
		_intervalMinutes = Param(nameof(IntervalMinutes), 360)
			.SetGreaterThanZero()
			.SetDisplay("Interval Minutes", "Minutes between closing and opening positions", "General");

		Volume = 1;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, TimeSpan.FromMinutes(IntervalMinutes).TimeFrame())];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		// Use time-based candles as a deterministic timer replacement.
		var timeFrame = TimeSpan.FromMinutes(IntervalMinutes).TimeFrame();

		var subscription = SubscribeCandles(timeFrame);
		subscription
			.Bind(ProcessCandle)
			.Start();

	}

	private void ProcessCandle(ICandleMessage candle)
	{
		// Process only final candles to execute logic exactly once per interval.
		if (candle.State != CandleStates.Finished)
			return;

		// Always close the existing position before selecting a new random direction.
		if (Position > 0)
			SellMarket(Position);
		else if (Position < 0)
			BuyMarket(Math.Abs(Position));

		// Derive a deterministic pseudo-random direction from the candle data.
		if (ShouldBuy(candle))
		{
			// Enter long after flattening the previous position.
			if (Position <= 0)
				BuyMarket(Volume);
		}
		else
		{
			// Enter short after flattening the previous position.
			if (Position >= 0)
				SellMarket(Volume);
		}
	}

	private static bool ShouldBuy(ICandleMessage candle)
	{
		var hash = HashCode.Combine(candle.OpenTime.Ticks, candle.ClosePrice, candle.TotalVolume);
		return (hash & 1) == 0;
	}
}