Auf GitHub ansehen

Crypto-Scalper-Momentum-Strategie

Überblick

Die Crypto-Scalper-Momentum-Strategie repliziert den ursprünglichen MetaTrader-Expert-Advisor "Crypto Scalper", indem sie Money Flow Index, Momentum und Multi-Zeitrahmen-MACD-Filter kombiniert. Sie arbeitet auf einem primären Intraday-Zeitrahmen, bestätigt kurzfristiges Momentum auf einem höheren Zeitrahmen und respektiert einen Makrotrendfilter aus einem langsamen MACD. Mehrere Risikomanagement-Funktionen der MQL-Implementierung wurden beibehalten, darunter währungsbasierte Basket-Ziele, Geld-Trailing, Break-even-Stops und Equity-Drawdown-Schutz.

Handelslogik

  1. Primäre Indikatoren
    • Money Flow Index (MFI) im Hauptzeitrahmen mit Standardwert 14 Perioden.
    • MACD im Hauptzeitrahmen (EMA-Konfiguration 12/26/9).
  2. Momentum des höheren Zeitrahmens
    • Momentum-Indikator auf einer separaten Kerzenserie. Die absolute Entfernung von der MetaTrader-Basislinie (100) muss eine konfigurierbare Schwelle überschreiten.
  3. Makrotrendfilter
    • Ein langsamer MACD auf einem Makrozeitrahmen (standardmäßig täglich) verhindert Trades gegen den höheren Trend und erzwingt Liquidation bei Umkehr.
  4. Einstiegsregeln
    • Longs: Mindestens einer der letzten drei MFI-Werte liegt unter der Überverkauft-Schwelle, die Momentum-Abweichung überschreitet die Schwelle, die primäre MACD-Linie liegt über der Signallinie und der Makro-MACD ist bullisch.
    • Shorts: gespiegelte Bedingungen mit Überkauft-Schwellen und bärischen MACD-Bestätigungen.
  5. Ausstiegsregeln
    • Fester Stop-Loss und Take-Profit in Pips.
    • Optionaler Trailing Stop entweder über Kerzenextreme oder als klassischer distanzbasierter Trail.
    • Break-even-Verschiebung nach einer konfigurierbaren günstigen Bewegung.
    • Eine Umkehr des Makro-MACD schließt bestehende Exposure.
    • Währungsziele, Prozentziele und Trailing-Gewinn in Geld replizieren die MQL-Funktionen.
    • Ein Equity-Drawdown-Wächter schließt alle Trades, wenn das Konto um einen vorgegebenen Prozentsatz vom Hoch zurückläuft.

Risikomanagement

  • Stops/Ziele: konfigurierbare Pip-Distanzen mit optionaler Aktivierung.
  • Trailing: kerzenbasiert (niedrigstes Tief/höchstes Hoch der jüngsten Kerzen) oder klassisches Pip-Trailing.
  • Break-even: verschiebt Stops, um Gewinne zu sichern, sobald die Triggerdistanz erreicht ist.
  • Geldmanagement: Basket-Take-Profit in Währung, Prozent der Anfangsequity und Trailing-Gewinn in Geld.
  • Equity-Stop: überwacht die höchste beobachtete Equity und schließt Trades, sobald der Drawdown den erlaubten Prozentsatz überschreitet.

Parameter

Name Beschreibung
CandleType Primäre Kerzenserie für Einstiege.
MomentumCandleType Kerzen des höheren Zeitrahmens für den Momentum-Indikator.
MacroCandleType Kerzen des langsamen Zeitrahmens für den Makro-MACD-Filter.
MfiPeriod Länge des Money Flow Index.
MfiOversold / MfiOverbought Oszillatorschwellen (Standard 30 / 70).
MomentumPeriod Momentum-Länge im höheren Zeitrahmen.
MomentumThreshold Mindestabweichung von der 100-Linie, die der Momentum-Filter verlangt.
MomentumReference Basiswert (MetaTrader-Standard ist 100).
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod MACD-Parameter im Handelszeitrahmen.
MacroMacdFastPeriod / MacroMacdSlowPeriod / MacroMacdSignalPeriod MACD-Parameter im Makrozeitrahmen.
TradeVolume Volumen jeder Marktorder (Lots).
MaxTrades Maximale gleichzeitige Trades pro Richtung (0 = unbegrenzt).
UseStopLoss / StopLossPips Aktiviert und konfiguriert den Schutzstop.
UseTakeProfit / TakeProfitPips Aktiviert und konfiguriert das Schutzziel.
UseTrailingStop Hauptschalter für die Trailing-Logik.
UseCandleTrail Wechsel zwischen Kerzenextrem-Trailing und klassischem Trailing.
TrailTriggerPips / TrailAmountPips Triggerdistanz und vom klassischen Trailing Stop gehaltene Distanz.
CandleTrailLength / CandleTrailBufferPips Anzahl Kerzen und zusätzlicher Puffer für kerzenbasiertes Trailing.
UseBreakEven / BreakEvenTriggerPips / BreakEvenOffsetPips Break-even-Aktivierungsdistanz und gesicherter Gewinn.
UseMoneyTakeProfit / MoneyTakeProfit Basket-Take-Profit in Kontowährung.
UsePercentTakeProfit / PercentTakeProfit Basket-Take-Profit in Prozent der Anfangsequity.
EnableMoneyTrailing / MoneyTrailTarget / MoneyTrailStop Trailing des schwebenden Gewinns in Währung.
UseEquityStop / EquityRiskPercent Equity-Drawdown-Schutz relativ zum beobachteten Hoch.
ForceExit Stellt Positionen beim nächsten Kerzenschluss sofort glatt.

Hinweise

  • Pip-Distanzen werden mit PriceStep des Instruments umgerechnet. Ein Fallback von 0.0001 wird verwendet, wenn der Broker keinen Preisschritt liefert, entsprechend der Punktbehandlung in MetaTrader.
  • Das Makro-MACD-Abonnement kann auf Monatskerzen zeigen, um den ursprünglichen EA nachzuahmen. Tageskerzen sind Standard, weil Monatsbalken nicht in allen Datenfeeds verfügbar sind.
  • Alle Kommentare im Code sind absichtlich auf Englisch geschrieben, um die Repository-Regeln einzuhalten.
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 CryptoScalperMomentumStrategy : 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 CryptoScalperMomentumStrategy()
	{
		_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;
	}
}