Diese Strategie ist ein C#-Port des MetaTrader-Expertenberaters "MACD 1 MIN SCALPER". Sie kombiniert gewichtete gleitende Durchschnitte mit Multi-Timeframe-MACD-Bestätigungen und einem Momentum-Filter vor der Eröffnung von Trades. Das Ziel ist, in Trendrichtung zu handeln, wenn Indikatoren auf niedrigerem und höherem Zeitrahmen ausgerichtet sind und das Kurs-Momentum ausreichend stark ist.
Handelslogik
Basis-Zeitrahmen – konfigurierbar (Standard M1). Zwei gewichtete gleitende Durchschnitte (WMA) mit den Perioden 50 und 200, berechnet auf dem typischen Preis (Hoch + Tief + Schluss) / 3, definieren den kurzfristigen Trend.
Trend-Filter höherer Zeitrahmen – WMAs mit denselben Perioden werden auf dem H1-Zeitrahmen berechnet. Long-Setups erfordern, dass beide schnellen WMAs über ihren langsamen Pendants liegen, Shorts erfordern das Gegenteil. Wenn der Arbeits-Zeitrahmen bereits H1 ist, werden die Basis-WMAs wiederverwendet.
MACD-Bestätigungen – der MACD (12, 26, 9) muss seine Hauptlinie über der Signallinie auf dem Basis-Zeitrahmen, dem H1-Zeitrahmen und einem monatlichen Zeitrahmen (ca. 43200 Minuten) haben. Short-Einstiege erfordern, dass alle drei MACDs unter ihren Signalen liegen.
Momentum-Filter – ein Momentum-Indikator mit Periode 14 operiert auf einem höheren Zeitrahmen, der aus dem MetaTrader-Basis-Zeitrahmen abgeleitet wird (M1→M15, M5→M30, …). Die absolute Abweichung von 100 muss einen konfigurierbaren Schwellenwert auf mindestens einem der letzten drei abgeschlossenen Bars überschreiten.
Einstiegsregeln – eine Long-Position wird eröffnet, wenn alle bullischen Bedingungen erfüllt sind und die Strategie aktuell keine Long-Exposition hat. Eine Short-Position erfordert die gespiegelten bärischen Bedingungen. Wenn eine entgegengesetzte Position offen ist, schließt die Ordergröße automatisch die zum Schließen benötigte Menge ein.
Risikomanagement – optionale Stop-Loss- und Take-Profit-Abstände werden in Pips angegeben und beim Start in Instrument-Punkte umgerechnet. Trailing-, Breakeven- und Geldverwaltungsfunktionen aus dem Originalskript werden in diesem High-Level-Port bewusst weggelassen.
Parameter
Parameter
Beschreibung
CandleType
Arbeitszeitrahmen für die Basisindikatoren.
OrderVolume
Volumen, das bei jedem Markteinstieg gesendet wird. Auch zum Schließen/Umkehren von Positionen verwendet.
FastMaPeriod / SlowMaPeriod
Längen der schnellen und langsamen gewichteten gleitenden Durchschnitte.
Momentum-Indikatorlänge auf dem Bestätigungs-Zeitrahmen.
MomentumThreshold
Minimale absolute Abweichung von 100, die erforderlich ist, um Momentum zu akzeptieren.
TakeProfitPips / StopLossPips
Optionale Schutz-Niveaus in Pips.
Implementierungshinweise
Die Strategie stützt sich auf StockSharpss High-Level-Kerzenabonnements (SubscribeCandles) und Indikatoranbindung (Bind / BindEx). Keine manuellen Indikatorberechnungen oder historischen Puffer werden verwendet.
Der Momentum-Zeitrahmen wird aus dem MetaTrader-Mapping abgeleitet: [1,5,15,30,60,240,1440,10080,43200]. Wenn ein Wert außerhalb dieser Liste liegt, wird ein 4×-Multiplikator des Basis-Zeitrahmens als Fallback verwendet.
StartProtection wird nur gestartet, wenn mindestens einer der Risikoparameter größer als null ist. In diesem Port gibt es keine Trailing-Stop-Implementierung.
Diagramm-Rendering ist für die Basis-Kerzen, beide WMAs und den MACD aktiviert, um visuelle Inspektion während des Debuggings oder Live-Tradings zu erleichtern.
Nutzungstipps
Den Parameter OrderVolume entsprechend der Mindestlosgröße des Instruments einstellen. Der Helfer passt automatisch das gesendete Volumen an, um es dem Schritt- und Min/Max-Constraints des Symbols anzupassen.
Sicherstellen, dass Daten höherer Zeitrahmen (H1 und monatlich) im Datenfeed verfügbar sind. Ohne diese Kerzen wird die Strategie keine Positionen eröffnen, da die Bestätigungssignale unvollständig bleiben.
Momentum-Filterung ist sensitiv gegenüber dem gewählten Schwellenwert. Höhere Werte erfordern stärkere Momentum-Schübe, während niedrigere Werte zu häufigeren Trades führen.
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 Macd1MinScalperStrategy : 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 Macd1MinScalperStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).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;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class macd_1_min_scalper_strategy(Strategy):
def __init__(self):
super(macd_1_min_scalper_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "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(macd_1_min_scalper_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(macd_1_min_scalper_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._fast_ind.IsFormed or not self._slow_ind.IsFormed:
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return macd_1_min_scalper_strategy()