GitHub で見る

VRスマートグリッドライト戦略

VR Smart Grid Lite 戦略 は、同じ名前の MetaTrader エキスパート アドバイザーのロジックを複製します。この戦略では、成行注文を使用してマーチンゲール スタイルの平均グリッドを構築します。ポジションのサイジングは基本ボリュームから始まり、価格が既存のポジションに対してユーザー定義の距離だけ移動するたびに 2 倍になります。この戦略は 2 つのエグジット モードをサポートしています。加重テイクプロフィット価格で極端な取引を終了するか、グリッドをアクティブに保ちながらエクスポージャを部分的に削減します。

パラメーター

  • 利益確定 (pips) – 1 つのポジションのみがアクティブな場合に決済するために使用される距離 (pips)。
  • 開始数量 – 各方向の最初の取引の初期注文数量。
  • 最大ボリューム – グリッドによってオープンされた単一注文のハードキャップ。
  • クローズ モードAverage は加重ターゲットで最も古い注文と最新の注文をクローズします。 PartClose は、最新の注文の一部と最も古い注文のすべてをクローズします。
  • 注文ステップ (pips) – 新しい取引が開始される前にポジションに対して移動する必要がある最小価格距離。
  • 最小利益 (pips) – 加重平均エグジット価格に追加される追加の利益幅。
  • スリッページ (pips) – 完全を期すため、元の EA から保持されているプレースホルダー パラメーター。
  • ローソクの種類 – 意思決定を促進するために使用される時間枠 (以前に完了したローソク足が取引バイアスを決定します)。

アルゴリズム

  1. 終了したローソクごとに、戦略は前のローソクの方向を評価します。
  2. 前のローソク足が強気で終了し、ロング取引が存在しないか、設定されたステップによって価格が下がった場合、新しい買い市場注文が発注されます。
  3. 前のローソク足が弱気で終了し、空売り取引が存在しないか、設定されたステップによって価格が上昇した場合、新しい売り市場注文が発注されます。
  4. 出来高は、その方向の最低価格のポジションから計算され、最大出来高とブローカーの出来高ステップを考慮して、新しいレベルごとに 2 倍になります。
  5. ポジションが 1 つだけ残っている場合、この戦略は単純なテイクプロフィット ディスタンスを適用し、タッチで終了します。
  6. 複数のポジションがある場合、ストラテジーは極端なエントリを使用して加重平均を計算します。
    • 平均モード は、価格が加重目標に最小利益バッファーを加えた値に達すると、両極端を閉じます。
    • PartClose モード は、開始ボリュームに等しい最新の注文の一部をクローズし、最も古いオーダーを完全にクローズすることで、グリッドがエクスポージャーを減らして実行を継続できるようにします。
  7. すべての約定およびクローズされたポジションが追跡され、内部グリッドの状態がライブポートフォリオと同期されます。

注意事項

  • この戦略は成行注文に依存しているため、実際の約定品質とスリッページはブローカーの状況に依存します。
  • 機器の音量制限 (最小音量と音量ステップ) が、選択した開始音量と互換性があることを確認してください。
  • 他のグリッドやマーチンゲールのアプローチと同様、市場がポジションに反して強い傾向にある場合、リスクが急速に増大する可能性があります。慎重な資金管理を行ってください。
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// VR Smart Grid Lite: grid trading based on price levels with SMA filter.
/// </summary>
public class VrSmartGridLiteStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _gridPercent;
	private readonly StrategyParam<int> _smaPeriod;

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

	public decimal GridPercent
	{
		get => _gridPercent.Value;
		set => _gridPercent.Value = value;
	}

	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	public VrSmartGridLiteStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_gridPercent = Param(nameof(GridPercent), 3.0m)
			.SetGreaterThanZero()
			.SetDisplay("Grid %", "Grid step percentage", "Grid");

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA period for trend", "Indicators");
	}

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };

		decimal? lastTradePrice = null;

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

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (!lastTradePrice.HasValue)
				{
					lastTradePrice = close;
					return;
				}

				var step = lastTradePrice.Value * GridPercent / 100m;

				if (close <= lastTradePrice.Value - step)
				{
					BuyMarket();
					lastTradePrice = close;
				}
				else if (close >= lastTradePrice.Value + step)
				{
					SellMarket();
					lastTradePrice = close;
				}
			})
			.Start();

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