Die iCCI iRSI-Strategie ist eine direkte Konvertierung des MetaTrader 5 Expert Advisors iCCI iRSI.mq5. Das ursprüngliche System kombiniert den Commodity Channel Index (CCI) und den Relative Strength Index (RSI), um Erschöpfungszonen zu erkennen. Wenn beide Oszillatoren auf einen überkauften oder überverkauften Zustand einig sind, öffnet der Advisor eine Position, befestigt Schutzorders und verfolgt optional den Stop, während der Trade in Gewinn geht. Dieser StockSharp-Port spiegelt dieses Verhalten mit High-Level-APIs wider, einschließlich pip-basierter Eingaben, automatischem Schließen von Gegenpositionen und einem umkehrbaren Signalmodus.
Handelslogik
Den konfigurierten Kerzentyp abonnieren und einen CommodityChannelIndex mit Periode CciPeriod sowie einen RelativeStrengthIndex mit Periode RsiPeriod berechnen.
Nur abgeschlossene Kerzen auswerten. Intrabar-Rauschen wird ignoriert, genau wie die MQL-Implementierung, die auf eine neue Bar wartet.
Wenn beide Indikatoren unter ihre jeweiligen unteren Schwellenwerte fallen (CciLowerLevel und RsiLowerLevel), öffnet oder dreht die Strategie in eine Long-Position. Wenn beide Indikatoren über die oberen Schwellenwerte steigen (CciUpperLevel und RsiUpperLevel), wird ein Short-Setup ausgelöst. Das Aktivieren von ReverseSignals tauscht die Richtungen.
Bevor eine neue Order gesendet wird, wird das aktuelle entgegengesetzte Exposure geschlossen, sodass die Nettoposition immer dem aktiven Signal entspricht.
Nach dem Einstieg überwacht die Strategie den Schlusskurs der folgenden Kerzen. In Pips ausgedrückte Take-Profit- und Stop-Loss-Niveaus werden mit dem PriceStep des Instruments in Preiseinheiten umgerechnet. Für 3- oder 5-stellige Forex-Symbole reproduziert eine zusätzliche ×10-Anpassung die MetaTrader-Pip-Definition.
Wenn TrailingStopPips positiv ist, wird der Stop-Loss Richtung Markt vorgerückt, sobald sich der Preis mehr als TrailingStopPips + TrailingStepPips in der günstigen Richtung bewegt. Updates respektieren den konfigurierten Schritt, um schnelle Stop-Modifikationen zu vermeiden.
Risiko- und Handelsmanagement
Take-Profit / Stop-Loss – optionale Pip-Abstände, die unmittelbar nach einer Ausführung zu absoluten Preisniveaus werden. Wenn eines der Niveaus beim Kerzen-Schluss durchbrochen wird, wird die Position zum Marktpreis liquidiert.
Trailing-Stop – repliziert die Trailing-Logik des EA. Gewinne müssen die Trailing-Distanz plus den Trailing-Schritt überschreiten, bevor der Stop enger gezogen wird.
Volumen – ein fester TradeVolume-Parameter ersetzt den ursprünglichen Lot-oder-Risiko-Selektor (ENUM_LOT_OR_RISK). Optimierung verwenden, um geeignete Volumina zu entdecken, wenn Geldverwaltungsvarianten benötigt werden.
Positionshygiene – wenn ein neues Signal erscheint, flättet die Strategie jedes entgegengesetzte Holding, bevor der neue Trade eröffnet wird, genau wie der EA ClosePositions durchführt.
Parameter
Candle Type – von den Indikatoren verarbeitete Kerzendatenserie (Standard: 1-Stunden-Kerzen).
ReverseSignals – kehrt die Interpretation der Oszillatorsignale um (Standard: false).
TradeVolume – Marktordergröße. Auf den MT5-Lot-Input abstimmen (Standard: 0.1).
StopLossPips / TakeProfitPips – Schutzabstände in Pips (Standards: 0 und 140). Auf null setzen zum Deaktivieren.
TrailingStopPips / TrailingStepPips – Trailing-Stop-Distanz und Mindestschritt (Standards: 5 / 5). Eine null Trailing-Distanz deaktiviert Trailing, auch wenn ein Schritt angegeben ist.
Implementierungshinweise
StockSharp-Indikatoren (CommodityChannelIndex, RelativeStrengthIndex) liefern gebrauchsfertige Dezimalwerte über die Bind-API, sodass keine manuelle CopyBuffer-Logik erforderlich ist.
Das gesamte Handelsmanagement findet auf abgeschlossenen Kerzen statt. Dies entspricht der PrevBars-Bewachung des EA und verhindert mehrere Einstiege innerhalb derselben Bar.
Die Pip-Konvertierung berücksichtigt fraktionale Pip-Notierungen, indem der PriceStep für Instrumente mit 3 oder 5 Dezimalstellen mit 10 multipliziert wird – ein direktes Analogon zur MQL digits_adjust-Logik.
Schutziele werden über Marktausstiege simuliert, da StockSharp-Strategien in einer Sandbox-Umgebung arbeiten, in der synchrone Ordermodifikationen nicht verfügbar sind.
Zusätzliche Chartbereiche zeichnen die CCI- und RSI-Linien zur visuellen Validierung der Einstiegszonen.
Unterschiede zum ursprünglichen Expert Advisor
Das MetaTrader-Modul MoneyFixedMargin ist nicht portiert. Die Positionsdimensionierung ist jetzt ein einfacher fester Volumensparameter.
Brokerspezifische Prüfungen wie FreezeStopsLevels sind in StockSharp nicht verfügbar. Der Trailing-Stop beobachtet daher nur Preisabstand und Schrittanforderungen.
Logging- und Warnungsstrings wurden zugunsten einer sauberen Strategieausgabe entfernt. Das Logging-System von StockSharp kann bei Bedarf extern angehängt werden.
Das Handelsmanagement arbeitet auf Kerzen-Schlusskursen. Die MT5-Version konnte intrabar reagieren, wenn Stop oder Take-Profit berührt werden, aber die End-of-Bar-Approximation hält die Logik für Backtests deterministisch.
Nutzungshinweise
Mit dem standardmäßigen 1-Stunden-Zeitrahmen beginnen, um die Originalvorlage zu replizieren. Kürzere Frames können mehr Signale, aber auch mehr Fehlsignale einführen.
CciUpperLevel, CciLowerLevel, RsiUpperLevel und RsiLowerLevel zusammen optimieren – der EA basiert auf Übereinstimmung beider Oszillatoren, daher sind ausgewogene Schwellenwerte wesentlich.
Bei Forex-Paaren prüfen, ob die Wertpapier-Metadaten PriceStep und Decimals bereitstellen, damit Pip-Abstände korrekt konvertiert werden.
ReverseSignals für klassisches Trendumkehr-Verhalten deaktivieren. Aktivieren, um Ausbrüche aus überkauften/überverkauften Zonen zu handeln.
Mit StockSharp-Risikomodulen (Eigenkapital-Stop, Drawdown-Schutz) kombinieren, wenn Portfolio-Kontrollen erforderlich sind – sie ersetzen den MT5 m_money-Helper.
Diese Dokumentation liefert den gesamten notwendigen Kontext für Einsatz, Anpassung und Erweiterung der iCCI iRSI-Strategie innerhalb der StockSharp-Umgebung.
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 IcciIrsiStrategy : 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 IcciIrsiStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).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 icci_irsi_strategy(Strategy):
def __init__(self):
super(icci_irsi_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(icci_irsi_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(icci_irsi_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
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 > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
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 = 100
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 = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return icci_irsi_strategy()