GitHub で見る

DLM v1.4 グリッド戦略

概要

この戦略は、Alejandro Galindo の MetaTrader 4 エキスパート アドバイザー「DLM v1.4」の StockSharp 移植です。オリジナルのロボットは、フィッシャー変換信号フィルターとマーチンゲール スタイルの平均化スキームを組み合わせており、価格が最後のエントリーに対して変動するたびにポジションのグリッドを段階的に構築します。 StockSharp バージョンは、同じ資金管理のアイデアを維持しながら、実行と保護のロジックを高レベルの API (キャンドル サブスクリプション、インジケーター バインディング、マーケット/リミット ヘルパー) に適応させています。

取引ロジック

  • 構成された時間枠から終了したローソク足を分析し、フィッシャー変換とフィッシャー値の SMA 平滑化という 2 つの指標を計算します。
  • 2 本の線の相対位置からバスケットの方向を決定します。フィッシャーがスムーザーを上回ったとき、戦略は買いの準備をします。スムーサーを下回ると売却の準備をします。 ReverseSignals フラグはこの解釈を逆転します。
  • 方向が利用可能になり、自動取引が有効になったら (ManualTrading = false)、最初のポジションをすぐにオープンします (成行注文)。
  • バスケットがアクティブな間、最新の約定に対して価格が GridDistancePips 変動するたびに新しいエントリを追加し続けます。 UseLimitOrders フラグに応じて、追加の取引は成行注文 (次のローソク足の終値) として送信されるか、最後の約定からちょうど 1 グリッド ステップ離れた位置にある休止指値注文として送信されます。
  • それぞれの新しい取引の量は元のマーチンゲールの増加に従います。MaxTrades > 12 の場合は基本ロット サイズに 1.5 を掛け、それ以外の場合はサイズを 2 倍にします。基本サイズ自体は固定することも (LotSize)、または UseMoneyManagement が有効な場合はアカウントの資本から導き出すこともできます。
  • 約定ごとに集計されたストップロスとテイクプロフィットのレベルが更新されるため、バスケット全体が単一セットの保護レベルを共有します。トレーリングストップ ロジックでは、価格が収益性の高い方向に GridDistancePips + TrailingStopPips 移動した後にストップを引き締めることができます。

アカウントの保護

  • 安全な利益ガード (SecureProfitProtection): 未決済エントリの数が OrdersToProtect に達すると、未実現利益 (口座通貨) が SecureProfit と比較されます。しきい値に達すると、バスケット全体が直ちに閉じられます。
  • 株式保護 (EquityProtection + EquityProtectionPercent): 現在のポートフォリオの価値を監視し、株式が戦略開始時に取得された株式の選択された割合を下回るたびにバスケットを閉じます。
  • 資金ドローダウン保護 (AccountMoneyProtection + AccountMoneyProtectionValue): 初期資本からの通貨ドローダウンが設定された金額を超えると取引を停止します。
  • ライフタイム保護 (OrdersLifeSeconds): 最新のエントリに最大ライフタイムを強制します。制限を超えると、すべての取引が終了し、マーチンゲール サイクルが停止します。
  • 金曜日フィルター (TradeOnFriday): 無効にすると、金曜日に新しいバスケットが開始されなくなります。

すべての保護的出口は成行注文を使用して約定を保証します。未決の指値注文は、保護ブロックがトリガーされるかグリッドがリセットされるたびにキャンセルされます。

パラメーター

パラメータ 説明
TakeProfitPips すべてのエントリーに適用される共有テイクプロフィットディスタンス (pips)。
StopLossPips 新しい取引ごとの最初のストップロス距離 (pips)。
TrailingStopPips トリガーしきい値の後にアクティブになるトレーリング ストップの距離。
MaxTrades バスケット内で許可される平均ステップの最大数。
GridDistancePips 次の注文を追加する前の最小逆動き (pips)。
LotSize 資金管理が無効になっている場合の基本ロット サイズ。
UseMoneyManagement オリジナルのリスク計算式による残高ベースのサイジングを可能にします。
RiskPercent 動的な基本ロットサイズを導き出すために使用されるリスクパーセンテージ。
AccountType 動的なロット サイズに適用されるスケーリング (0 標準、1 ミニ、2 マイクロ)。
SecureProfitProtection 変動利益ガードを有効にします。
SecureProfit ガードをトリガーするには未実現利益 (通貨単位) が必要です。
OrdersToProtect 安全な利益が有効になるまでのオープンエントリーの最小数。
EquityProtection 自己資本比率のセーフティネットを有効にします。
EquityProtectionPercent 戦略の開始を基準とした資本パーセンテージのしきい値。
AccountMoneyProtection ドローダウン (通貨) ベースの保護を有効にします。
AccountMoneyProtectionValue 口座通貨での最大許容ドローダウン。
TradeOnFriday 金曜日に新しいバスケットを開くことを許可/禁止します。
OrdersLifeSeconds 清算前の最新注文の最大存続期間 (秒)。
ReverseSignals フィッシャー変換の方向を反転します。
UseLimitOrders マーケットを切り替えて、平均取引のエントリーを制限します。
ManualTrading true に設定すると、自動エントリが無効になります。
CandleType インジケーターの計算に使用される時間枠。
FisherLength フィッシャー変換のルックバックの長さ。
SignalSmoothing SMA 期間は平滑化フィッシャー値に適用されます。
DefaultPipValue 未実現損益を通貨に変換するために使用されるフォールバック pip 値。

注意事項

  • リポジトリ ガイドラインの要求に従って、ソース コード内のすべてのコメントは英語で記載されています。
  • この戦略は、StockSharp の高レベルの API (SubscribeCandlesBindBuyLimitSellLimit など) のみに依存しており、インジケーター バッファーを直接操作しません。
  • 資金管理の計算では元のリスク計算式が再利用されますが、商品の契約仕様を尊重するため、出来高と価格の調整は Security.ShrinkVolumeSecurity.ShrinkPrice を介して行われます。
  • この変換により、StockSharp の違いを考慮しながら、MetaTrader EA の動作が可能な限り近く維持されます (たとえば、バスケットの終了では、既存の注文を変更する代わりに成行注文が使用されます)。
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>
/// DLM v1 Grid strategy - EMA with RSI direction filter.
/// Buys when EMA is rising and RSI is above 50.
/// Sells when EMA is falling and RSI is below 50.
/// </summary>
public class Dlmv1GridStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private bool _hasPrev;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Dlmv1GridStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 14)
			.SetDisplay("EMA Period", "EMA lookback", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI 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(); _prevEma = 0m; _hasPrev = false; }

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

		_hasPrev = false;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, rsi, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevEma = ema;
			_hasPrev = true;
			return;
		}

		// EMA rising + RSI above 50 = buy
		if (ema > _prevEma && rsi > 50 && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// EMA falling + RSI below 50 = sell
		else if (ema < _prevEma && rsi < 50 && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevEma = ema;
	}
}