GitHub で見る

CCI MACD ダフ屋

概要

CCI MACD スカルパーは、MetaTrader 5 エキスパート アドバイザー「CCI + MACD スカルパー」を StockSharp の高レベル戦略 API に移植します。この変換では、資金管理ロジックを StockSharp の規則に変換しながら、元のインジケーター スタック(EMA トレンド フィルター、CCI ゼロライン トリガー、MACD 発散チェック)を維持します。注文はポートフォリオの資産から自動的に決定され、距離が近すぎる場合はストップが拒否され、オプションのトレーリングストップは最初の調整後にポジションを部分的にクローズすることで利益を確保できます。 5 つのキャンドルのクールダウンにより、実行直後にストラテジーが再入することがなくなり、MQL タイマーの動作が再現されます。

戦略ロジック

インジケーターとデータ処理

  • ローソク足 – 1 つの構成可能な時間枠によってすべての計算が行われます。再描画を避けるために、信号は完成したキャンドルのみで評価されます。
  • EMA(34) – 終値指数移動平均は方向性フィルターとして機能します。ロングの場合は最新の終値が以前の EMA の値を上回る必要があり、ショートの場合は終値がそれを下回っている必要があります。
  • CCI(50) – 勢いトリガーとして使用されます。この戦略は、最後に完成した 2 つのローソク足で発生したゼロラインのクロスを待ちます (現在のローソク足は設定を確認しますが、論理比較には参加しません)。
  • MACD(12,26,9) – MACD のメイン ラインとシグナル ラインは両方とも、前の 2 つのローソク足でゼロの同じ側に留まっている必要があります。エントリーするには、MACD シグナル ラインがこれら 2 つのバーの間のポジションを優先してメイン ラインを横切る必要があります (ロングの場合は強気のクロスオーバー、ショートの場合は弱気のクロスオーバー)。
  • スイングバッファ – 最後の 5 つの終了したローソク足の高値と安値がストップロスの基準を形成します。ロングは最低安値に固定され、ショートは最高高値にアンカーされ、1 バーのシフトで MetaTrader iLowest/iHighest の呼び出しと正確に一致します。

エントリールール

  • セッション制御 – ローソク足の終了時間が現地ターミナル時間で [MinHour, MaxHour] 以内にある場合にのみ取引が許可されます。
  • クールダウン – 各エントリーが記入された後、システムは新しい取引を許可する前に 5 つのローソク足期間待機し、元のコードから EventSetTimer をミラーリングします。
  • 長いセットアップ
    • アクティブなロングポジション (Position <= 0) がありません。
    • 終値が以前の EMA 値を上回っています。
    • CCI は、直近の 2 つの閉じたローソク足でマイナスからプラスに転じました。
    • 同じ 2 つのバーの間に、MACD のクロスオーバーがゼロ以下で発生しました (信号は MACD を超えました)。
    • 直近のスイングローに位置するストップロスは、最小距離制約を満たします。
  • 簡単なセットアップ
    • アクティブなショートポジション (Position >= 0) はありません。
    • 終値が以前の EMA の値を下回っています。
    • CCI は、完了した最後の 2 つのローソク足でプラスからマイナスに転じました。
    • MACD クロスオーバーがゼロより上で発生しました (信号は MACD を下回りました)。
    • スイングハイでのストップロスは、最小距離要件を尊重します。

リスクと取引の管理

  • 動的なポジションサイジング – 取引サイズは、ポートフォリオ株式の設定された RiskPercent から導出されます。契約ごとのリスクは、ストップロス距離、証券価格ステップおよびステップ値から計算されます。結果はインストゥルメントのボリュームステップにスナップされ、最小ボリュームと最大ボリュームの間にクランプされます。
  • ストップロス / テイクプロフィット – ストップロスは選択された極端なスイングを使用し、距離が MinimalStopLossPoints を下回る場合は拒否されます。テイクプロフィットは entry ± RiskReward × stopDistance に等しく、EA の報酬対リスクの計算と一致します。
  • トレーリングストップ (オプション) – 有効にすると、価格が前のストップを十分に超えて終了すると、ストップが TrailingStopPoints だけ移動します。最初のトレーリング調整は、元のボリュームの半分を閉じる部分的な終了をトリガーし、MetaTrader の実装を忠実にミラーリングします。
  • 保護的エグジット – ロングの場合、価格がストップレベル (ローソク足の安値) を突破するか、テイクプロフィットレベル (ローソク足の高値) に達すると、ポジションがクローズされます。ショートは、ローソク足の高値と安値をそれぞれ使用したロジックを反映します。

パラメーター

名前 説明 デフォルト
CandleType インジケーターの計算を駆動する時間枠。 15分キャンドル
RiskPercent 各取引でリスクを負うポートフォリオ資産の割合。 2%
RiskReward テイクプロフィットレベルの報酬とリスクの乗数。 1.5
EmaPeriod EMA トレンド フィルターの長さ。 34
CciPeriod 商品チャネルインデックスの長さ。 50
MinHour 新しい取引が開始される可能性がある最も早い時間 (両端を含む)。 0
MaxHour 新しい取引が開始される可能性のある最新の時間 (含む)。 24
MinimalStopLossPoints 価格ポイントで表されるエントリーとストップロスの間の最小許容距離。 100
UseTrailingStop トレーリングストップモジュールと部分的なテイクプロフィットを有効にします。 障害者
TrailingStopPoints トレーリング ストップの距離は価格ポイントで測定されます。 100

追加の注意事項

  • 価格ポイントの変換は証券の PriceStep に依存します。有効なステップのないシンボルは、1 価格単位の距離にフォールバックします。
  • ポートフォリオの資本は Portfolio.CurrentValue から取得され、現在の評価額が利用できない場合は BeginValue に戻ります。両方が欠落している場合、戦略は基本の Volume プロパティに戻ります。
  • この戦略には Python ポートはありません。 API パッケージには C# バージョンのみが含まれています。
using System;
using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "CCI MACD Scalper" MetaTrader expert.
/// Uses CCI zero-line crossover with EMA trend filter for scalping entries.
/// </summary>
public class CciMacdScalperStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _cciPeriod;

	private ExponentialMovingAverage _ema;
	private CommodityChannelIndex _cci;
	private decimal? _prevCci;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public int CciPeriod
	{
		get => _cciPeriod.Value;
		set => _cciPeriod.Value = value;
	}

	public CciMacdScalperStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for scalping", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");

		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "CCI period for zero-line crosses", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevCci = null;
		_ema = new ExponentialMovingAverage { Length = EmaPeriod };
		_cci = new CommodityChannelIndex { Length = CciPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_ema, _cci, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal cciValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_ema.IsFormed || !_cci.IsFormed)
		{
			_prevCci = cciValue;
			return;
		}

		if (_prevCci is null)
		{
			_prevCci = cciValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var close = candle.ClosePrice;

		// CCI crosses back above the oversold zone with trend confirmation -> buy
		var cciCrossUp = _prevCci.Value <= -50m && cciValue > -50m;
		// CCI crosses back below the overbought zone with trend confirmation -> sell
		var cciCrossDown = _prevCci.Value >= 50m && cciValue < 50m;

		if (cciCrossUp && close > emaValue)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (cciCrossDown && close < emaValue)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevCci = cciValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_ema = null;
		_cci = null;
		_prevCci = null;

		base.OnReseted();
	}
}