Portierung des MT4-Expert-Advisors "5MIN SCALPING" (MQL ID 22828) auf die StockSharp High-Level-API. Die Strategie sucht nach schnellen Ausbruchs-Setups im primären Zeitrahmen, bestätigt diese mit dem Momentum eines übergeordneten Zeitrahmens und der monatlichen MACD-Richtung, bevor sie in den Markt eintritt.
Kategorie: Ausbruchs-Scalping / Momentum
Originalplattform: MetaTrader 4
Datenanforderungen: Tick- oder Kerzen-Feed für alle konfigurierten Zeitrahmen (Standard 5 Minuten, 30 Minuten, 1 Monat)
Handelslogik
Trendfilter. Zwei Linear-Gewichtete Gleitende Durchschnitte (LWMA) mit konfigurierbaren Längen (Standard 6 und 85) definieren den vorherrschenden Trend. Longs erfordern, dass der schnelle LWMA über dem langsamen bleibt, Shorts erfordern das umgekehrte Verhältnis.
Multi-Balken-Strukturfilter. Das interne LWMA-Triplett (Längen 8, 13, 21) wird über die letzten 20 abgeschlossenen Kerzen bewertet. Der Algorithmus imitiert die scalper()-Funktion der MQL-Version:
Bullisches Setup: Jeder Balken innerhalb der Schleife muss LWMA8 > LWMA13 > LWMA21 erfüllen, das Kerzentief zieht sich zum gleitenden Durchschnitts-Stapel zurück, und der aktuelle Schlusskurs bricht über das höchste Hoch der vorherigen 5 Kerzen aus.
Bärisches Setup: Spiegellogik mit Hochs, die in den LWMA-Stapel eindringen, und dem aktuellen Schlusskurs, der unter das niedrigste Tief der vorherigen 5 Kerzen ausbricht.
Überlappungsschutz. Eine kleine Überlappungsbedingung (Low[2] < High[1] für Longs, Low[1] < High[2] für Shorts) verhindert Einstiege in isolierten Spitzen.
Momentum-Bestätigung. Ein Momentum-Indikator des übergeordneten Zeitrahmens (Standard 30-Minuten-Kerzen, Länge 14) muss zeigen, dass mindestens einer der letzten drei Werte von der Basislinie 100 stärker abweicht als die konfigurierten Schwellenwerte (Standard 0.3).
Makro-MACD-Ausrichtung. Ein monatliches MACD(12, 26, 9)-Histogramm wird via MovingAverageConvergenceDivergenceSignal berechnet. Long-Trades erfordern, dass die MACD-Linie über der Signallinie liegt, Short-Trades erfordern das Gegenteil.
Positionsaggregation. Der Eintritt in die Gegenrichtung schließt zunächst das bestehende Engagement und eröffnet unmittelbar danach den neuen Trade mit dem konfigurierten Volumen.
Risikomanagement
Statische Ziele. Optionale Take-Profit- und Stop-Loss-Levels in Pips (intern über den PriceStep des Instruments konvertiert).
Break-Even-Modul. Wenn aktiviert, wird der Stop auf Einstieg ± Offset verschoben, sobald der Preis eine konfigurierbare Anzahl von Pips zurücklegt.
Trailing Stop. Optionaler Trailing Stop, der die Position in einem festen Pip-Abstand verfolgt, sobald sich der Markt bewegt.
Manuelle Ausstiege. Alle Ausstiege werden innerhalb der Strategie verwaltet, ohne schützende Orders zu platzieren, was das Verhalten des ursprünglichen EA widerspiegelt.
Parameter
Parameter
Standard
Beschreibung
CandleType
5-Minuten-Zeitrahmen
Primärer Zeitrahmen, auf dem Ausbrüche erkannt werden.
MomentumCandleType
30-Minuten-Zeitrahmen
Kerzentyp für den übergeordneten Momentum-Filter.
MacroMacdCandleType
1-Monats-Zeitrahmen
Kerzentyp für die langfristige MACD-Bestätigung.
FastMaLength
6
Länge des schnellen LWMA-Trendfilters.
SlowMaLength
85
Länge des langsamen LWMA-Trendfilters.
MomentumLength
14
Lookback-Periode für den Momentum-Indikator.
MomentumBuyThreshold
0.3
Mindestabweichung
Momentum-100
zur Bestätigung von Long-Trades.
MomentumSellThreshold
0.3
Mindestabweichung
Momentum-100
zur Bestätigung von Short-Trades.
TakeProfitPips
50
Take-Profit-Distanz in Pips. Auf 0 setzen zum Deaktivieren.
StopLossPips
20
Stop-Loss-Distanz in Pips. Auf 0 setzen zum Deaktivieren.
TrailingStopPips
40
Trailing-Stop-Distanz in Pips. Nur wirksam wenn EnableTrailing wahr ist.
EnableTrailing
true
Aktiviert oder deaktiviert die Trailing-Stop-Logik.
EnableBreakEven
true
Aktiviert automatisches Break-Even-Management.
BreakEvenTriggerPips
30
Gewinn in Pips, bevor der Stop zum Break-Even verschoben wird.
BreakEvenOffsetPips
30
Zusätzlicher Puffer (in Pips) beim Verschieben des Stops zum Break-Even.
TradeVolume
1
Ordervolumen für Einstiege.
Verwendung
Die Strategie zum StockSharp-Projekt hinzufügen und mit dem gewünschten Instrument verbinden.
Sicherstellen, dass historische Daten für alle konfigurierten Kerzentypen vor dem Start der Strategie verfügbar sind.
Volumen, Zeitrahmen und Schwellenwerte entsprechend der Volatilität des gehandelten Instruments konfigurieren.
Die Strategie starten. Sie abonniert alle erforderlichen Kerzenserien, zeichnet Indikatoren auf dem Chart (wenn verfügbar) und verwaltet Einstiege/Ausstiege automatisch.
Unterschiede zum ursprünglichen EA
Die geldbasierten Trailing-Module (Take_Profit_In_Money, TRAIL_PROFIT_IN_MONEY2) und der Equity-Stop der MQL-Version sind nicht portiert. Das Risiko wird über Pip-Distanzen verwaltet.
Die Martingal-ähnliche Lot-Skalierung (Lots * MathPow(LotExponent, CountTrades())) ist nicht implementiert. TradeVolume manuell anpassen, wenn dynamisches Positionsmanagement benötigt wird.
E-Mail-/Benachrichtigungs-Alerts aus dem Originalcode werden weggelassen. StockSharp-Benachrichtigungsinfrastruktur bei Bedarf verwenden.
Die Strategie ist auf den PriceStep des Instruments zur Pip-Konvertierung angewiesen. Sicherstellen, dass die Instrument-Metadaten in der Verbindungsumgebung korrekt gefüllt sind.
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;
/// <summary>
/// 5-minute scalping strategy using fast/slow WMA crossover with momentum confirmation.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class FiveMinScalpingStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private WeightedMovingAverage _fast;
private WeightedMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast WMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow WMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="FiveMinScalpingStrategy"/> class.
/// </summary>
public FiveMinScalpingStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast WMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 85)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow WMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new WeightedMovingAverage { Length = FastPeriod };
_slow = new WeightedMovingAverage { 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;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// WMA crossover buy
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
// WMA crossover sell
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class five_min_scalping_strategy(Strategy):
"""
5-minute scalping using fast/slow WMA crossover with SL/TP and cooldown.
Buys on bullish crossover, sells on bearish crossover.
"""
def __init__(self):
super(five_min_scalping_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20) \
.SetDisplay("Fast Period", "Fast WMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 85) \
.SetDisplay("Slow Period", "Slow WMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 500) \
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Trading timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(five_min_scalping_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(five_min_scalping_strategy, self).OnStarted2(time)
fast = WeightedMovingAverage()
fast.Length = self._fast_period.Value
slow = WeightedMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = float(fast_val)
self._prev_slow = float(slow_val)
return
fast_val = float(fast_val)
slow_val = float(slow_val)
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None:
step = float(self.Security.PriceStep)
if step <= 0:
step = 1.0
sl_pts = self._stop_loss_points.Value
tp_pts = self._take_profit_points.Value
if self.Position > 0 and self._entry_price > 0:
if sl_pts > 0 and close <= self._entry_price - sl_pts * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if tp_pts > 0 and close >= self._entry_price + tp_pts * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if sl_pts > 0 and close >= self._entry_price + sl_pts * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if tp_pts > 0 and close <= self._entry_price - tp_pts * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 60
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return five_min_scalping_strategy()