Стратегия SMC Trader Camel CCI MACD
Обзор
Данная стратегия представляет собой портирование советника MetaTrader 4 "Steve Cartwright Trader Camel CCI MACD" на платформу StockSharp.
Алгоритм повторяет исходную логику: используется «верблюжий» канал из экспоненциальных средних по максимумам и минимумам,
фильтр тренда MACD и пороговые значения индикатора CCI. Все решения принимаются только на завершённых свечах,
что обеспечивает детерминированное поведение и повторяет бар-за-баром модель работы в MQL4.
Логика торговли
- Индикаторы
- Две экспоненциальные скользящие средние одинаковой длины рассчитываются по максимумам и минимумам свечей, формируя
канал Camel. Пробой предыдущего закрытия выше/ниже этих линий сигнализирует о силе импульса.
- Индикатор MACD подтверждает направление тренда (быстрая EMA, медленная EMA и сигнальная линия).
- Индикатор CCI подтверждает импульс через уровни перекупленности/перепроданности ±100 (по умолчанию).
- Вход в длинную позицию
- Закрытие предыдущей свечи выше верхней линии канала Camel.
- Значение MACD основной линии на предыдущей свече выше нуля и выше сигнальной линии.
- Значение CCI на предыдущей свече выше положительного порога.
- Позиция отсутствует и с момента последнего выхода прошло не менее одной свечи (защита от повторных входов).
- Вход в короткую позицию
- Закрытие предыдущей свечи ниже нижней линии канала Camel.
- Значение MACD основной линии на предыдущей свече ниже нуля и ниже сигнальной линии.
- Значение CCI на предыдущей свече ниже отрицательного порога.
- Дополнительно выполняются условия отсутствия позиции и тайм-аут после выхода.
- Выходы
- Длинная позиция закрывается при пересечении основной линии MACD ниже сигнальной либо при падении CCI ниже положительного порога.
- Короткая позиция закрывается при пересечении основной линии MACD выше сигнальной.
- После любого выхода запускается тайм-аут продолжительностью в одну свечу, который блокирует немедленный новый вход.
Благодаря использованию значений с предыдущей свечи стратегия совершает не более одной сделки за бар.
Параметры
| Параметр |
Описание |
Значение по умолчанию |
CandleType |
Тип свечей и таймфрейм, используемые для расчётов индикаторов. |
Свечи с периодом 1 час |
CamelLength |
Длина EMA-канала по максимумам и минимумам. |
34 |
CciPeriod |
Период индикатора CCI. |
20 |
MacdFastPeriod |
Период быстрой EMA MACD. |
12 |
MacdSlowPeriod |
Период медленной EMA MACD. |
26 |
MacdSignalPeriod |
Период сглаживания сигнальной линии MACD. |
9 |
CciThreshold |
Абсолютный порог CCI для открытия позиций (используется симметрично). |
100 |
Все параметры подготовлены к оптимизации через SetOptimize, что упрощает подбор значений в оптимизаторе StockSharp.
Управление рисками
- Заявки отправляются методами
BuyMarket и SellMarket, объём берётся из свойства Volume стратегии.
- Метод
StartProtection() активирует стандартные защитные механизмы StockSharp.
- В алгоритме не предусмотрены фиксированные стоп-лосс или тейк-профит; закрытие выполняется только по сигналам индикаторов.
Визуализация
Стратегия автоматически выводит на график канал Camel, MACD, CCI и собственные сделки, чтобы повторить визуальную поддержку,
которую использовал оригинальный советник.
Дополнительные замечания
- Тайм-аут после выхода вычисляется на основе длительности свечи из
CandleType.Arg. При смене таймфрейма убедитесь,
что аргумент типа данных содержит корректный TimeSpan.
- Использование значений только с предыдущего бара эквивалентно вызовам
iMACD, iCCI и iMA с shift = 1 в оригинальном MQL-советнике.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Strategy combining CCI and MACD signal crossover with EMA trend filter.
/// Buy when MACD crosses above signal with CCI positive and price above EMA.
/// Sell when MACD crosses below signal with CCI negative and price below EMA.
/// </summary>
public class SmcTraderCamelCciMacd1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevMacdMain;
private decimal? _prevMacdSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
public int MacdSignalPeriod { get => _macdSignalPeriod.Value; set => _macdSignalPeriod.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public SmcTraderCamelCciMacd1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaLength = Param(nameof(EmaLength), 34)
.SetDisplay("EMA Length", "Trend EMA period", "Indicators");
_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
.SetDisplay("MACD Fast", "Fast EMA for MACD", "Indicators");
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
.SetDisplay("MACD Slow", "Slow EMA for MACD", "Indicators");
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 9)
.SetDisplay("MACD Signal", "Signal line period", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetDisplay("CCI Period", "CCI period", "Indicators");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacdMain = null;
_prevMacdSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacdMain = null;
_prevMacdSignal = null;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod }
},
SignalMa = { Length = MacdSignalPeriod }
};
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, cci, ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue cciValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal || !cciValue.IsFinal || !emaValue.IsFinal)
return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue macdData)
return;
if (macdData.Macd is not decimal macdMain || macdData.Signal is not decimal macdSignal)
return;
var cci = cciValue.ToDecimal();
var emaVal = emaValue.ToDecimal();
if (_prevMacdMain is not decimal prevMain || _prevMacdSignal is not decimal prevSignal)
{
_prevMacdMain = macdMain;
_prevMacdSignal = macdSignal;
return;
}
var macdBullCross = prevMain <= prevSignal && macdMain > macdSignal;
var macdBearCross = prevMain >= prevSignal && macdMain < macdSignal;
// Long: MACD bullish cross + CCI > 0 + price above EMA
if (Position <= 0 && macdBullCross && cci > 0 && candle.ClosePrice > emaVal)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Short: MACD bearish cross + CCI < 0 + price below EMA
else if (Position >= 0 && macdBearCross && cci < 0 && candle.ClosePrice < emaVal)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMacdMain = macdMain;
_prevMacdSignal = macdSignal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import (
CommodityChannelIndex,
ExponentialMovingAverage,
MovingAverageConvergenceDivergenceSignal
)
from StockSharp.Algo.Strategies import Strategy
class smc_trader_camel_cci_macd1_strategy(Strategy):
"""Strategy combining CCI and MACD signal crossover with EMA trend filter.
Buy when MACD crosses above signal with CCI positive and price above EMA.
Sell when MACD crosses below signal with CCI negative and price below EMA."""
def __init__(self):
super(smc_trader_camel_cci_macd1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ema_length = self.Param("EmaLength", 34) \
.SetDisplay("EMA Length", "Trend EMA period", "Indicators")
self._macd_fast_period = self.Param("MacdFastPeriod", 12) \
.SetDisplay("MACD Fast", "Fast EMA for MACD", "Indicators")
self._macd_slow_period = self.Param("MacdSlowPeriod", 26) \
.SetDisplay("MACD Slow", "Slow EMA for MACD", "Indicators")
self._macd_signal_period = self.Param("MacdSignalPeriod", 9) \
.SetDisplay("MACD Signal", "Signal line period", "Indicators")
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._prev_macd_main = None
self._prev_macd_signal = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@property
def CciPeriod(self):
return self._cci_period.Value
def OnReseted(self):
super(smc_trader_camel_cci_macd1_strategy, self).OnReseted()
self._prev_macd_main = None
self._prev_macd_signal = None
def OnStarted2(self, time):
super(smc_trader_camel_cci_macd1_strategy, self).OnStarted2(time)
self._prev_macd_main = None
self._prev_macd_signal = None
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.MacdFastPeriod
macd.Macd.LongMa.Length = self.MacdSlowPeriod
macd.SignalMa.Length = self.MacdSignalPeriod
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, cci, ema, self._process_candle).Start()
def _process_candle(self, candle, macd_value, cci_value, ema_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not cci_value.IsFinal or not ema_value.IsFinal:
return
macd_raw = macd_value.Macd if hasattr(macd_value, 'Macd') else None
signal_raw = macd_value.Signal if hasattr(macd_value, 'Signal') else None
if macd_raw is None or signal_raw is None:
return
macd_main = float(macd_raw)
macd_signal = float(signal_raw)
cci_val = float(cci_value)
ema_val = float(ema_value)
if self._prev_macd_main is None or self._prev_macd_signal is None:
self._prev_macd_main = macd_main
self._prev_macd_signal = macd_signal
return
prev_main = self._prev_macd_main
prev_signal = self._prev_macd_signal
macd_bull_cross = prev_main <= prev_signal and macd_main > macd_signal
macd_bear_cross = prev_main >= prev_signal and macd_main < macd_signal
close = float(candle.ClosePrice)
# Long: MACD bullish cross + CCI > 0 + price above EMA
if self.Position <= 0 and macd_bull_cross and cci_val > 0 and close > ema_val:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Short: MACD bearish cross + CCI < 0 + price below EMA
elif self.Position >= 0 and macd_bear_cross and cci_val < 0 and close < ema_val:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_macd_main = macd_main
self._prev_macd_signal = macd_signal
def CreateClone(self):
return smc_trader_camel_cci_macd1_strategy()