MA2CCI-Strategie
Diese Strategie kombiniert einen schnellen und langsamen Simple Moving Average (SMA) Crossover mit dem Commodity Channel Index (CCI) als Bestätigungsfilter. Eine Position wird nur eröffnet, wenn sowohl die gleitenden Durchschnitte als auch der CCI ihre Niveaus in der gleichen Richtung kreuzen. Der Average True Range (ATR) definiert den anfänglichen Stop-Loss-Abstand.
Das System kann in beide Richtungen handeln. Es gibt kein Take-Profit; Positionen werden bei einem entgegengesetzten Signal oder beim Auslösen des ATR-basierten Stop-Loss geschlossen.
Details
- Einstiegskriterien:
- Long: Schneller SMA kreuzt über den langsamen SMA und CCI kreuzt über 0.
- Short: Schneller SMA kreuzt unter den langsamen SMA und CCI kreuzt unter 0.
- Ausstiegskriterien:
- Umgekehrter SMA-Crossover.
- ATR-basierter Stop-Loss.
- Indikatoren: SMA, CCI, ATR.
- Zeitrahmen: Konfigurierbar über
CandleType. - Standardparameter:
Fast MA Period= 4Slow MA Period= 8CCI Period= 4ATR Period= 4
- Long/Short: Beide.
- Stops: Ja, dynamischer Stop mit ATR.
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;
/// <summary>
/// Strategy based on two moving averages with CCI filter and ATR stop-loss.
/// Opens long when fast MA crosses above slow MA and CCI > 0.
/// Opens short when fast MA crosses below slow MA and CCI < 0.
/// </summary>
public class Ma2CciStrategy : Strategy
{
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isInitialized;
private decimal _stopLoss;
public int FastMaPeriod { get => _fastMaPeriod.Value; set => _fastMaPeriod.Value = value; }
public int SlowMaPeriod { get => _slowMaPeriod.Value; set => _slowMaPeriod.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Ma2CciStrategy()
{
_fastMaPeriod = Param(nameof(FastMaPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Period of the fast moving average", "Indicators");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 15)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Period of the slow moving average", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period for CCI filter", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Period for ATR stop-loss", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_isInitialized = false;
_stopLoss = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
var slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var atr = new StandardDeviation { Length = AtrPeriod };
SubscribeCandles(CandleType)
.Bind(fastMa, slowMa, cci, atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal cciValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_isInitialized)
{
_prevFast = fast;
_prevSlow = slow;
_isInitialized = true;
return;
}
// Stop-loss check
if (Position > 0 && _stopLoss > 0 && candle.ClosePrice <= _stopLoss)
{
SellMarket();
_stopLoss = 0;
_prevFast = fast;
_prevSlow = slow;
return;
}
else if (Position < 0 && _stopLoss > 0 && candle.ClosePrice >= _stopLoss)
{
BuyMarket();
_stopLoss = 0;
_prevFast = fast;
_prevSlow = slow;
return;
}
var isFastAbove = fast > slow;
var wasFastAbove = _prevFast > _prevSlow;
// MA crossover up => long (CCI as optional filter)
if (isFastAbove && !wasFastAbove)
{
if (Position < 0) BuyMarket();
if (Position <= 0)
{
BuyMarket();
if (atrValue > 0)
_stopLoss = candle.ClosePrice - atrValue * 2;
}
}
// MA crossover down => short
else if (!isFastAbove && wasFastAbove)
{
if (Position > 0) SellMarket();
if (Position >= 0)
{
SellMarket();
if (atrValue > 0)
_stopLoss = candle.ClosePrice + atrValue * 2;
}
}
_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 CommodityChannelIndex, ExponentialMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class ma2_cci_strategy(Strategy):
def __init__(self):
super(ma2_cci_strategy, self).__init__()
self._fast_ma_period = self.Param("FastMaPeriod", 10) \
.SetDisplay("Fast MA Period", "Period of the fast moving average", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 15) \
.SetDisplay("Slow MA Period", "Period of the slow moving average", "Indicators")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "Period for CCI filter", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "Period for ATR stop-loss", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_initialized = False
self._stop_loss = 0.0
@property
def fast_ma_period(self):
return self._fast_ma_period.Value
@property
def slow_ma_period(self):
return self._slow_ma_period.Value
@property
def cci_period(self):
return self._cci_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma2_cci_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_initialized = False
self._stop_loss = 0.0
def OnStarted2(self, time):
super(ma2_cci_strategy, self).OnStarted2(time)
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.fast_ma_period
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.slow_ma_period
cci = CommodityChannelIndex()
cci.Length = self.cci_period
atr = StandardDeviation()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ma, slow_ma, cci, atr, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, fast, slow, cci_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not self._is_initialized:
self._prev_fast = fast
self._prev_slow = slow
self._is_initialized = True
return
# Stop-loss check
if self.Position > 0 and self._stop_loss > 0 and candle.ClosePrice <= self._stop_loss:
self.SellMarket()
self._stop_loss = 0
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._stop_loss > 0 and candle.ClosePrice >= self._stop_loss:
self.BuyMarket()
self._stop_loss = 0
self._prev_fast = fast
self._prev_slow = slow
return
is_fast_above = fast > slow
was_fast_above = self._prev_fast > self._prev_slow
# MA crossover up => long (CCI as optional filter)
if is_fast_above and not was_fast_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
if atr_value > 0:
self._stop_loss = candle.ClosePrice - atr_value * 2
# MA crossover down => short
elif not is_fast_above and was_fast_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
if atr_value > 0:
self._stop_loss = candle.ClosePrice + atr_value * 2
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return ma2_cci_strategy()