GitHub で見る

MA2CCI アダプティブボリューム戦略

概要

MA2CCI 戦略は、当初「MA2CCI.mq4」として配布された MetaTrader 4 エキスパート アドバイザの直接移植です。このシステムは、高速/低速単純移動平均 (SMA) クロスオーバーと商品チャネル指数 (CCI) のゼロライン確認を組み合わせています。検証されたすべてのクロスオーバーは単一の市場ポジションを開き、すぐに平均トゥルー レンジ (ATR) に基づいた保護ストップを設定します。ポジションサイジングは、株式に応じて注文サイズを調整し、連続損失取引の後に注文サイズを減らすことにより、元の資金管理ロジックに従います。

指標とデータ

  • 設定された時間枠で 速い SMA (FMa)遅い SMA (SMa) を検出し、トレンドの反転を検出します。
  • コモディティ チャネル インデックス (CCI) と同じ価格ストリームで、ゼロライン クロスを通じて勢いの方向を確認します。
  • 平均トゥルー レンジ (ATR) は、最近のボラティリティを測定し、ストップロス距離を導き出します。
  • 選択した時間枠 (デフォルトは 15 分) の ローソク足は、すべてのインジケーターの入力系列を提供します。

取引ルール

  • ロングエントリー: 速い SMA が遅い SMA を上抜けている一方で、CCI は同じ足でマイナスからプラスにクロスしており、ポジションはオープンしておらず、取引は許可されています。成行買い注文が送信され、close − ATR × AtrMultiplier でストップロスが設定されます。
  • ショートエントリー: 速い SMA が遅い SMA を下回ってクロスしている一方、CCI はプラスからマイナスにクロスしています。オープンポジションはありません。成行売り注文は、close + ATR × AtrMultiplier でストップロスを指定して発注されます。
  • ロングポジションの終了: 速い SMA が遅い SMA を下回った場合、ロングポジション全体が市場でクローズされます。保護停止も解除されます。
  • ショートのためのエグジット: 速い SMA が遅い SMA を上回った場合、ショートポジションは市場でカバーされ、ストップはキャンセルされます。
  • ストップロス: 新しいポジションごとに、MetaTrader ロジックを反映したボラティリティ ストップが復元されます。ストップは新しいエントリでのみ再計算され、別の条件付き注文として保存されます。

ポジションサイズ

  • 基本ロット サイズは BaseVolume パラメータから始まります (デフォルトは 0.1 ロット)。
  • RiskFraction が正の場合、ストラテジーは元の AccountFreeMargin 式を模倣して equity × RiskFraction / 1000 を使用して追加のサイズを計算し、両方の値の間の最大値を使用します。
  • 2 回以上連続して負けた取引の後、ロットサイズは volume × losses / DecreaseFactor だけ減少し、DcF ドローダウン コントロールが複製されます。
  • 音量は楽器の VolumeStep に正規化されます。

パラメーター

名前 デフォルト 説明
FastMaPeriod 4 SMA の高速ルックバック期間。
SlowMaPeriod 8 SMA のルックバック期間が遅いです。
CciPeriod 4 コモディティチャネルインデックス期間。
AtrPeriod 4 停止距離に使用される平均 True Range 期間。
AtrMultiplier 1.0 ストップロスを設定する前に ATR に適用される乗数。
BaseVolume 0.1 リスク調整前の最小取引サイズ。
RiskFraction 0.02 取引ごとにリスクが生じる株式の割合(1000通貨単位あたり)。
DecreaseFactor 3 損失後にサイズがどれだけ速く縮小するかを制御する除数。
CandleType 15分キャンドル インジケーターとシグナルに使用される時間枠。

注意事項

  • 元のエキスパート アドバイザー (SndMl) からの電子メール通知は意図的に省略されています。
  • ソース コードの MetaTrader の動作に一致する、一度にオープンできるポジションは 1 つだけです。
  • 孤立注文がブックに残らないように、ポジションが反転またはクローズされるたびに保護ストップが再作成されます。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MA2CCI Adaptive Volume strategy - dual EMA crossover with CCI filter.
/// Buys when fast EMA crosses above slow EMA and CCI is above zero.
/// Sells when fast EMA crosses below slow EMA and CCI is below zero.
/// </summary>
public class Ma2CciAdaptiveVolumeStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Ma2CciAdaptiveVolumeStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 8)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetDisplay("CCI Period", "CCI lookback", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var cci = new CommodityChannelIndex { Length = CciPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, cci, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal cci)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_prevFast <= _prevSlow && fast > slow && cci > 0 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (_prevFast >= _prevSlow && fast < slow && cci < 0 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		_prevFast = fast; _prevSlow = slow;
	}
}