Auf GitHub ansehen

Mc Valute Cloud-Strategie

Dieser Ordner enthält den StockSharp-Port des MetaTrader-Expertenberaters „Mc_valute“. Der ursprüngliche Roboter kombinierte einen Kurzschluss exponentieller gleitender Durchschnitt (EMA) mit drei geglätteten gleitenden Durchschnitten, einem Ichimoku-Wolkenfilter und mehreren MACD-Instanzen während Skalierung in den Trend. Die StockSharp-Implementierung behält den zentralen Trendbestätigungsstapel bei, vereinfacht jedoch die Positionsverwaltung auf eine einzelne Belichtung in jede Richtung, sodass die Logik natürlich in das übergeordnete API passt.

Handelslogik

  1. Preisfilter EMA – der FilterMaLength EMA muss über (für Long-Positionen) oder unter (für Short-Positionen) der beiden geglätteten Bewegungen liegen Durchschnittswerte (BlueMaLength und LimeMaLength). Die geglätteten Durchschnittswerte emulieren die „blauen“ und „limettenfarbenen“ Linien aus der MT4-Vorlage.
  2. Ichimoku Cloud-Bestätigung – der EMA muss sich auch außerhalb der Cloud befinden. Für lange Trades ist der Filter EMA über beiden erforderlich Senkou spannt sich, während Short-Trades erfordern, dass es unter dem Wolkenboden bleibt.
  3. MACD-Impulsprüfung – die Hauptlinie MACD muss bei langen Einstiegen über ihrer Signallinie und bei kurzen Einstiegen darunter liegen. Nur der erste MACD-Satz aus der ursprünglichen EA-Version wird beibehalten, da die restlichen Kopien in der endgültigen MQL-Version deaktiviert wurden.
  4. Einzelpositionsmanagement – immer wenn ein neues Signal erscheint, gleicht die Strategie jede bestehende Gegenposition aus und eröffnet eine neuer Handel mit dem konfigurierten Volume. Schutzaufträge werden sofort nach dem Absenden der Marktorder aktualisiert.
  5. Kerze-für-Kerze-Auswertung – alle Indikatoren arbeiten in dem durch CandleType definierten Zeitrahmen. Handelsentscheidungen werden getroffen Nur bei fertigen Kerzen, um den MT4 start()-Handler widerzuspiegeln, der geschlossene Balken verarbeitet hat.

Risikomanagement

  • TakeProfit und StopLoss werden in Preispunkten gemessen. Nach jedem Eintrag werden die Helfer SetTakeProfit und SetStopLoss angezeigt. Funktionen werden unter Verwendung der erwarteten resultierenden Positionsgröße aufgerufen, die das MT4-Verhalten widerspiegelt, bei dem Stopps angewendet wurden Fahrkarte.
  • Der ursprüngliche Expertenberater hat mithilfe der Distanz Step bis zu drei zusätzliche Orders in eine Pyramide gebracht. Der Port StockSharp behält eine Einzelposition, um im oberen Rang der Ordnungshelfer zu bleiben. Benutzer, die eine Skalierung benötigen, können Volume erhöhen oder klonen Strategie über mehrere Portfolios hinweg.

Parameter

Parameter Beschreibung
Volume Basishandelsgröße, die von den übergeordneten BuyMarket/SellMarket-Aufrufen verwendet wird.
CandleType Primäre Kerzenserien steuern die Indikatoren und die Handelslogik.
FilterMaLength Länge des Trendfilters EMA.
BlueMaLength, LimeMaLength Längen der beiden geglätteten gleitenden Durchschnitte, die als Richtungsband fungieren.
MacdFastLength, MacdSlowLength, MacdSignalLength EMA Längen für die MACD-Bestätigung.
TenkanLength, KijunLength, SenkouLength Ichimoku Kinko Hyo-Einstellungen für den Cloud-Filter.
TakeProfit, StopLoss Schutzabstände ausgedrückt in Preispunkten.

Nutzungshinweise

  1. Indikatorverschiebungen – MetaTrader erlaubte „Verschiebungs“-Parameter ungleich Null bei der Erstellung der geglätteten gleitenden Durchschnitte. StockSharps Indikatoren funktionieren auf dem aktuellen Balken, daher ignoriert der Port diese Verschiebungen, behält aber die ursprünglichen Perioden bei.
  2. MACD-Varianten – der Quellcode deklarierte drei MACD-Blöcke, aber nur der erste nahm an Live-Signalen teil. Der Hafen folgt diesem Verhalten; Zusätzliche MACD-Filter können durch Duplizieren der Indikatorbindungen wieder aktiviert werden.
  3. Skalierende Trades – der MT4-Roboter sendete bis zu drei Durchschnittsaufträge im Abstand von Step Punkten. Dieses Verhalten ist dokumentiert aber absichtlich weggelassen, da High-Level-Strategien mit einer einzigen aggregierten Position arbeiten.
  4. SchutzblockStartProtection() wird einmal während des Startvorgangs aufgerufen, damit die integrierte Infrastruktur den Stopp überwacht und Zielaufträge auch nach Wiederverbindungen.

