GitHub で見る

Bull & Bear Candle Martingale戦略

概要

この戦略は強い強気/弱気ローソク足に反応し、同じ方向へ成行ポジションを開きます。各側で独立したマーチンゲールシーケンスを使います。ロングポジションはBull Multiplierで数量を拡大し、ショートポジションはBear Multiplierを使います。保護用ストップロスとテイクプロフィット距離も方向ごとに別々に設定され、元のMQLエキスパートアドバイザーが公開する非対称動作を細かく制御できます。

取引ロジック

  1. 設定したローソク足タイプ(既定: 1分)を購読し、確定ローソク足のみを待ちます。
  2. オープンポジションがない場合:
    • 強気セットアップ: Close > Openかつローソク足実体サイズが強気実体フィルターを超える場合、成行で買います。
    • 弱気セットアップ: Close < Openかつ実体サイズが弱気実体フィルターを超える場合、成行で売ります。
  3. 各エントリーは、pip距離から銘柄価格ステップへ変換したストップロスとテイクプロフィット注文を設定します。
  4. ポジションが閉じると、実現PnLを前回の基準と比較します。
    • 結果が負の場合、対応するマーチンゲール数量を乗算します。
    • 正またはブレイクイーブンの場合、その側を初期数量へ戻します。
  5. ポジションが開いている間、新しいシグナルは無視され、元EAの単一取引動作を再現します。

資金管理

  • ロングとショートのマーチンゲールサイクルは独立して追跡されるため、ロングの損失連鎖は次のショート取引へ影響せず、その逆も同様です。
  • 注文拒否を避けるため、数量は銘柄のVolumeStepに合わせられます。
  • StartProtection(useMarketOrders: true)は、付与されたstop/take水準に対するStockSharp保護注文処理を有効にします。

パラメーター

パラメーター 説明
Initial Volume 両方向の各マーチンゲールサイクルを開始する基本数量。
Bull Multiplier ロング損失後の次の強気取引に適用する乗数。
Bear Multiplier ショート損失後の次の弱気取引に適用する乗数。
Bull Stop Loss 強気取引用のストップロス距離(pips)。銘柄ステップを使って価格へ変換されます。
Bull Take Profit 強気取引用のテイクプロフィット距離(pips)。
Bear Stop Loss 弱気取引用のストップロス距離(pips)。
Bear Take Profit 弱気取引用のテイクプロフィット距離(pips)。
Bull Body Filter 買い注文を発動するために必要な最小強気ローソク足実体(pips)。
Bear Body Filter 売り注文を発動するために必要な最小弱気ローソク足実体(pips)。
Candle Type シグナル生成に使う時間軸(既定: 1分足)。

使用上の注意

  • 接続された銘柄が有効なPriceStepVolumeStep値を公開していることを確認してください。PriceStepがない場合、戦略は既定で0.0001を使います。
  • マーチンゲールロジックは実現PnLに依存するため、手動でポジションを閉じてもシーケンスは正しく更新されます。
  • 最適化では、応答性とドローダウンのバランスを取るため、実体フィルターと乗数の組み合わせに焦点を当てられます。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bull/Bear Candle Martingale strategy: Bullish/bearish candle direction + EMA filter.
/// Buys after strong bullish candle when close crosses above EMA.
/// Sells after strong bearish candle when close crosses below EMA.
/// </summary>
public class BullBearCandleMartingaleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;

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

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

	public BullBearCandleMartingaleStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		decimal? prevClose = null;
		decimal? prevEma = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, (candle, emaVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;
				var bullish = close > candle.OpenPrice;
				var bearish = close < candle.OpenPrice;
				var bodySize = Math.Abs(close - candle.OpenPrice);
				var range = candle.HighPrice - candle.LowPrice;

				// Require strong candle body (>50% of range)
				var strongCandle = range > 0 && bodySize / range > 0.5m;

				if (prevClose.HasValue && prevEma.HasValue && strongCandle)
				{
					var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
					var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;

					if (bullish && crossUp && Position <= 0)
						BuyMarket();
					else if (bearish && crossDown && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevEma = emaVal;
			})
			.Start();

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