Die MA2CCI-Strategie ist eine direkte Portierung des Expert Advisors MetaTrader 4, der ursprünglich als „MA2CCI.mq4“ vertrieben wurde. Das System kombiniert einen schnellen/langsamen einfachen gleitenden Durchschnitt (SMA) mit einer Bestätigung der Nulllinie des Commodity Channel Index (CCI). Jeder validierte Crossover eröffnet eine einzelne Marktposition und platziert sofort einen auf dem Average True Range (ATR) basierenden Schutzstopp. Die Positionsgrößenbestimmung folgt der ursprünglichen Money-Management-Logik, indem die Ordergröße im Verhältnis zum Eigenkapital skaliert und nach Phasen von Verlusten bei Trades reduziert wird.
Indikatoren und Daten
Schnell SMA (FMa) und Langsam SMA (SMa) im konfigurierten Zeitrahmen, um Trendumkehrungen zu erkennen.
Commodity Channel Index (CCI) mit demselben Preisstrom zur Bestätigung der Momentumrichtung durch Nullliniendurchgänge.
Average True Range (ATR) zur Messung der jüngsten Volatilität und zur Ableitung der Stop-Loss-Distanz.
Kerzen des gewählten Zeitrahmens (Standard 15 Minuten) liefern die Eingabereihen für alle Indikatoren.
Handelsregeln
Langer Einstieg: Der schnelle SMA kreuzt den langsamen SMA, während CCI auf demselben Balken von negativ nach positiv kreuzt, keine Position offen ist und Handel erlaubt ist. Eine Marktkauforder wird gesendet und ein Stop-Loss wird bei close − ATR × AtrMultiplier aktiviert.
Kurzer Einstieg: Der schnelle SMA kreuzt den langsamen SMA, während CCI von positiv nach negativ kreuzt, es ist keine Position offen. Eine Market-Sell-Order wird mit einem Stop-Loss bei close + ATR × AtrMultiplier platziert.
Ausstieg bei Long-Positionen: Wenn der schnelle SMA den langsamen SMA wieder unterschreitet, wird die gesamte Long-Position zum Marktwert geschlossen. Auch der Schutzstopp wird aufgehoben.
Ausstieg bei Shorts: Wenn der schnelle SMA den langsamen SMA wieder überschreitet, wird die Short-Position zum Marktwert gedeckt und der Stop aufgehoben.
Stop-Loss: Jede neue Position stellt einen Volatilitätsstopp wieder her, der die MetaTrader-Logik widerspiegelt. Stopps werden nur bei neuen Einträgen neu berechnet und als separate bedingte Orders gespeichert.
Positionsgrößen
Die Basislosgröße beginnt beim Parameter BaseVolume (Standard: 0,1 Los).
Wenn RiskFraction positiv ist, berechnet die Strategie eine zusätzliche Größe mit equity × RiskFraction / 1000, ahmt die ursprüngliche AccountFreeMargin-Formel nach und verwendet das Maximum zwischen beiden Werten.
Nach zwei oder mehr aufeinanderfolgenden Verlustgeschäften wird die Losgröße um volume × losses / DecreaseFactor reduziert, wodurch die Drawdown-Kontrolle von DcF repliziert wird.
Die Lautstärken werden auf den VolumeStep des Instruments normalisiert.
Parameter
Name
Standard
Beschreibung
FastMaPeriod
4
Kurzer Lookback-Zeitraum von SMA.
SlowMaPeriod
8
Langsamer Lookback-Zeitraum von SMA.
CciPeriod
4
Zeitraum des Commodity Channel Index.
AtrPeriod
4
Durchschnittliche True-Range-Periode, die für die Stoppdistanz verwendet wird.
AtrMultiplier
1,0
Der Multiplikator wird vor der Platzierung des Stop-Loss auf ATR angewendet.
BaseVolume
0,1
Mindesthandelsgröße vor Risikoanpassungen.
RiskFraction
0,02
Anteil des pro Trade riskierten Eigenkapitals (pro 1000 Währungseinheiten).
DecreaseFactor
3
Divisor, der steuert, wie schnell die Größe nach Verlusten schrumpft.
CandleType
15-Minuten-Kerzen
Für Indikatoren und Signale verwendeter Zeitrahmen.
Notizen
E-Mail-Benachrichtigungen des ursprünglichen Fachberaters (SndMl) werden bewusst weggelassen.
Es kann jeweils nur eine Position offen sein, entsprechend dem MetaTrader-Verhalten des Quellcodes.
Schutzstopps werden immer dann neu erstellt, wenn die Position umkippt oder geschlossen wird, um zu verhindern, dass verwaiste Aufträge im Buch verbleiben.
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>
/// MA2CCI Adaptive Volume strategy - dual EMA crossover with CCI filter.
/// Buys when fast EMA crosses above slow EMA and CCI is above zero.
/// Sells when fast EMA crosses below slow EMA and CCI is below zero.
/// </summary>
public class Ma2CciAdaptiveVolumeStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Ma2CciAdaptiveVolumeStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetDisplay("CCI Period", "CCI lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal cci)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_prevFast <= _prevSlow && fast > slow && cci > 0 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (_prevFast >= _prevSlow && fast < slow && cci < 0 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fast; _prevSlow = slow;
}
}
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, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class ma2_cci_adaptive_volume_strategy(Strategy):
def __init__(self):
super(ma2_cci_adaptive_volume_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._cci_period = self.Param("CciPeriod", 14).SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
@property
def fast_period(self): return self._fast_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def cci_period(self): return self._cci_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(ma2_cci_adaptive_volume_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(ma2_cci_adaptive_volume_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage(); fast.Length = self.fast_period
slow = ExponentialMovingAverage(); slow.Length = self.slow_period
cci = CommodityChannelIndex(); cci.Length = self.cci_period
sub = self.SubscribeCandles(self.candle_type)
sub.Bind(fast, slow, cci, self.process_candle).Start()
def process_candle(self, candle, fast, slow, cci):
if candle.State != CandleStates.Finished: return
f = float(fast); s = float(slow); c = float(cci)
if not self._has_prev: self._prev_fast = f; self._prev_slow = s; self._has_prev = True; return
if self._prev_fast <= self._prev_slow and f > s and c > 0 and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and c < 0 and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_fast = f; self._prev_slow = s
def CreateClone(self): return ma2_cci_adaptive_volume_strategy()