Multi-Strategie-Kombinationsstrategie
Überblick
Die Multi Strategy Combo Strategy ist eine C#-Konvertierung des Expertenberaters MetaTrader 4 „Multi-Strategy iFSF“. Das Original EA kombiniert mehrere Indikatoren (MA, RSI, MACD, Stochastic, SAR) und umhüllt sie mit Trend-, Bollinger-Bereichs- und Rauschfiltern. Der StockSharp-Port bewahrt die gleiche Idee unter Verwendung von SubscribeCandles().Bind(...)-Streams und Indikatorklassen auf hoher Ebene. Jeder aktivierte Indikator erzeugt eine KAUF/VERKAUF-Abstimmung; Erst wenn alle Stimmen übereinstimmen, führt die Strategie einen Auftrag aus. Zusätzliche Filter emulieren die Kombinationsmodi des EA.
Kernlogik
- Konsens-Engine – Die gleitenden Durchschnitte RSI, MACD, Stochastic und Parabolic SAR liefern jeweils ein diskretes Signal. Wenn alle aktivierten Indikatoren auf KAUFEN (oder VERKAUFEN) übereinstimmen, wird der Konsens bullisch (oder bärisch).
- Kombinationsfaktor (1–3) – Spiegelt die
Combo_Trader_Factor-Logik von EA wider. Jeder Faktor mischt Konsens mit ADX-Trenderkennung und Bollinger-Bereichsbestätigung unterschiedlich:
- Faktor 1 bevorzugt Trendbedingungen. Bereichszustände basieren auf Bollinger Umkehrungen, wenn sie aktiviert sind.
- Faktor 2 erfordert eine stärkere Bestätigung: Trend- und Bereichsfilter müssen mit dem Konsens übereinstimmen.
- Faktor 3 ist die strengste Variante und erfordert eine Abstimmung zwischen allen aktiven Modulen.
- Trenderkennung – ADX in einem konfigurierbaren Zeitrahmen kennzeichnet den Markt als aufwärts/abwärts tendierend oder aufwärts/abwärts tendierend.
- Bollinger-Filter – Verwendet mittlere (2σ) und breite (3σ) Bänder. Long-Signale erfordern einen Absprung vom unteren Band, der durch die jüngsten überverkauften RSI-Werte bestätigt wird; Shorts spiegeln das Verhalten am oberen Band wider.
- Rauschfilter – ATR-basierte Prüfung, die neue Trades blockiert, wenn die Volatilität zu gering ist (Ersatz für das Damiani Volatmeter).
- Auto-Close – Wenn diese Option aktiviert ist, wird die Strategie sofort beendet, wenn der Konsens in die entgegengesetzte Richtung wechselt.
Indikatoren und Signale
- Gleitende Durchschnitte – Drei konfigurierbare MAs (Methode + Länge). Die Modi 1–5 reproduzieren die ursprünglichen Crossover-Kombinationen (schnell vs. mittel, mittel vs. langsam, aggregierte Logik).
- RSI – Die Modi 1–4 decken Überkauft/Überverkauft, Momentum, kombiniert und Zonenprüfungen ab. Alle Schwellenwerte sind einstellbar.
- MACD – Vier Modi ahmen den EA nach: Trendsteigung, Histogrammkreuzung unter/über Null, kombinierte Bestätigung und Nulldurchgang der Signallinie.
- Stochastic-Oszillator – Entweder einfache Kreuzung von %K vs. %D oder Kreuzung mit hohen/niedrigen Schwellenwerten.
- Parabolic SAR – Optionale Richtungsabstimmung, die das Verhalten „Letztes Signal merken“ unterstützt, um mehrere Auslöser pro Trend zu vermeiden.
Risikomanagement
- Optionale Stop-Loss-/Take-Profit-Offsets (absoluter Preisabstand), konfiguriert über
StopLossOffset und TakeProfitOffset.
- Integrierte Trailing-Stop-Unterstützung durch den StockSharp
StartProtection-Helfer.
- Der tägliche Positionsschutz folgt der Basismechanik
Strategy; Es ist keine manuelle Chargenverwaltung erforderlich.
Schlüsselparameter
- Allgemein –
ComboFactor, CandleType.
- Gleitende Durchschnitte –
UseMa, MaMode, individuelle Längen/Methoden, Kerzenzeitrahmen, Flag „Letztes merken“.
- RSI –
UseRsi, RsiMode, RsiPeriod, überkaufte/überverkaufte Ebenen, Zonenschwellenwerte, Flag „Letztes merken“.
- MACD –
UseMacd, MacdMode, schnell/langsam/Signallängen, Kerzenzeitrahmen, Flag „Letztes merken“.
- Stochastic –
UseStochastic, Glättungsparameter, Schwellenwerte und Kerzenzeitrahmen.
- SAR –
UseSar, Beschleunigungseinstellungen, Kerzenzeitrahmen.
- Trendfilter –
UseTrendDetection, AdxPeriod, AdxLevel, Kerzenzeitrahmen.
- Bollinger-Filter –
UseBollingerFilter, BollingerPeriod, mittlere/breite Abweichungen, RSI Bereichslänge.
- Rauschfilter –
UseNoiseFilter, NoiseAtrLength, NoiseThreshold, Kerzenzeitrahmen.
- Automatisches Schließen und Risiko –
UseAutoClose, AllowOppositeAfterClose, StopLossOffset, TakeProfitOffset, UseTrailingStop.
Alle Parameter werden als StrategyParam<T> angezeigt, um Optimierung, Validierung und UI-Gruppierung zu unterstützen.
Unterschiede zum MT4 EA
- Es werden nur StockSharp integrierte Indikatoren verwendet. Die ursprüngliche Option zwischen ZeroLag und der klassischen MACD wird durch die native MACD-Implementierung ersetzt.
- Alle gleitenden Durchschnitte und Oszillatoren basieren auf Kerzenschlusskursen. Preistyp- und Shift-Offsets von MT4 (z. B.
FastMa_Price, FastMa_Shift) sind nicht verfügbar.
- Der Damiani-Rauschfilter wird mit ATR angenähert; Das Verhalten kann über
NoiseThreshold angepasst werden.
- Die Geldverwaltung und Auftragswiederholungen werden von StockSharp abgewickelt (keine manuellen
OrderSend-Schleifen). Die Strategie funktioniert mit aggregierten Positionen (BuyMarket/SellMarket).
- Das Kommentarfeld und die Diagrammobjekte von EA werden weggelassen. Stattdessen ist die Protokollierung über
LogInfo verfügbar.
Nutzung
- Fügen Sie die Klasse
MultiStrategyComboStrategy zu Ihrer StockSharp-Lösung hinzu und kompilieren Sie sie.
- Instanziieren Sie die Strategie, legen Sie
Security, Portfolio und das gewünschte Volume fest.
- Konfigurieren Sie Zeitrahmen für jeden Indikator, wenn eine Bestätigung mehrerer Zeitrahmen erforderlich ist (Standardeinstellungen folgen den Eingaben von EA).
- Passen Sie optional Stop/Take-Offsets, Nachlaufverhalten und Filterschwellenwerte an.
- Starten Sie die Strategie. Trades werden bei geschlossenen Kerzen ausgelöst, wenn alle aktivierten Module entsprechend dem ausgewählten Kombinationsfaktor übereinstimmen.
Konvertierungshinweise
- Die Strategie basiert ausschließlich auf High-Level-Abonnement-APIs (
SubscribeCandles().Bind(...)) – es werden keine manuellen Indikatorpuffer verwendet.
- Tabulatoren werden zum Einrücken gemäß den Repository-Richtlinien verwendet.
- Ausführliche Inline-Kommentare verdeutlichen, wie EA-Konzepte auf StockSharp-Code abgebildet werden.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Multi Combo: Dual EMA crossover with RSI filter and ATR stops.
/// </summary>
public class MultiComboStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public MultiComboStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 9)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 21)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, rsi, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (fastVal < slowVal && _prevFast >= _prevSlow)
{
SellMarket();
_entryPrice = 0;
}
else if (close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
BuyMarket();
_entryPrice = 0;
}
else if (close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 45)
{
_entryPrice = close;
BuyMarket();
}
else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 55)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class multi_combo_strategy(Strategy):
"""
Multi Combo: EMA crossover with RSI filter and ATR-based stops.
"""
def __init__(self):
super(multi_combo_strategy, self).__init__()
self._fast_ema = self.Param("FastEmaLength", 9).SetDisplay("Fast EMA", "Fast EMA", "Indicators")
self._slow_ema = self.Param("SlowEmaLength", 21).SetDisplay("Slow EMA", "Slow EMA", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetDisplay("RSI", "RSI period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR", "ATR period", "Indicators")
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
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(multi_combo_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(multi_combo_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_ema.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_ema.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, rsi, atr, self._process_candle).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 _process_candle(self, candle, fast_val, slow_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
rsi = float(rsi_val)
atr = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_fast == 0 or self._prev_slow == 0 or atr <= 0:
self._prev_fast = fast
self._prev_slow = slow
return
if self.Position > 0:
if fast < slow and self._prev_fast >= self._prev_slow:
self.SellMarket()
self._entry_price = 0
elif close <= self._entry_price - atr * 2.0:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if fast > slow and self._prev_fast <= self._prev_slow:
self.BuyMarket()
self._entry_price = 0
elif close >= self._entry_price + atr * 2.0:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0:
if fast > slow and self._prev_fast <= self._prev_slow and rsi > 45:
self._entry_price = close
self.BuyMarket()
elif fast < slow and self._prev_fast >= self._prev_slow and rsi < 55:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return multi_combo_strategy()