SMC トレーダー キャメル CCI MACD 戦略
概要
この戦略は、MetaTrader 4 エキスパート アドバイザー 「Steve Cartwright Trader Camel CCI MACD」 の StockSharp 移植です。
キャメルスタイルの指数移動平均チャネルに基づいたオリジナルの取引ロジックを再現します。
MACD トレンド フィルターと商品チャネル インデックス (CCI) のしきい値。取引は完了した時点で実行されます
キャンドルを使用して、決定的な動作を保証し、MQL バージョンの小節ごとのワークフローに近い状態を保ちます。
取引ロジック
- 指標
- 同じ期間の 2 つの指数移動平均 (EMA) がローソク足の高値と安値に適用されて、
ラクダチャンネル。これらのエンベロープを超える前の終値のブレイクアウトは、勢いの強さを示します。
- 標準の MACD インジケーター (速い EMA、遅い EMA およびシグナル ライン) は、基本的なトレンドの方向を確認するために使用されます。
- CCI インジケーターは、デフォルトで ±100 の買われすぎ/売られすぎレベルを使用して勢いの強さを検証します。
- 長いエントリ
- 前回のローソク足の終値はラクダの高値 EMA を上回っています。
- 以前の MACD のメイン値はゼロより上で かつ 信号線よりも上です。
- 以前の CCI の値は正のしきい値を超えています。
- アクティブなポジションがオープンしておらず、現在のローソク足の時間枠内にエグジットが発生しませんでした (急速なリエントリーが防止されます)。
- 短いエントリー
- 前回のローソク足の終値はラクダ安値 EMA を下回っています。
- 以前の MACD の主要値はゼロ未満であり、**かつ信号線を下回っています。
- 以前の CCI の値は負のしきい値を下回っています。
- ロングセットアップと同じフラットポジションとクールダウン条件。
- 出口
- 前の MACD のメイン値がシグナルラインを下回ったとき、または前の CCI のときにロングポジションが閉じられます。
値が正のしきい値を下回ります。
- 前の MACD メイン値がシグナルラインを上抜けたときにショートポジションが閉じられます。
- 終了後、新しいエントリーの前に、ローソク足の 1 本の期間に等しいクールダウンが適用されます。
すべての決定は以前に完了したローソク足のデータに基づいているため、この戦略はバーごとに最大 1 回取引されます。
パラメーター
| パラメータ |
説明 |
デフォルト |
CandleType |
すべてのインジケーターに使用されるローソク足のデータ型/タイムフレーム。 |
1時間枠 |
CamelLength |
高/低 EMA チャンネルの長さ。 |
34 |
CciPeriod |
CCI フィルターの長さ。 |
20 |
MacdFastPeriod |
MACD の高速な EMA の長さ。 |
12 |
MacdSlowPeriod |
MACD の EMA の長さが遅いです。 |
26 |
MacdSignalPeriod |
MACD の信号平滑化期間。 |
9 |
CciThreshold |
エントリに対して超える必要がある絶対的な CCI レベル (対称的に適用)。 |
100 |
すべてのパラメータは、SetOptimize 呼び出しのおかげで、StockSharp オプティマイザーを通じて最適化できます。
リスク管理
- 注文は
BuyMarket および SellMarket を介して送信され、戦略 Volume プロパティを継承します。
StartProtection() は、標準の StockSharp 保護ヘルパーを初期化するために有効になっています。
- 元のアルゴリズムでは固定のストップロスやテイクプロフィットは定義されていません。イグジットはインジケーター信号のみに依存します。
グラフ化
この戦略は、ラクダの EMA チャネル、MACD、および CCI インジケーターを独自の取引とともに自動的にプロットします。
これは、MT4 実装で使用される視覚的なキューを複製します。
注意事項
- クールダウン タイマーは、
CandleType.Arg から導出されたローソク足の継続時間を使用します。 CandleType に
期間を変更する場合は、TimeSpan 引数を使用します。
- すべての決定は前のバーの値に基づいているため、操作の順序は
iMACD、iCCI を反映します。
および iMA (shift=1 を指定) はソース EA を呼び出します。
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()