Auf GitHub ansehen

Simple-2-MA-I-Strategie

Überblick

Simple 2 MA I ist eine Trendfolge-Strategie, die die Kernlogik des ursprünglichen MetaTrader Expert Advisors repliziert. Sie verwendet ein Paar linear gewichteter gleitender Durchschnitte (LWMAs), die auf typischen Preisen berechnet werden, um den dominanten Trend zu erkennen. Momentum-Bestätigung und MACD-Richtungsfilter entfernen schwache Signale. Optional verwaltet die Strategie Risiko über automatische Stop-Loss-, Take-Profit-, Break-even-Bewegungen und kerzenbasierte Trailing Stops.

Handelslogik

Long-Setup

  1. Die schnelle LWMA liegt über der langsamen LWMA und bestätigt einen Aufwärtstrend.
  2. Das Tief der Kerze vor zwei Bars liegt unter dem Hoch der vorherigen Bar und signalisiert frische bullische Struktur.
  3. Mindestens eine der letzten drei Rate-of-Change-Messungen liegt über dem konfigurierten Momentum-Schwellenwert.
  4. Die MACD-Linie liegt über der Signallinie.
  5. Das Nettopositionsvolumen liegt unter dem Limit Max Net Volume.

Wenn alle Bedingungen erfüllt sind, schließt die Strategie Short-Exposure (falls vorhanden) und kauft zum Markt.

Short-Setup

  1. Die schnelle LWMA liegt unter der langsamen LWMA und bestätigt einen Abwärtstrend.
  2. Das Tief der vorherigen Bar liegt unter dem Hoch der Bar vor zwei Perioden und zeigt bärische Struktur.
  3. Mindestens eine der letzten drei Rate-of-Change-Messungen liegt über dem Momentum-Schwellenwert (absoluter Wert).
  4. Die MACD-Linie liegt unter der Signallinie.
  5. Das Nettopositionsvolumen liegt unter Max Net Volume.

Wenn die Bedingungen gelten, deckt die Strategie Longs (falls vorhanden) und verkauft zum Markt.

Risikomanagement

  • Stop-Loss / Take-Profit: optionale feste Distanzen in Punkten relativ zum Einstiegspreis.
  • Break-even: Sobald der Preis die Trigger-Distanz im Gewinn erreicht, wird der Stop auf Einstieg ± Offset verschoben.
  • Kerzen-Trailing: Nach Erreichen der Aktivierungsdistanz folgt der Stop Kerzenextremen mit einem konfigurierbaren Puffer.
  • Schutzorders werden automatisch storniert, sobald die Position geschlossen ist.

Parameter

Name Beschreibung Standard
Candle Type Zeitrahmen für Indikatorberechnungen. 15-Minuten-Kerzen
Fast LWMA Periode der schnellen LWMA. 6
Slow LWMA Periode der langsamen LWMA. 85
Momentum Length Rückblickperiode für den Rate-of-Change-Indikator. 14
Momentum Threshold Erforderlicher minimaler absoluter Rate-of-Change-Wert. 0.3
MACD Fast Schnelle EMA-Länge in MACD. 12
MACD Slow Langsame EMA-Länge in MACD. 26
MACD Signal Signal-EMA-Länge in MACD. 9
Use Stop-Loss Aktiviert das Platzieren von Stop-Loss-Orders. true
Stop-Loss (points) Distanz vom Einstiegspreis zum Stop-Loss. 20
Use Take-Profit Aktiviert das Platzieren von Take-Profit-Orders. true
Take-Profit (points) Distanz vom Einstiegspreis zum Take-Profit. 50
Use Break-Even Aktiviert die automatische Break-even-Bewegung. true
Break-Even Trigger Gewinn (Punkte), der vor Break-even erforderlich ist. 30
Break-Even Offset Offset (Punkte), der beim Verschieben auf Break-even hinzugefügt wird. 30
Use Candle Trailing Aktiviert Trailing Stops auf Basis von Kerzenextremen. true
Trailing Activation Gewinn (Punkte), der vor Aktivierung von Trailing erforderlich ist. 40
Trailing Padding Zusätzliche Distanz (Punkte), die zum Kerzenextrem hinzugefügt wird. 10
Max Net Volume Maximal zulässiges absolutes Nettovolumen. 1

Hinweise

  • Alle Preisdistanzen werden in Wertpapier-Preisschritten (Punkten) ausgedrückt. Die Strategie multipliziert Parameterwerte automatisch mit der Tickgröße des Wertpapiers.
  • Die Standard-Zeitrahmenzuordnung folgt den ursprünglichen Expert-Defaults, kann aber frei angepasst werden.
  • Die Strategie erwartet abgeschlossene Kerzen. Unvollendete Bars werden ignoriert, um mit dem Quell-EA konsistent zu bleiben.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class Simple2MaIStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public Simple2MaIStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}