Die CCI and Martin-Strategie sucht nach scharfen Umkehrungen nach einer kurzen bärischen oder bullischen Sequenz und bestätigt die Bewegung mit dem Commodity Channel Index. Die Logik repliziert den ursprünglichen MetaTrader 5-Expertenberater unter Verwendung der StockSharp-High-Level-API. Die Strategie arbeitet nur mit fertigen Kerzen und kann auf jedem Instrument betrieben werden, für das CCI-Werte und Preisschritte verfügbar sind.
Handelsregeln
Bullisches Setup
Kerze -2 und Kerze -1 müssen beide bärisch sein (Eröffnung größer als Schluss).
Kerze 0 muss über ihrer Eröffnung und über der Eröffnung von Kerze -1 schließen.
CCI auf Kerze -1 muss unter +5 liegen, unter dem Wert von Kerze -2, und sowohl -2 als auch -3 müssen eine absteigende Sequenz zeigen. Der aktuelle CCI (Kerze 0) muss sich nach oben über den vorherigen Wert drehen.
Wenn alle Bedingungen zutreffen und keine Position offen ist, tritt die Strategie in einen Long-Trade ein.
Bärisches Setup
Kerze -2 und Kerze -1 müssen beide bullisch sein (Eröffnung kleiner als Schluss).
Kerze 0 muss unter ihrer Eröffnung und unter der Eröffnung von Kerze -1 schließen.
CCI auf Kerze -1 muss über -5 liegen, über dem Wert von Kerze -2, und sowohl -2 als auch -3 müssen eine aufsteigende Sequenz bilden. Der aktuelle CCI (Kerze 0) muss sich nach unten unter den vorherigen Wert drehen.
Wenn alle Bedingungen zutreffen und keine Position offen ist, tritt die Strategie in einen Short-Trade ein.
Der Algorithmus überwacht nur abgeschlossene Kerzen. Die ursprüngliche MQL-Implementierung wartete 40 Sekunden nach der Minuten-Eröffnung, um vorzeitige Signale zu vermeiden; die Verwendung fertiger Kerzen macht diesen Filter unnötig.
Risikomanagement
Stop-Loss- und Take-Profit-Abstände werden in Pips definiert. Sie werden in Preisoffsets konvertiert, indem der Preisschritt des Instruments mit zehn multipliziert wird, wenn der Schritt einer 3- oder 5-stelligen Notierung entspricht, was die ursprüngliche Pip-Berechnung widerspiegelt.
Der Trailing-Stop wird aktiv, nachdem der Preis um die Trailing-Stop-Distanz plus dem Trailing-Schritt vorrückt. Der Stop wird dann bewegt, um die Trailing-Distanz aufrechtzuerhalten, und rückt nur vor, wenn die Preisverbesserung den konfigurierten Schritt überschreitet.
Wenn Stop-Loss oder Take-Profit auf null gesetzt wird, ist der jeweilige Ausstieg deaktiviert. Trailing erfordert, dass sowohl die Stop-Distanz als auch der Schritt positiv sind.
Volumenverwaltung
Zwei optionale Positionsgrößen-Engines können die Losgröße nach jedem Trade ändern.
Martingale-Skalierung multipliziert das aktuelle Volumen mit dem Martingale-Koeffizienten, sobald die Anzahl aufeinanderfolgender Verluste den Auslöser erreicht. Die Skalierung stoppt nach der konfigurierten Anzahl von Martingale-Schritten. Jeder profitable Trade setzt das Volumen auf den Anfangswert zurück.
Schritt-Anpassungen erhöhen das Volumen um einen festen Betrag entweder nach Verlusten oder nach Gewinnen, abhängig vom gewählten Modus. Der Zuwachs wird auf den Volumenschritt des Instruments normiert und durch den maximalen Volumenparameter begrenzt. Wenn das Limit überschritten wird oder ein Trade die Auslöserbedingung nicht erfüllt, fällt das Volumen auf die Anfangsgröße zurück.
Der ursprüngliche Expertenberater verbietet die gleichzeitige Aktivierung von Martingale- und Schritt-Logik; der C#-Port erzwingt dieselbe Einschränkung.
Parameter
CandleType – für die Analyse verwendete Kerzenserie.
CciPeriod – Mittelungslänge für den Commodity Channel Index.
InitialVolume – Basis-Ordergröße vor jeglicher Skalierung.
StopLossPips – Stop-Loss-Abstand in Pips.
TakeProfitPips – Take-Profit-Abstand in Pips.
TrailingStopPips – Trailing-Stop-Abstand in Pips (0 deaktiviert Trailing).
TrailingStepPips – Mindestpreisverbesserung erforderlich, bevor der Trailing-Stop sich bewegt.
EnableMartingale – aktiviert Martingale-Skalierung nach Verlusten.
MartingaleCoefficient – Multiplikator für das aktuelle Volumen bei Martingale-Trades.
MartingaleTriggerLosses – Anzahl aufeinanderfolgender Verlust-Trades vor der Skalierung.
MartingaleMaxSteps – maximale Anzahl von Martingale-Multiplikationen.
StepVolumeIncrement – absoluter Zuwachs bei Auslösung der Schrittregel.
StepVolumeMax – Obergrenze für das schrittbasierte Volumen.
StepAdjustmentMode – wählt, ob der Schritterhöhung nach einem Verlust oder nach einem Gewinn ausgelöst wird.
Hinweise
Die Strategie geht davon aus, dass Marktorders nahe am angeforderten Preis ausgeführt werden. Protective Logik berechnet Stops bei jeder fertigen Kerze neu, um das tick-basierte Trailing im ursprünglichen EA zu emulieren.
Wenn der Preisschritt des Instruments nicht der klassischen FX-Notierung entspricht, funktioniert die Pip-Konvertierung trotzdem, aber pip-basierte Abstände können unterschiedliche Geldwerte darstellen.
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>
/// CCI based strategy with martingale-style entry.
/// Buys when CCI crosses above oversold level, sells when CCI crosses below overbought level.
/// </summary>
public class CCIAndMartinStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<decimal> _oversold;
private decimal? _prevCci;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
public decimal Overbought
{
get => _overbought.Value;
set => _overbought.Value = value;
}
public decimal Oversold
{
get => _oversold.Value;
set => _oversold.Value = value;
}
public CCIAndMartinStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 27)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI indicator length", "Indicators");
_overbought = Param(nameof(Overbought), 100m)
.SetDisplay("Overbought", "CCI overbought level", "Indicators");
_oversold = Param(nameof(Oversold), -100m)
.SetDisplay("Oversold", "CCI oversold level", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, cci);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevCci = cciValue;
return;
}
if (_prevCci == null)
{
_prevCci = cciValue;
return;
}
var prev = _prevCci.Value;
_prevCci = cciValue;
// Buy signal: CCI crosses above oversold level from below
if (prev < Oversold && cciValue >= Oversold && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell signal: CCI crosses below overbought level from above
else if (prev > Overbought && cciValue <= Overbought && 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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class cci_and_martin_strategy(Strategy):
def __init__(self):
super(cci_and_martin_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._cci_period = self.Param("CciPeriod", 27) \
.SetDisplay("CCI Period", "CCI indicator length", "Indicators")
self._overbought = self.Param("Overbought", 100.0) \
.SetDisplay("Overbought", "CCI overbought level", "Indicators")
self._oversold = self.Param("Oversold", -100.0) \
.SetDisplay("Oversold", "CCI oversold level", "Indicators")
self._prev_cci = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def CciPeriod(self):
return self._cci_period.Value
@property
def Overbought(self):
return self._overbought.Value
@property
def Oversold(self):
return self._oversold.Value
def OnReseted(self):
super(cci_and_martin_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(cci_and_martin_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(cci, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def _on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
cv = float(cci_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = cv
return
if self._prev_cci is None:
self._prev_cci = cv
return
prev = self._prev_cci
self._prev_cci = cv
ob = float(self.Overbought)
os_level = float(self.Oversold)
# Buy signal: CCI crosses above oversold level from below
if prev < os_level and cv >= os_level and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell signal: CCI crosses below overbought level from above
elif prev > ob and cv <= ob and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return cci_and_martin_strategy()