Diese Strategie ist eine C#-Konvertierung des MetaTrader-Experts Exp_X2MACandle_MMRec. Sie beobachtet die Farbe einer doppelt geglätteten Kerze, die vom originalen X2MA-Indikator erzeugt wird, um zu entscheiden, wann Positionen geöffnet oder geschlossen werden. Die StockSharp-Version recreiert die duale Glättungspipeline und hält eine leichtgewichtige Geldmanagement-Schicht, die das Handelsvolumen nach einer konfigurierbaren Anzahl von kürzlichen Verlusten reduziert.
Der Algorithmus verarbeitet nur abgeschlossene Kerzen. Er abonniert einen konfigurierbaren Zeitrahmen, wendet zwei verkettete gleitende Durchschnitte auf die OHLC-Werte der Kerze an, leitet eine synthetische Kerzenfarbe (grün, grau oder rot) ab und verwendet Farbübergänge mit einer benutzerwählbaren Balkenverschiesung, um Aktionen auszulösen. Long-Trades werden geöffnet, wenn sich die Farbe von bullisch zu etwas anderem ändert. Short-Trades folgen der symmetrischen Bedingung. Positionsausgänge sind mit denselben Farbprüfungen ausgerichtet und können für jede Seite separat aktiviert oder deaktiviert werden.
Indikatorlogik
Jede Kerze wird zweimal geglättet. Beide Stufen können unterschiedliche Methoden und Längen verwenden.
Glättungsoptionen werden StockSharp-Indikatoren zugeordnet:
Simple → SimpleMovingAverage
Exponential → ExponentialMovingAverage
Smoothed → SmoothedMovingAverage (RMA)
Weighted → WeightedMovingAverage
Jurik → JurikMovingAverage (der Phase-Parameter wird berücksichtigt, wenn verfügbar).
Der synthetische Kerzenkörper wird abgeflacht, wenn der absolute Öffnungs-/Schluss-Unterschied unter GapPoints * Security.StepPrice liegt.
Signale werden auf Balken SignalBar + 1 ausgewertet (zwei Balken zurück mit der Standardeinstellung), sodass Orders nur nach Bestätigung eines vollständigen Kerzenfarbwechsels übermittelt werden.
Geldmanagement
Der ursprüngliche Expert reduzierte die Positionsgröße dynamisch nach einer Verlustserie unter Verwendung historischer Deal-Statistiken. StockSharp stellt die genaue MetaTrader-Historie nicht bereit, daher hält die Portierung eine interne Warteschlange aktueller geschlossener Trades.
Die Warteschlangenlänge wird durch HistoryDepth kontrolliert und das Volumen fällt auf ReducedVolume, sobald LossTrigger oder mehr Verluste innerhalb des Fensters erkannt werden.
Die Strategie erfasst Trade-Ergebnisse anhand von Kerzenschlusskursen, wenn ein manueller Ausstieg ausgelöst wird. Stop-Loss/Take-Profit-Orders aus der MetaTrader-Version werden nicht recreiert. Sie können bei Bedarf eigene Schutzregeln über StockSharp-Risikomanager hinzufügen.
Parameter
Name
Beschreibung
CandleType
Zeitrahmen der Kerzen für Glättung und Handel.
FirstMethod, FirstLength, FirstPhase
Primäre Glättungsmethode, Länge und Jurik-Phase.
SecondMethod, SecondLength, SecondPhase
Sekundäre Glättungsmethode, Länge und Jurik-Phase.
GapPoints
Kerzenkörper-Abflachungsschwelle in Kursschritten.
SignalBar
Verschiebung (0 = letzte abgeschlossene Kerze) beim Lesen der Farbpuffer.
AllowLongEntry / AllowShortEntry
Öffnen von Long- oder Short-Positionen aktivieren.
AllowLongExit / AllowShortExit
Schließen von Long- oder Short-Positionen aktivieren.
NormalVolume
Standard-Ordergröße (Lots, Aktien, Kontrakte).
ReducedVolume
Ordergröße nach der konfigurierten Anzahl von Verlusten.
HistoryDepth
Anzahl der für Verluste inspizierten jüngsten Trades (0 deaktiviert die Historienverfolgung).
LossTrigger
Verlustanzahl, die das reduzierte Volumen aktiviert (0 deaktiviert den Schalter).
Verwendungshinweise
Die Strategie operiert auf einem einzelnen Wertpapier, das von GetWorkingSecurities() zurückgegeben wird.
Signale und Ausstiege werden einmal pro abgeschlossener Kerze verarbeitet, um doppelte Orders zu vermeiden.
ReducedVolume gleich NormalVolume setzen, wenn die Volumenreduzierung deaktiviert werden soll, während die Historienstatistiken beibehalten werden.
Da die Portierung auf Kerzenschlusskursen basiert, um Trades zu klassifizieren, kann der Verlustzähler leicht von MetaTrader abweichen, wenn Slippage oder Teilausführungen auftreten. Die Dokumentation sollte helfen, Parameter anzupassen, um ähnliches Verhalten zu erzielen.
Stops und Take-Profits aus der MQL-Version werden nicht automatisch recreiert. StockSharp-Risikomanager (StartProtection) verwenden, wenn Plattform-Level-Schutz benötigt wird.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ExpX2MaCandleMmRecStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _prevSlow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public ExpX2MaCandleMmRecStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 25).SetGreaterThanZero().SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null; _prevSlow = null;
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); 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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_x2_ma_candle_mm_rec_strategy(Strategy):
def __init__(self):
super(exp_x2_ma_candle_mm_rec_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", 8) \
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(exp_x2_ma_candle_mm_rec_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(exp_x2_ma_candle_mm_rec_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = WeightedMovingAverage()
fast.Length = self.FastPeriod
slow = WeightedMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return exp_x2_ma_candle_mm_rec_strategy()