Auf GitHub ansehen

Toller Devisenhändler

Diese Strategie reproduziert das MetaTrader-Setup von MQL/8539, das aus den benutzerdefinierten Indikatoren AwesomeFxTradera.mq4 und t_ma.mq4 besteht. Der Originalcode malt das Bill Williams Awesome Oscillator-Histogramm in Grün oder Rot, je nachdem, ob der Wert steigt oder fällt, und überlagert einen linear gewichteten gleitenden Durchschnitt (LWMA) mit 34 Perioden neben einem geglätteten Klon derselben Kurve. Der StockSharp-Port behält die gleichen Berechnungen bei und wandelt die Indikatorfarben in Handelssignale um.

Ursprüngliche MQL-Logik

  1. AwesomeFxTradera.mq4 berechnet zwei exponentielle gleitende Durchschnitte, die auf den Eröffnungspreis mit den Perioden 8 und 13 angewendet werden. Ihre Differenz wird in ExtBuffer0 gespeichert. Der Puffer wird grün gefärbt, wenn der aktuelle Wert höher als der vorherige Balken ist, und rot, wenn er niedriger ist. Dies kodiert effektiv die Richtung des Impulses, nicht nur sein Vorzeichen.
  2. t_ma.mq4 stellt einen 34-Perioden-LWMA des Eröffnungspreises (ExtMapBuffer1) und einen 6-Perioden-einfachen gleitenden Durchschnitt dieses LWMA (ExtMapBuffer2) dar. Der Smoother verfolgt, ob sich der Trenddurchschnitt beschleunigt oder verlangsamt.

Das MetaTrader-Diagramm verdeutlicht daher das zinsbullische Momentum, wenn der Oszillator über Null liegt und weiter steigt, während der Preis über dem geglätteten LWMA liegt. Das rückläufige Momentum ist die entgegengesetzte Konfiguration.

StockSharp-Implementierung

Der AwesomeFxTraderStrategy abonniert einen konfigurierbaren Kerzentyp (Standard M15) und speist die Indikatoren mit dem Kerzenöffnungspreis, um ihn an die MetaTrader-Puffer anzupassen.

  1. Die schnellen und langsamen EMAs werden bei jeder fertigen Kerze neu berechnet; Ihre Differenz gibt das oszillierende Histogramm wieder.
  2. Der LWMA verfolgt den 34-Balken-Trend und ein 6-Balken SMA glättet ihn. Der Vergleich beider Serien zeigt, ob die Trendkurve steigt oder fällt.
  3. Die Oszillatorfarbe wird neu erstellt, indem der aktuelle Histogrammwert mit dem vorherigen Balken verglichen wird und dabei der bool up-Logik aus der MQL-Implementierung folgt.
  4. Eintrittsregeln:
    • Geben Sie „long“ ein, wenn der Oszillator positiv ist, ansteigt (grüner Puffer) und der LWMA über seinem Glättungswert liegt.
    • Geben Sie kurz ein, wenn der Oszillator negativ ist, fällt (roter Puffer) und der LWMA unter seinem Glättungswert liegt.
  5. Ausstiegs-/Umkehrregeln: Ein entgegengesetztes Signal kehrt die Position um. Die Ordergröße wird automatisch um die absolute aktuelle Position erhöht, sodass Short-Positionen geschlossen werden, bevor eine Long-Position entsteht, und umgekehrt.

Im Quellcode sind keine zusätzlichen Stop-Loss- oder Take-Profit-Levels definiert, daher verlässt sich der Port bei Ausstiegen ausschließlich auf Momentum-Flips. Protokollierungsanweisungen dokumentieren jeden Handelsauslöser zusammen mit den Indikatorwerten.

Parameter

Name Standard Beschreibung
FastEmaPeriod 8 Länge des schnellen EMA, das im Oszillator-Replikat verwendet wird.
SlowEmaPeriod 13 Länge des langsamen EMA.
TrendLwmaPeriod 34 Zeitraum des LWMA-Trendfilters aus t_ma.mq4.
TrendSmoothingPeriod 6 Fenster des auf die LWMA-Werte angewendeten SMA.
CandleType 15-minütiger Zeitrahmen Kerzendatentyp, der sowohl für Momentum- als auch für Trendberechnungen verwendet wird.

Dank der StrategyParam-Metadaten können alle Parameter über die StockSharp-Benutzeroberfläche optimiert werden.

Dateizuordnung

