GitHub で見る

シンプルな Martingale テンプレート戦略

概要

この戦略は、元の MetaTrader の「シンプルな Martingale テンプレート」のアイデアを StockSharp で再現したものです。単純な移動平均のペア (SMA) を使用して、設定可能な時間枠の終了したローソク足を分析します。ブレイクアウトフィルターは、前のローソク足の終値がさらに前のローソク足の高値または安値をブレイクアウトするかどうかをチェックして、方向を確認します。ポジション サイズはマーチンゲール数列に従います。負けるサイクルごとに次の取引量が倍増され、利益が得られるサイクルでは、設定された基本サイズに量がリセットされます。

取引ロジック

  1. CandleType 時間枠のローソク足を購読します。完成したキャンドルのみが信号生成に参加します。
  2. ローソク足の終値で速い SMA と遅い SMA を計算します。
  3. 次の場合に購入シグナルを生成します。
    • 最後に終了したローソク足の終値は速い SMA を上回っています。
    • 高速な SMA は低速な SMA を上回っています。
    • 前のローソク足では、速い SMA が遅い SMA を下回っていました、そして
    • 最後に終了したローソク足の終値は、2 バー前のローソク足の高値を上回っています。
  4. 終値が 2 バー前のローソク足の安値を下回るなど、下向きの対称条件が発生した場合に 売り シグナルを生成します。
  5. シグナルが発生し、オープンポジションやアクティブな注文がない場合は、現在計算されているマーチンゲール量を使用して成行注文を送信します。
  6. 将来のローソク足を監視して、総合的なストップロスとテイクプロフィットのレベルを設定します。価格がいずれかのレベルに達したら、オープンポジションを閉じます。
  7. ポジションがクローズされ、ポートフォリオ残高が更新されると、次のようになります。
    • 残高が増えた場合は、音量を BaseVolume の値にリセットします。
    • 残高が減少した場合は、最後の取引量に Multiplier を掛けて、商品の量ステップに合わせます。

パラメーター

名前 説明
StopLossPoints 価格ポイントでのエントリーから保護ストップまでの距離。
TakeProfitPoints 価格ポイントでのエントリーから利益目標までの距離。
BaseVolume マーチンゲール サイクルの初期ロット サイズ。
Multiplier 損失後の以前のロットサイズに適用される係数。
FastPeriod 方向バイアスに使用される高速 SMA の長さ。
SlowPeriod トレンド確認のための低速 SMA の長さ。
CandleType 戦略によって処理されるローソク足のタイムフレーム。

資金管理

  • マーチンゲール ラダーは、現実のバランス変化に厳密に反応します。ノイズを避けるため、小さな変動 (±0.01 通貨単位) は無視されます。
  • 有効な注文サイズを確保するために、ボリュームは商品 VolumeStepMinVolume、および MaxVolume に合わせて調整されます。
  • ストップロスとテイクプロフィットのレベルは、為替注文を行うのではなく、ローソク足の極値(高値/安値)で監視され、市場出口を使用した元の MQL 実装を反映しています。

使用上の注意

  • 取引を可能にする前に、両方の SMA が形成するのに十分なヒストリカル ローソク足を生成する時間枠とシンボルの組み合わせを選択します。
  • シンボルの目盛サイズに一致するように StopLossPointsTakeProfitPoints を調整します。これらは価格単位ではなくポイント数を表します。
  • マーチンゲール数列は急速に増大するため、資本要件を制御するために、さまざまな乗数とベース ボリュームをテストすることを検討してください。
  • この戦略は、開始時に StartProtection() を呼び出して、StockSharp の標準リスク管理機能と統合します。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Simple Martingale Template strategy: SMA crossover with momentum confirmation.
/// Buys on fast SMA crossing above slow SMA, sells on crossing below.
/// </summary>
public class SimpleMartingaleTemplateStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

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

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

	public SimpleMartingaleTemplateStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
				BuyMarket();
			else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
				SellMarket();
		}
		else
		{
			if (fastValue > slowValue && Position <= 0)
				BuyMarket();
			else if (fastValue < slowValue && Position >= 0)
				SellMarket();
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
		_hasPrev = true;
	}
}