Diese Strategie ist ein C#-Port des MetaTrader 5-Expertenberaters 3sma.mq5 (id 21495). Sie verfolgt dieselbe Idee, zu handeln, wenn sich drei einfache gleitende Durchschnitte um einen konfigurierbaren Spread voneinander trennen. Die Implementierung verwendet die StockSharp-High-Level-API mit Kerzen-Abonnements und Indikator-Bindung, sodass keine manuelle Serienverwaltung erforderlich ist.
Ursprüngliches MT5-Verhalten
Der MT5-Experte basiert auf drei einfachen gleitenden Durchschnitten mit verschiedenen Perioden und Anzeigeverschiebungen. Der schnelle Durchschnitt verwendet den aktuellen Balken, während der mittlere und langsame Durchschnitt um einen und zwei Balken in die Vergangenheit verschoben sind. Bei jedem Tick:
Konvertiert den benutzerdefinierten Spread von Pips in Preiseinheiten basierend auf der Symbolpräzision.
Schließt Long-Positionen, wenn der schnelle SMA um mindestens die Hälfte des Spreads unter den mittleren SMA fällt, und schließt Short-Positionen, wenn der schnelle SMA um die Hälfte des Spreads über den mittleren SMA steigt.
Öffnet neue Long-Positionen, wenn MA1 > MA2 + spread und MA2 > MA3 + spread, solange keine anderen Long-Trades des Experten bestehen. Analog öffnet er Short-Positionen, wenn alle drei Durchschnitte in der entgegengesetzten Reihenfolge ausgerichtet sind.
Verwendet nur Marktorders mit einer festen Losgröße und wendet keine expliziten Stop-Loss- oder Take-Profit-Level an.
StockSharp-Implementierung
Indikatoren – drei SimpleMovingAverage-Instanzen abonnieren dieselbe Kerzenquelle. Kompakte Verlaufspuffer reproduzieren die MT5-"Shift"-Parameter, sodass jeder Vergleich fertige Balkenwerte aus den angeforderten Offsets verwendet.
Spread-Handhabung – der Spread-Parameter wird in Pips eingegeben. Die Strategie leitet eine Pip-Größe aus Security.PriceStep (oder Security.Step) ab und multipliziert sie mit zehn für 3/5-stellige FX-Symbole, was der MT5-Anpassung für Bruchteils-Quotes entspricht.
Order-Fluss – Orders werden mit BuyMarket/SellMarket eingereicht. Wenn eine Umkehrbedingung erscheint, fügt die Strategie den Absolutwert der aktuellen Nettoposition zum Basisvolumen hinzu, um das entgegengesetzte Exposure aufzulösen und die neue Richtung mit einer einzigen Marktorder zu etablieren.
Visualisierung – wenn Charts verfügbar sind, zeichnet die Strategie die Quellkerzen zusammen mit den drei gleitenden Durchschnitten und ausgeführten Trades.
Parameter
Name
Beschreibung
Standard
Volume
Ordervolumen für jeden Markteinstieg.
0.1
FastMaPeriod
Periode des schnellen SMA (entspricht MA1 in MT5).
9
FastMaShift
Anzahl der fertigen Balken zur Verschiebung des schnellen SMA.
0
MiddleMaPeriod
Periode des mittleren SMA (MA2).
14
MiddleMaShift
Verschiebung in fertigen Balken für den mittleren SMA.
1
SlowMaPeriod
Periode des langsamen SMA (MA3).
29
SlowMaShift
Verschiebung in fertigen Balken für den langsamen SMA.
2
MaSpreadPips
Minimal erforderlicher Spread zwischen aufeinanderfolgenden SMAs in Pips.
10
CandleType
Kerzenserie für Berechnungen.
1 Minuten-Zeitrahmen
Handelslogik
Warten bis alle drei gleitenden Durchschnitte gebildet sind und die Verlaufspuffer Werte für die angeforderten Verschiebungen enthalten.
Den Spread-Parameter von Pips in Preiseinheiten konvertieren und den Halb-Spread für Exit-Filter berechnen.
Exit-Filter –
Long-Exposure schließen, wenn der verschobene schnelle SMA um mindestens die Hälfte des Spreads unter den verschobenen mittleren SMA fällt.
Short-Exposure schließen, wenn der verschobene schnelle SMA um mindestens die Hälfte des Spreads über den verschobenen mittleren SMA steigt.
Eintrittsbedingungen –
Long einsteigen (oder von Short zu Long umkehren), wenn der schnelle SMA größer als der mittlere SMA plus Spread und der mittlere SMA größer als der langsame SMA plus Spread ist.
Short einsteigen (oder von Long zu Short umkehren), wenn der schnelle SMA kleiner als der mittlere SMA minus Spread und der mittlere SMA kleiner als der langsame SMA minus Spread ist.
Unterschiede zur MT5-Version
StockSharp arbeitet mit einer einzigen Nettoposition pro Wertpapier. Wenn ein Umkehrsignal erscheint, gibt die Strategie eine einzige Marktorder aus, die so dimensioniert ist, dass sie das vorherige Netto-Exposure auflöst und die neue Richtung etabliert. Der MT5-Experte konnte unabhängige Long- und Short-Positionen halten.
Die Pip-Konvertierung verwendet die besten verfügbaren Security-Metadaten. Wenn der Broker weder PriceStep noch Step bereitstellt, wird 1 als Fallback verwendet.
Orders werden auf fertigen Kerzen statt bei jedem Tick eingereicht, da die High-Level-API auf Kerzen-Abonnements basiert.
Die Strategie implementiert nicht die ausführlichen Protokollierungshelfer aus dem MT5-Code; StockSharp-integrierte Protokollierung kann bei Bedarf verwendet werden.
Nutzungshinweise
Sicherstellen, dass die ausgewählte Kerzenserie dem in der ursprünglichen MT5-Einrichtung verwendeten Zeitrahmen entspricht.
Den Spread-Parameter anpassen, wann immer das Instrument nicht standardmäßige Pip-Größen verwendet.
Da die Strategie mit fertigen Kerzen arbeitet, wird die Ausführung verzögert, bis die aktuelle Kerze schließt.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Triple SMA strategy that trades when three moving averages are properly aligned.
/// Enters long when fast > middle > slow, enters short when fast < middle < slow.
/// </summary>
public class TripleSmaSpreadStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _middlePeriod;
private readonly StrategyParam<int> _slowPeriod;
private int _prevSignal;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int MiddlePeriod
{
get => _middlePeriod.Value;
set => _middlePeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public TripleSmaSpreadStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_middlePeriod = Param(nameof(MiddlePeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Middle Period", "Middle SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 29)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSignal = 0;
var fastSma = new ExponentialMovingAverage { Length = FastPeriod };
var slowSma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var signal = 0;
if (fast > slow && close > fast)
signal = 1;
else if (fast < slow && close < fast)
signal = -1;
if (signal == _prevSignal)
return;
var oldSignal = _prevSignal;
_prevSignal = signal;
if (signal == 1 && oldSignal <= 0)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (signal == -1 && oldSignal >= 0)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 triple_sma_spread_strategy(Strategy):
def __init__(self):
super(triple_sma_spread_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 9) \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._middle_period = self.Param("MiddlePeriod", 14) \
.SetDisplay("Middle Period", "Middle SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 29) \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._prev_signal = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def MiddlePeriod(self):
return self._middle_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(triple_sma_spread_strategy, self).OnReseted()
self._prev_signal = 0
def OnStarted2(self, time):
super(triple_sma_spread_strategy, self).OnStarted2(time)
self._prev_signal = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
fv = float(fast_value)
sv = float(slow_value)
signal = 0
if fv > sv and close > fv:
signal = 1
elif fv < sv and close < fv:
signal = -1
if signal == self._prev_signal:
return
old_signal = self._prev_signal
self._prev_signal = signal
if signal == 1 and old_signal <= 0:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif signal == -1 and old_signal >= 0:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return triple_sma_spread_strategy()