MetaTrader-Datei StockSharp Gegenstück Notizen
MQL/8539/AwesomeFxTradera.mq4 CS/AwesomeFxTraderStrategy.cs Erstellt den EMA-on-open-Oszillator und seine steigende/fallende Farblogik neu.
MQL/8539/t_ma.mq4 CS/AwesomeFxTraderStrategy.cs Implementiert den 34-Perioden-LWMA mit einem 6-Perioden-SMA-Glätter zur Trenderkennung.

Die Python-Version wird wie gewünscht bewusst weggelassen.

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>
/// Awesome Fx Trader strategy.
/// Recreates the MetaTrader logic that paints the Awesome Oscillator histogram and trend moving averages.
/// Goes long when the oscillator turns bullish while the linear weighted average stays above its smoother.
/// Opens shorts on the opposite momentum and trend alignment.
/// </summary>
public class AwesomeFxTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _trendLwmaPeriod;
	private readonly StrategyParam<int> _trendSmoothingPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private EMA _fastEma;
	private EMA _slowEma;
	private WeightedMovingAverage _trendLwma;

	private decimal _previousAo;
	private bool _hasPreviousAo;
	private bool _isAoIncreasing;
	private decimal _previousLwma;

	/// <summary>
	/// Period for the fast EMA used in the oscillator.
	/// </summary>
	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period for the slow EMA used in the oscillator.
	/// </summary>
	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	/// <summary>
	/// Length of the trend linear weighted moving average.
	/// </summary>
	public int TrendLwmaPeriod
	{
		get => _trendLwmaPeriod.Value;
		set => _trendLwmaPeriod.Value = value;
	}

	/// <summary>
	/// Length of the smoothing simple moving average applied to the trend LWMA.
	/// </summary>
	public int TrendSmoothingPeriod
	{
		get => _trendSmoothingPeriod.Value;
		set => _trendSmoothingPeriod.Value = value;
	}

	/// <summary>
	/// Type of candles to use for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="AwesomeFxTraderStrategy"/>.
	/// </summary>
	public AwesomeFxTraderStrategy()
	{
		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Period of the fast EMA driving the oscillator", "Awesome Oscillator")
			
			.SetOptimize(4, 20, 1);

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Period of the slow EMA driving the oscillator", "Awesome Oscillator")
			
			.SetOptimize(8, 40, 1);

		_trendLwmaPeriod = Param(nameof(TrendLwmaPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Trend LWMA", "Length of the linear weighted trend average", "Trend Filter")
			
			.SetOptimize(20, 80, 2);

		_trendSmoothingPeriod = Param(nameof(TrendSmoothingPeriod), 6)
			.SetGreaterThanZero()
			.SetDisplay("Trend Smoother", "Length of the SMA applied to the trend LWMA", "Trend Filter")
			
			.SetOptimize(3, 10, 1);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Time-frame used for calculations", "General");
	}

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

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

		_fastEma = null;
		_slowEma = null;
		_trendLwma = null;
		_previousAo = 0m;
		_hasPreviousAo = false;
		_isAoIncreasing = false;
		_previousLwma = 0m;
	}

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

		_fastEma = new EMA { Length = FastEmaPeriod };
		_slowEma = new EMA { Length = SlowEmaPeriod };
		_trendLwma = new WeightedMovingAverage { Length = TrendLwmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(_fastEma, _slowEma, _trendLwma, ProcessCandle).Start();

		var priceArea = CreateChartArea();
		if (priceArea != null)
		{
			DrawCandles(priceArea, subscription);
			DrawIndicator(priceArea, _trendLwma);
			DrawOwnTrades(priceArea);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastEma, decimal slowEma, decimal lwma)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var ao = fastEma - slowEma;

		if (!_hasPreviousAo)
		{
			_previousAo = ao;
			_hasPreviousAo = true;
			_isAoIncreasing = ao >= 0m;
			_previousLwma = lwma;
			return;
		}

		if (ao > _previousAo)
			_isAoIncreasing = true;
		else if (ao < _previousAo)
			_isAoIncreasing = false;

		var isTrendBullish = lwma > _previousLwma;
		var isTrendBearish = lwma < _previousLwma;
		var bullishSignal = _isAoIncreasing && ao > 0m && isTrendBullish;
		var bearishSignal = !_isAoIncreasing && ao < 0m && isTrendBearish;

		if (bullishSignal && Position <= 0)
		{
			var volume = Volume + Math.Abs(Position);
			if (volume <= 0)
				volume = 1;

			BuyMarket(volume);
		}
		else if (bearishSignal && Position >= 0)
		{
			var volume = Volume + Math.Abs(Position);
			if (volume <= 0)
				volume = 1;

			SellMarket(volume);
		}

		_previousAo = ao;
		_previousLwma = lwma;
	}
}