GitHub で見る

マルチロットスキャルパー戦略

概要

Multi Lot Scalper Strategy は、古典的な MetaTrader エキスパート アドバイザー「Multi Lot Scalper」から変換されたマーチンゲール スタイルの平均化システムです。元のアルゴリズムは主要なFXペア向けに設計されており、MACD ヒストグラムの傾きに基づいて、市場が強気局面に入っているか弱気局面に入っているかを判断していました。方向が特定されると、この戦略は成行注文のはしごを開き、逆方向に動くたびに量を徐々に増やします。 StockSharp ポートは、元のエントリー ロジック、資金管理ルール、保護メカニズムを維持しながら、高レベルのキャンドル サブスクリプション API を活用します。

この戦略は、スプレッドが狭く、ピップの定義が安定している流動的な商品で最も効果的です。デフォルトでは、15 分のローソク足をサブスクライブしますが、商品と互換性のある他の時間枠は、CandleType パラメーターを通じて指定できます。

取引ロジック

  1. シグナル検出 – MACD インジケーター (MacdFastLengthMacdSlowLengthMacdSignalLength) は、完成したすべてのキャンドルで評価されます。 MACD メインラインが前の値と比較して上昇すると、戦略はロングの機会を探しますが、そうでない場合はショートの準備をします。 ReverseSignals パラメータは、逆張りエントリーを好むユーザー向けにこの解釈を反転します。
  2. 最初のエントリー – 日付/時刻フィルター (StartYearStartMonthEndYearEndMonthEndHourEndMinute) が取引を許可している限り、有効なシグナルの直後に新しいシーケンスの最初のポジションがオープンされます。 MetaTrader の実装を反映して、成行注文が使用されます。
  3. ピラミッド – 価格が最新の約定に対して少なくとも EntryDistancePips だけ変動した場合にのみ、後続の注文がトリガーされます。追加の取引ごとに、基本ボリュームが 2 倍または 1.5 倍(MaxTrades が 12 を超える場合)、EA のマーチンゲール サイズが再現されます。
  4. ストップとターゲットInitialStopPipsTakeProfitPips はバスケット全体の価格レベルに変換されます。トレーリングストップは、有利な動きが EntryDistancePips + TrailingStopPips を超えた後に有効になり、市場が加速するにつれて出口が狭まります。
  5. アカウント保護 – バスケットがその容量 (MaxTrades - OrdersToProtect) に近づき、変動利益が SecureProfit に達すると、UseAccountProtection が有効になっている場合、戦略は最新の取引を終了し、新規エントリーを一時的にブロックします。

資金管理

元のエキスパートアドバイザーはオプションで、口座残高の関数として基本ロットサイズを再計算しました。 StockSharp ポートは、UseMoneyManagementRiskPercent、および IsStandardAccount パラメータを通じてこの動作を維持します。この機能が有効な場合、基本ロット (LotSize) は無視され、代わりにポートフォリオ値から導出され、MQL コードと同様にミニ口座または標準口座向けにスケーリングされます。

パラメーター

パラメータ 説明 デフォルト
TakeProfitPips 各エントリーに適用されるテイクプロフィットディスタンス(pips 単位で表現)。 40
LotSize 資金管理が無効な場合に使用される基本ロット サイズ。 0.1
InitialStopPips 初期のストップロス距離 (pips)。 0
TrailingStopPips しきい値を超えた後にアクティブになるトレーリング ストップの距離。 20
MaxTrades 同時に許可されるマーチンゲール エントリの最大数。 10
EntryDistancePips 新しい注文を追加する前の逆方向の動きを最小限に抑えます。 15
SecureProfit アカウント保護をトリガーするには変動利益 (通貨) が必要です。 10
UseAccountProtection 安全な利益のしきい値に達したときに最後の取引を終了できるようにします。 true
OrdersToProtect 確実な利益ルールの影響を受ける最終取引の数。 3
ReverseSignals MACD の解釈を反転します (強気はショート、弱気はロングになります)。 false
UseMoneyManagement 口座残高ベースのロット計算が可能になります。 false
RiskPercent 資金管理がアクティブな場合に使用されるリスクの割合。 12
IsStandardAccount ミニロット スケーリングの代わりに標準ロット スケーリングを使用します。 false
EurUsdPipValue EURUSD の PIP 値の上書き。 10
GbpUsdPipValue GBPUSD の PIP 値のオーバーライド。 10
UsdChfPipValue USDCHF の Pip 値のオーバーライド。 10
UsdJpyPipValue USDJPY の Pip 値の上書き。 9.715
DefaultPipValue 他のインストゥルメントに使用されるフォールバック pip 値。 5
StartYear 新しいポジションが募集される最初の暦年。 2005
StartMonth 最初の 1 か月間は新規エントリーが許可されます。 1
EndYear 取引を開始した最後の暦年。 2006
EndMonth 取引を開始する最後の暦月。 12
EndHour 新しいエントリがブロックされるまでの時間 (24 時間)。 22
EndMinute 毎日のカットオフ時間の分部分。 30
CandleType 信号生成に使用されるキャンドル タイプ (デフォルトは 15 分)。 15-minute time frame
MacdFastLength MACD インジケーターの高速な EMA 長さ。 14
MacdSlowLength MACD インジケーターの EMA の長さが遅いです。 26
MacdSignalLength MACD インジケーターの EMA の長さを信号します。 9

