Стратегия Triple CCI MFI Confirmed
Стратегия открывает лонг, когда быстрый CCI пересекает ноль снизу вверх, средний и медленный CCI остаются положительными, цена выше EMA и MFI превышает 50. После активации на основе ATR прибыль сопровождается EMA.
Тестирование показывает средние результаты, лучше всего работает в трендовых рынках.
Детали
- Условия входа:
- Лонг: быстрый CCI пересекает 0 вверх, средний CCI > 0, медленный CCI > 0, MFI > 50, закрытие выше EMA
- Лонг/Шорт: только лонг.
- Условия выхода:
- Лонг: закрытие ниже трейлинг-EMA после активации или минимум свечи достигает стопа ATR
- Стопы: да.
- Значения по умолчанию:
StopLossAtrMultiplier= 1.75TrailingActivationMultiplier= 2.25FastCciPeriod= 14MiddleCciPeriod= 25SlowCciPeriod= 50MfiLength= 14EmaLength= 50TrailingEmaLength= 20AtrPeriod= 14CandleType= TimeSpan.FromMinutes(5)
- Фильтры:
- Категория: Trend
- Направление: Long
- Индикаторы: CCI, MFI, EMA, 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 using triple CCI confirmed by MFI and ExponentialMovingAverage with ATR based trailing exit.
/// </summary>
public class TripleCciMfiConfirmedStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossAtrMultiplier;
private readonly StrategyParam<decimal> _trailingActivationMultiplier;
private readonly StrategyParam<int> _fastCciPeriod;
private readonly StrategyParam<int> _middleCciPeriod;
private readonly StrategyParam<int> _slowCciPeriod;
private readonly StrategyParam<int> _mfiLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _trailingEmaLength;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<DateTimeOffset> _tradeStart;
private readonly StrategyParam<DateTimeOffset> _tradeStop;
private decimal _prevFastCci;
private decimal _stopLossLevel;
private decimal _activationLevel;
private decimal _takeProfitLevel;
private bool _trailingActivated;
private DateTimeOffset _lastSignal;
/// <summary>
/// ATR multiplier for stop loss.
/// </summary>
public decimal StopLossAtrMultiplier
{
get => _stopLossAtrMultiplier.Value;
set => _stopLossAtrMultiplier.Value = value;
}
/// <summary>
/// ATR multiplier for trailing profit activation.
/// </summary>
public decimal TrailingActivationMultiplier
{
get => _trailingActivationMultiplier.Value;
set => _trailingActivationMultiplier.Value = value;
}
/// <summary>
/// Fast CCI period.
/// </summary>
public int FastCciPeriod
{
get => _fastCciPeriod.Value;
set => _fastCciPeriod.Value = value;
}
/// <summary>
/// Middle CCI period.
/// </summary>
public int MiddleCciPeriod
{
get => _middleCciPeriod.Value;
set => _middleCciPeriod.Value = value;
}
/// <summary>
/// Slow CCI period.
/// </summary>
public int SlowCciPeriod
{
get => _slowCciPeriod.Value;
set => _slowCciPeriod.Value = value;
}
/// <summary>
/// MFI length.
/// </summary>
public int MfiLength
{
get => _mfiLength.Value;
set => _mfiLength.Value = value;
}
/// <summary>
/// ExponentialMovingAverage length.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Trailing ExponentialMovingAverage length.
/// </summary>
public int TrailingEmaLength
{
get => _trailingEmaLength.Value;
set => _trailingEmaLength.Value = value;
}
/// <summary>
/// ATR period.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Trading start date.
/// </summary>
public DateTimeOffset TradeStart
{
get => _tradeStart.Value;
set => _tradeStart.Value = value;
}
/// <summary>
/// Trading stop date.
/// </summary>
public DateTimeOffset TradeStop
{
get => _tradeStop.Value;
set => _tradeStop.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public TripleCciMfiConfirmedStrategy()
{
_stopLossAtrMultiplier = Param(nameof(StopLossAtrMultiplier), 1.75m)
.SetRange(0.5m, 5m)
.SetDisplay("ATR Stop Loss", "ATR multiplier for stop loss", "Risk Management")
;
_trailingActivationMultiplier = Param(nameof(TrailingActivationMultiplier), 2.25m)
.SetRange(0.5m, 5m)
.SetDisplay("ATR Trailing Activation", "ATR multiplier to activate trailing", "Risk Management")
;
_fastCciPeriod = Param(nameof(FastCciPeriod), 14)
.SetRange(5, 50)
.SetDisplay("CCI Fast Length", "Fast CCI period", "Indicators")
;
_middleCciPeriod = Param(nameof(MiddleCciPeriod), 25)
.SetRange(5, 100)
.SetDisplay("CCI Middle Length", "Middle CCI period", "Indicators")
;
_slowCciPeriod = Param(nameof(SlowCciPeriod), 50)
.SetRange(10, 150)
.SetDisplay("CCI Slow Length", "Slow CCI period", "Indicators")
;
_mfiLength = Param(nameof(MfiLength), 14)
.SetRange(1, 200)
.SetDisplay("MFI Length", "Money Flow Index length", "Indicators")
;
_emaLength = Param(nameof(EmaLength), 50)
.SetRange(10, 200)
.SetDisplay("ExponentialMovingAverage Length", "ExponentialMovingAverage filter length", "Indicators")
;
_trailingEmaLength = Param(nameof(TrailingEmaLength), 20)
.SetRange(10, 100)
.SetDisplay("Trailing ExponentialMovingAverage Length", "ExponentialMovingAverage length for trailing profit", "Indicators")
;
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetRange(5, 50)
.SetDisplay("ATR Period", "ATR calculation period", "Indicators")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_tradeStart = Param(nameof(TradeStart), new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero))
.SetDisplay("Trade Start", "Start date for trading", "Time Range");
_tradeStop = Param(nameof(TradeStop), new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero))
.SetDisplay("Trade Stop", "Stop date for trading", "Time Range");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFastCci = default;
_stopLossLevel = default;
_activationLevel = default;
_takeProfitLevel = default;
_trailingActivated = default;
_lastSignal = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastCci = new CommodityChannelIndex { Length = FastCciPeriod };
var middleCci = new CommodityChannelIndex { Length = MiddleCciPeriod };
var slowCci = new CommodityChannelIndex { Length = SlowCciPeriod };
var mfi = new MoneyFlowIndex { Length = MfiLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var trailingEma = new ExponentialMovingAverage { Length = TrailingEmaLength };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastCci, middleCci, slowCci, mfi, ema, trailingEma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastCci);
DrawIndicator(area, middleCci);
DrawIndicator(area, slowCci);
DrawIndicator(area, mfi);
DrawIndicator(area, ema);
DrawIndicator(area, trailingEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastCci, decimal middleCci, decimal slowCci, decimal mfi, decimal ema, decimal trailingEma, decimal atr)
{
if (candle.State != CandleStates.Finished)
return;
if (candle.OpenTime < TradeStart || candle.OpenTime > TradeStop)
return;
var crossedUp = _prevFastCci <= 0m && fastCci > 0m;
_prevFastCci = fastCci;
var cooldown = TimeSpan.FromMinutes(1440);
if (crossedUp && candle.ClosePrice > ema && middleCci > 0m && slowCci > 0m && mfi > 65m && Position <= 0 && candle.OpenTime - _lastSignal >= cooldown)
{
BuyMarket();
_lastSignal = candle.OpenTime;
_stopLossLevel = candle.ClosePrice - StopLossAtrMultiplier * atr;
_activationLevel = candle.ClosePrice + TrailingActivationMultiplier * atr;
_trailingActivated = false;
_takeProfitLevel = default;
return;
}
if (Position <= 0)
return;
if (!_trailingActivated && candle.HighPrice > _activationLevel)
_trailingActivated = true;
if (_trailingActivated)
_takeProfitLevel = trailingEma;
if (_takeProfitLevel != default && candle.ClosePrice < _takeProfitLevel)
{
SellMarket();
_lastSignal = candle.OpenTime;
return;
}
if (candle.LowPrice <= _stopLossLevel)
{
SellMarket();
_lastSignal = candle.OpenTime;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, DateTimeOffset, DateTime
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange, CommodityChannelIndex, ExponentialMovingAverage, MoneyFlowIndex
from StockSharp.Algo.Strategies import Strategy
class triple_cci_mfi_confirmed_strategy(Strategy):
def __init__(self):
super(triple_cci_mfi_confirmed_strategy, self).__init__()
self._stop_loss_atr_multiplier = self.Param("StopLossAtrMultiplier", 1.75) \
.SetDisplay("ATR Stop Loss", "ATR multiplier for stop loss", "Risk Management")
self._trailing_activation_multiplier = self.Param("TrailingActivationMultiplier", 2.25) \
.SetDisplay("ATR Trailing Activation", "ATR multiplier to activate trailing", "Risk Management")
self._fast_cci_period = self.Param("FastCciPeriod", 14) \
.SetDisplay("CCI Fast Length", "Fast CCI period", "Indicators")
self._middle_cci_period = self.Param("MiddleCciPeriod", 25) \
.SetDisplay("CCI Middle Length", "Middle CCI period", "Indicators")
self._slow_cci_period = self.Param("SlowCciPeriod", 50) \
.SetDisplay("CCI Slow Length", "Slow CCI period", "Indicators")
self._mfi_length = self.Param("MfiLength", 14) \
.SetDisplay("MFI Length", "Money Flow Index length", "Indicators")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("ExponentialMovingAverage Length", "ExponentialMovingAverage filter length", "Indicators")
self._trailing_ema_length = self.Param("TrailingEmaLength", 20) \
.SetDisplay("Trailing ExponentialMovingAverage Length", "ExponentialMovingAverage length for trailing profit", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR calculation period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._trade_start = self.Param("TradeStart", DateTime(2023, 1, 1)) \
.SetDisplay("Trade Start", "Start date for trading", "Time Range")
self._trade_stop = self.Param("TradeStop", DateTime(2025, 1, 1)) \
.SetDisplay("Trade Stop", "Stop date for trading", "Time Range")
self._prev_fast_cci = 0.0
self._stop_loss_level = 0.0
self._activation_level = 0.0
self._take_profit_level = 0.0
self._trailing_activated = False
self._last_signal = DateTime.MinValue
@property
def stop_loss_atr_multiplier(self):
return self._stop_loss_atr_multiplier.Value
@property
def trailing_activation_multiplier(self):
return self._trailing_activation_multiplier.Value
@property
def fast_cci_period(self):
return self._fast_cci_period.Value
@property
def middle_cci_period(self):
return self._middle_cci_period.Value
@property
def slow_cci_period(self):
return self._slow_cci_period.Value
@property
def mfi_length(self):
return self._mfi_length.Value
@property
def ema_length(self):
return self._ema_length.Value
@property
def trailing_ema_length(self):
return self._trailing_ema_length.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def trade_start(self):
return self._trade_start.Value
@property
def trade_stop(self):
return self._trade_stop.Value
def OnReseted(self):
super(triple_cci_mfi_confirmed_strategy, self).OnReseted()
self._prev_fast_cci = 0.0
self._stop_loss_level = 0.0
self._activation_level = 0.0
self._take_profit_level = 0.0
self._trailing_activated = False
self._last_signal = DateTime.MinValue
def OnStarted2(self, time):
super(triple_cci_mfi_confirmed_strategy, self).OnStarted2(time)
fast_cci = CommodityChannelIndex()
fast_cci.Length = self.fast_cci_period
middle_cci = CommodityChannelIndex()
middle_cci.Length = self.middle_cci_period
slow_cci = CommodityChannelIndex()
slow_cci.Length = self.slow_cci_period
mfi = MoneyFlowIndex()
mfi.Length = self.mfi_length
ema = ExponentialMovingAverage()
ema.Length = self.ema_length
trailing_ema = ExponentialMovingAverage()
trailing_ema.Length = self.trailing_ema_length
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
def on_candle(candle, fast_cci_val, middle_cci_val, slow_cci_val, mfi_val, ema_val, trailing_ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
if candle.OpenTime < self.trade_start or candle.OpenTime > self.trade_stop:
return
fc = float(fast_cci_val)
mc = float(middle_cci_val)
sc = float(slow_cci_val)
mv = float(mfi_val)
ev = float(ema_val)
tv = float(trailing_ema_val)
av = float(atr_val)
crossed_up = self._prev_fast_cci <= 0 and fc > 0
self._prev_fast_cci = fc
cooldown = TimeSpan.FromMinutes(1440)
if crossed_up and float(candle.ClosePrice) > ev and mc > 0 and sc > 0 and mv > 65 and self.Position <= 0 and candle.OpenTime - self._last_signal >= cooldown:
self.BuyMarket()
self._last_signal = candle.OpenTime
self._stop_loss_level = float(candle.ClosePrice) - float(self.stop_loss_atr_multiplier) * av
self._activation_level = float(candle.ClosePrice) + float(self.trailing_activation_multiplier) * av
self._trailing_activated = False
self._take_profit_level = 0.0
return
if self.Position <= 0:
return
if not self._trailing_activated and float(candle.HighPrice) > self._activation_level:
self._trailing_activated = True
if self._trailing_activated:
self._take_profit_level = tv
if self._take_profit_level != 0.0 and float(candle.ClosePrice) < self._take_profit_level:
self.SellMarket()
self._last_signal = candle.OpenTime
return
if float(candle.LowPrice) <= self._stop_loss_level:
self.SellMarket()
self._last_signal = candle.OpenTime
subscription.Bind(fast_cci, middle_cci, slow_cci, mfi, ema, trailing_ema, atr, on_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_cci)
self.DrawIndicator(area, middle_cci)
self.DrawIndicator(area, slow_cci)
self.DrawIndicator(area, mfi)
self.DrawIndicator(area, ema)
self.DrawIndicator(area, trailing_ema)
self.DrawOwnTrades(area)
def CreateClone(self):
return triple_cci_mfi_confirmed_strategy()