Dateien

  • CS/McValuteCloudStrategy.cs – C#-Implementierung unter Verwendung der High-Level-Strategie API mit Indikatorbindungen und detailliert Kommentare.
  • README.md – Englische Dokumentation (diese Datei).
  • README_zh.md – Vereinfachte chinesische Übersetzung.
  • README_ru.md – Russische Übersetzung.
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>
/// Trend-following strategy inspired by the "Mc_valute" MetaTrader expert advisor.
/// Combines smoothed moving averages, an Ichimoku cloud filter and a MACD confirmation.
/// </summary>
public class McValuteCloudStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _filterMaLength;
	private readonly StrategyParam<int> _blueMaLength;
	private readonly StrategyParam<int> _limeMaLength;
	private readonly StrategyParam<int> _macdFastLength;
	private readonly StrategyParam<int> _macdSlowLength;
	private readonly StrategyParam<int> _macdSignalLength;
	private readonly StrategyParam<int> _tenkanLength;
	private readonly StrategyParam<int> _kijunLength;
	private readonly StrategyParam<int> _senkouLength;
	private readonly StrategyParam<int> _takeProfit;
	private readonly StrategyParam<int> _stopLoss;

	private ExponentialMovingAverage _filterMa;
	private SmoothedMovingAverage _blueMa;
	private SmoothedMovingAverage _limeMa;
	private MovingAverageConvergenceDivergenceSignal _macd;
	private Ichimoku _ichimoku;

	private decimal? _filterValue;
	private decimal? _blueValue;
	private decimal? _limeValue;
	private decimal? _senkouAValue;
	private decimal? _senkouBValue;
	private decimal? _macdMainValue;
	private decimal? _macdSignalValue;

	private DateTimeOffset _lastProcessedTime;

	/// <summary>
	/// Initializes a new instance of the <see cref="McValuteCloudStrategy"/> class.
	/// </summary>
	public McValuteCloudStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Primary timeframe used for signals", "General");

		_filterMaLength = Param(nameof(FilterMaLength), 3)
		.SetDisplay("Filter EMA", "Length of the trend filter EMA", "Trend")
		
		.SetOptimize(2, 20, 1);

		_blueMaLength = Param(nameof(BlueMaLength), 13)
		.SetDisplay("Blue SMMA", "Length of the slower smoothed MA", "Trend")
		
		.SetOptimize(5, 60, 1);

		_limeMaLength = Param(nameof(LimeMaLength), 5)
		.SetDisplay("Lime SMMA", "Length of the faster smoothed MA", "Trend")
		
		.SetOptimize(3, 40, 1);

		_macdFastLength = Param(nameof(MacdFastLength), 12)
		.SetDisplay("MACD Fast", "Short EMA length for the MACD", "Momentum")
		
		.SetOptimize(5, 30, 1);

		_macdSlowLength = Param(nameof(MacdSlowLength), 26)
		.SetDisplay("MACD Slow", "Long EMA length for the MACD", "Momentum")
		
		.SetOptimize(10, 80, 1);

		_macdSignalLength = Param(nameof(MacdSignalLength), 9)
		.SetDisplay("MACD Signal", "Signal EMA length for the MACD", "Momentum")
		
		.SetOptimize(3, 30, 1);

		_tenkanLength = Param(nameof(TenkanLength), 12)
		.SetDisplay("Tenkan", "Tenkan-sen length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(5, 30, 1);

		_kijunLength = Param(nameof(KijunLength), 20)
		.SetDisplay("Kijun", "Kijun-sen length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(10, 60, 1);

		_senkouLength = Param(nameof(SenkouLength), 40)
		.SetDisplay("Senkou Span B", "Span B length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(20, 120, 1);

		_takeProfit = Param(nameof(TakeProfit), 30)
		.SetDisplay("Take Profit", "Take profit distance in points", "Risk")
		
		.SetOptimize(10, 200, 5);

		_stopLoss = Param(nameof(StopLoss), 350)
		.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk")
		
		.SetOptimize(50, 600, 10);

		_lastProcessedTime = DateTimeOffset.MinValue;
	}

	/// <summary>
	/// Timeframe used for the working candles.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Length of the EMA filter.
	/// </summary>
	public int FilterMaLength
	{
		get => _filterMaLength.Value;
		set => _filterMaLength.Value = value;
	}

	/// <summary>
	/// Length of the slower smoothed moving average.
	/// </summary>
	public int BlueMaLength
	{
		get => _blueMaLength.Value;
		set => _blueMaLength.Value = value;
	}

	/// <summary>
	/// Length of the faster smoothed moving average.
	/// </summary>
	public int LimeMaLength
	{
		get => _limeMaLength.Value;
		set => _limeMaLength.Value = value;
	}

	/// <summary>
	/// Fast EMA length used by the MACD.
	/// </summary>
	public int MacdFastLength
	{
		get => _macdFastLength.Value;
		set => _macdFastLength.Value = value;
	}

	/// <summary>
	/// Slow EMA length used by the MACD.
	/// </summary>
	public int MacdSlowLength
	{
		get => _macdSlowLength.Value;
		set => _macdSlowLength.Value = value;
	}

	/// <summary>
	/// Signal EMA length used by the MACD.
	/// </summary>
	public int MacdSignalLength
	{
		get => _macdSignalLength.Value;
		set => _macdSignalLength.Value = value;
	}

	/// <summary>
	/// Tenkan-sen length for the Ichimoku indicator.
	/// </summary>
	public int TenkanLength
	{
		get => _tenkanLength.Value;
		set => _tenkanLength.Value = value;
	}

	/// <summary>
	/// Kijun-sen length for the Ichimoku indicator.
	/// </summary>
	public int KijunLength
	{
		get => _kijunLength.Value;
		set => _kijunLength.Value = value;
	}

	/// <summary>
	/// Senkou Span B length for the Ichimoku indicator.
	/// </summary>
	public int SenkouLength
	{
		get => _senkouLength.Value;
		set => _senkouLength.Value = value;
	}

	/// <summary>
	/// Take profit distance in points.
	/// </summary>
	public int TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Stop loss distance in points.
	/// </summary>
	public int StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_filterMa = null;
		_blueMa = null;
		_limeMa = null;
		_macd = null;
		_ichimoku = null;
		_filterValue = null;
		_blueValue = null;
		_limeValue = null;
		_senkouAValue = null;
		_senkouBValue = null;
		_macdMainValue = null;
		_macdSignalValue = null;
		_lastProcessedTime = DateTimeOffset.MinValue;
	}

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

		_filterMa = new ExponentialMovingAverage { Length = FilterMaLength };
		_blueMa = new SmoothedMovingAverage { Length = BlueMaLength };
		_limeMa = new SmoothedMovingAverage { Length = LimeMaLength };

		_macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastLength },
				LongMa = { Length = MacdSlowLength },
			},
			SignalMa = { Length = MacdSignalLength }
		};

		_ichimoku = new Ichimoku
		{
			Tenkan = { Length = TenkanLength },
			Kijun = { Length = KijunLength },
			SenkouB = { Length = SenkouLength }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
		.Bind(_filterMa, _blueMa, _limeMa, ProcessMovingAverages)
		.BindEx(_macd, ProcessMacd)
		.BindEx(_ichimoku, ProcessIchimoku)
		.Start();

		StartProtection(null, null);

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _filterMa);
			DrawIndicator(area, _blueMa);
			DrawIndicator(area, _limeMa);
			DrawIndicator(area, _macd);
			DrawOwnTrades(area);
		}
	}

	private void ProcessMovingAverages(ICandleMessage candle, decimal filter, decimal blue, decimal lime)
	{
		if (candle.State != CandleStates.Finished)
		return;

		_filterValue = filter;
		_blueValue = blue;
		_limeValue = lime;

		TryTrade(candle);
	}

	private void ProcessMacd(ICandleMessage candle, IIndicatorValue macdValue)
	{
		if (candle.State != CandleStates.Finished)
		return;

		var typed = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
		if (typed.Macd is not decimal macd || typed.Signal is not decimal signal)
		return;

		_macdMainValue = macd;
		_macdSignalValue = signal;

		TryTrade(candle);
	}

	private void ProcessIchimoku(ICandleMessage candle, IIndicatorValue value)
	{
		if (candle.State != CandleStates.Finished)
		return;

		var ichimokuValue = (IchimokuValue)value;
		if (ichimokuValue.SenkouA is not decimal spanA || ichimokuValue.SenkouB is not decimal spanB)
		return;

		_senkouAValue = spanA;
		_senkouBValue = spanB;

		TryTrade(candle);
	}

	private void TryTrade(ICandleMessage candle)
	{
		// indicators formed check removed

		if (candle.State != CandleStates.Finished)
		return;

		if (_lastProcessedTime == candle.OpenTime)
		return;

		if (_filterValue is not decimal filter ||
		_blueValue is not decimal blue ||
		_limeValue is not decimal lime ||
		_senkouAValue is not decimal spanA ||
		_senkouBValue is not decimal spanB ||
		_macdMainValue is not decimal macd ||
		_macdSignalValue is not decimal signal)
		{
			return;
		}

		_lastProcessedTime = candle.OpenTime;

		var cloudTop = Math.Max(spanA, spanB);
		var cloudBottom = Math.Min(spanA, spanB);
		var maUpper = Math.Max(blue, lime);
		var maLower = Math.Min(blue, lime);

		var allowLong = filter > maUpper && filter > cloudTop && macd > signal;
		var allowShort = filter < maLower && filter < cloudBottom && macd < signal;

		var closePrice = candle.ClosePrice;

		if (allowLong && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (allowShort && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}