使用ガイドライン

  • 機器の pip ステップが pip 値の設定と一致していることを確認してください。 CFD、金属、または暗号資産に戦略を適用する場合は、pip 値パラメーターを更新します。
  • マーチンゲール法では、露出が急速に増加する可能性があります。より大きなバスケットを試す前に、控えめな MaxTradesEntryDistancePips、および TrailingStopPips の値から始めてください。
  • 取引される商品の MACD 設定とローソク足間隔を最適化します。通常、チャートが遅いと平均化ステップの数が減りますが、チャートが速いとアクティビティが増加します。
  • アカウント保護ルールは、突然の反転が起こりやすい市場では特に重要です。確保された利益が頻繁に達成されない場合は、SecureProfit を減らすか、TrailingStopPips を引き締めることを検討してください。
  • 取引ウィンドウ フィルターを使用すると、選択した日中時間の後に戦略を無効にすることができます。これは、ニュースリリースやセッション後半のボラティリティを回避するのに役立ちます。

変換メモ

  • StockSharp バージョンは、手動ティック処理の代わりに高レベルのローソク足サブスクリプション API (SubscribeCandles().BindEx(...)) を使用し、インジケーター管理の透明性を保ちます。
  • トレーリングストップは、各子注文を個別に変更するのではなく、バスケットの集計ストップレベルを管理することによって内部的に処理され、ポートフォリオを認識した環境で意図された動作を反映します。
  • EA による位置サイジングのための AccountBalance の使用は、Portfolio.CurrentValue プロパティにマッピングされ、MetaTrader と StockSharp の実装間の同等性が維持されます。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Multi Lot Scalper: MACD slope scalping with EMA filter and ATR stops.
/// </summary>
public class MultiLotScalperStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _emaFilterLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevMacd;
	private decimal _entryPrice;

	public MultiLotScalperStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastEmaLength = Param(nameof(FastEmaLength), 12)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowEmaLength = Param(nameof(SlowEmaLength), 26)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_emaFilterLength = Param(nameof(EmaFilterLength), 50)
			.SetDisplay("EMA Filter", "Trend filter.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

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

	public int FastEmaLength
	{
		get => _fastEmaLength.Value;
		set => _fastEmaLength.Value = value;
	}

	public int SlowEmaLength
	{
		get => _slowEmaLength.Value;
		set => _slowEmaLength.Value = value;
	}

	public int EmaFilterLength
	{
		get => _emaFilterLength.Value;
		set => _emaFilterLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevMacd = 0;
		_entryPrice = 0;
	}

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

		_prevMacd = 0;
		_entryPrice = 0;

		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var emaFilter = new ExponentialMovingAverage { Length = EmaFilterLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, emaFilter, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var macd = fastVal - slowVal;

		if (_prevMacd == 0 || atrVal <= 0)
		{
			_prevMacd = macd;
			return;
		}

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 1.5m || macd < _prevMacd && macd < 0)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 1.5m || macd > _prevMacd && macd > 0)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (macd > 0 && _prevMacd <= 0 && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (macd < 0 && _prevMacd >= 0 && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevMacd = macd;
	}
}