Открыть на GitHub

VR Smart Grid Lite Averaging

Обзор

VR Smart Grid Lite — это стратегия усреднения по сетке, переведённая с оригинального советника MetaTrader 5. Алгоритм открывает рыночные ордера по направлению последней завершённой свечи и наращивает мартингейл-лестницу при движении цены против позиции. Все расстояния, объёмы и логика выхода настраиваются и соответствуют поведению MQL-версии.

Торговая логика

  • После закрытия каждой свечи анализируется её направление.
    • Если свеча бычья, можно открыть новый buy-ордер, когда текущая цена минимум на Order Step (pips) ниже самой дешёвой покупки.
    • Если свеча медвежья, можно открыть новый sell-ордер, когда текущая цена минимум на Order Step (pips) выше самой дорогой продажи.
  • Первый ордер в каждом направлении использует Start Volume. Каждый следующий ордер удваивает объём самой дальней позиции, но ограничивается параметром Max Volume.
  • При наличии только одной позиции срабатывает фиксация по достижении расстояния Take Profit (pips).
  • При двух и более позициях используется выбранный режим закрытия Close Mode:
    • Average — закрывает самую высокую и самую низкую сделки, когда цена достигает их взвешенного среднего плюс Minimal Profit (pips).
    • PartialClose — полностью закрывает самую низкую сделку и уменьшает самую высокую на Start Volume, когда цена достигает целевого уровня.

Управление рисками

  • Объёмы автоматически подгоняются под MinVolume, MaxVolume и StepVolume инструмента, чтобы избежать отклонённых сделок.
  • Вызов StartProtection() активирует защиту счёта StockSharp перед началом торговли.

Параметры

Параметр Описание
Take Profit (pips) Дистанция тейк-профита для одиночной позиции.
Start Volume Начальный объём для первого ордера в каждом направлении.
Max Volume Максимальный объём ордера (0 отключает ограничение).
Close Mode Выбор между усреднённым выходом и частичным закрытием.
Order Step (pips) Минимальный шаг против позиции для открытия нового ордера.
Minimal Profit (pips) Запас прибыли, добавляемый к целевой цене усреднения.
Candle Type Тип свечей, используемых в расчётах.

Примечания

  • Стратегия работает только с рыночными ордерами; условные заявки оригинального советника моделируются проверкой условий на каждой свече.
  • Хранится отдельное состояние сделок, что позволяет повторить выборочное закрытие и частичное снятие объёма, как в MetaTrader.
  • Для идентичного поведения задайте тип свечей и тик-стоимость, соответствующие таймфрейму исходного MQL-скрипта.
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 Averaging: grid with averaging approach using Bollinger Bands.
/// Buys near lower band, sells near upper band.
/// </summary>
public class VrSmartGridLiteAveragingStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bbPeriod;

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

	public int BbPeriod
	{
		get => _bbPeriod.Value;
		set => _bbPeriod.Value = value;
	}

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

		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
	}

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

		var bb = new BollingerBands { Length = BbPeriod };

		decimal? prevClose = null;
		decimal? prevMid = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, (candle, bbVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var bbv = (BollingerBandsValue)bbVal;
				if (bbv.UpBand is not decimal upper || bbv.LowBand is not decimal lower)
					return;

				var close = candle.ClosePrice;
				var mid = (upper + lower) / 2m;

				if (prevClose.HasValue && prevMid.HasValue)
				{
					var crossBelow = prevClose.Value >= prevMid.Value && close < mid;
					var crossAbove = prevClose.Value <= prevMid.Value && close > mid;

					if (crossBelow && Position <= 0)
						BuyMarket();
					else if (crossAbove && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevMid = mid;
			})
			.Start();

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