GitHub で見る

ダブルアップ戦略

概要

Double Up 戦略は、MetaTrader エキスパート アドバイザー DoubleUp.mq4 を直接移植したものです。これは、商品チャネル指数 (CCI) オシレーターと MACD インジケーターのメインラインを組み合わせて極端なモメンタム状態を検出し、マーチンゲール スタイルのポジションサイジング モデルを適用します。両方のオシレーターが同じ極端なゾーンに達すると、アルゴリズムは反対方向の取引に向けて準備を整えます。 CCI が中間点に向かって戻ると、この戦略は、(既存のショートを閉じた後) 新しいロング ポジションをオープンするか、(既存のロングを閉じた後) 新しいショート ポジションをオープンします。

すべての新しいポジションの出来高は指数関数的進行 (baseVolume * 2^lossCounter) に基づいています。連続して負けて終了すると指数が増加しますが、利益を上げて終了すると、蓄積された待機バッファに従って進行状況がリセットされます。この動作は、pos 変数と wait 変数が適用される乗数を制御する元のコードのピラミッド ロジックを反映しています。

取引ロジック

  • 単一のローソク足シリーズをサブスクライブし、CCI (デフォルトの長さ 8) と MACD メインライン (デフォルトの高速 13、低速 33、シグナル 2) を計算します。
  • MACD の読み取り値に 100 万を掛けて、その大きさが CCI のしきい値レベルと一致するようにします。
  • 両方のオシレーターが +Threshold を超えたら、将来のショートエントリーに備えて戦略を準備します。両方のオシレーターが -Threshold を下回ったら、将来のロングエントリーに向けて準備します。
  • 保留中の長いエントリは、CCI の値が +Threshold を下回るとすぐに実行されます。保留中のショート エントリは、ショート フラグがアクティブなときに CCI が -Threshold を下回ると実行され、元のコードの正確な順序が再現されます。
  • 新しいポジションをオープンする前に、アルゴリズムは反対側のエクスポージャを完全にクローズします。新しい注文は、すべての終了取引が終了した後にのみ発送されます。
  • イグジットトレードは、シグナル反転中に生成される成行注文です。クローズされた各取引の実現損益がマーチンゲール カウンターに入力されます。

ポジションサイジングモデル

  • 出口に負けると、損失カウンターが増加します。カウンタが PreWait に達すると、その値が待機バッファに追加され、損失カウンタがゼロにリセットされます。
  • 利益を上げて終了すると、(切り捨てられた) 待機バッファ値が損失カウンタに転送され、バッファがクリアされます。したがって、将来の取引サイズは 2^lossCounter ロットから始まります。
  • 待機バッファは InitialWait から初期化され、それ以外の場合は上記のルールによって制御されます。

パラメーター

名前 デフォルト 説明
CciPeriod 8 商品チャネル指数の期間。
Threshold 230 オシレーターの極値を検出するために使用される絶対レベル。
MacdFastPeriod 13 MACD の高速な EMA 計算。
MacdSlowPeriod 33 MACD の計算の EMA の長さが遅いです。
MacdSignalPeriod 2 信号 EMA の長さは、MetaTrader の呼び出し署名と一致するために必要です。
BaseVolume 0.01 マーチンゲール指数を適用する前のボリューム乗数の開始。
InitialWait 0 待機バッファの初期値 (元のスクリプトの wait 変数)。
PreWait 2 待機バッファに損失カウンタが蓄積されるまでに必要な、連続損失終了の最小数。
BackShift 0 インジケーター測定値の歴史的な推移。このポートではゼロのみがサポートされます。
CandleType 15分の時間枠 データフィードからリクエストされたローソクのタイプ。 MetaTrader で使用されるチャートの時間枠に一致するように調整します。

注意事項

  • このポートは現在、元の Expert Advisor のデフォルト設定をミラーリングする BackShift = 0 のみをサポートしています。
  • すべての注文の送信とクローズには成行注文が使用されます。必要に応じて、個別のプロテクション (ストップロス、テイクプロフィット) をアタッチします。
  • この戦略では取引に負けた後にポジションサイズが 2 倍になるため、証拠金制限とリスク管理が取引商品に適切であることを確認してください。
using System;

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

namespace StockSharp.Samples.Strategies;

public class DoubleUpStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

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

	public DoubleUpStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

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

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

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