Открыть на GitHub

Сетка VR Setka Grid

Стратегия реализует в StockSharp систему сеточного трейдинга "VR---SETKAa3hM" из MetaTrader 4. Ордера на покупку или продажу открываются при отклонении цены от дневного диапазона на заданный процент. При включённом мартингейле объём каждой новой позиции увеличивается. Средняя цена входа по всем ордерам используется для выставления общего тейк-профита.

Параметры

  • Distance: расстояние между уровнями сетки в пунктах.
  • TakeProfit: тейк-профит для первого ордера в пунктах.
  • Correction: добавочный профит в пунктах, прибавляемый к средней цене при нескольких ордерах.
  • SignalPercent: процент отклонения от дневного диапазона для формирования сигнала.
  • UseMartingale: включение увеличения объёма по мартингейлу.
  • CandleType: таймфрейм свечей для расчётов.

Логика

  1. По завершённой свече рассчитывается положение закрытия относительно дневного максимума и минимума.
  2. Если предыдущая свеча бычья и цена ниже дневного максимума на указанный процент, открывается или добавляется покупка.
  3. Если предыдущая свеча медвежья и цена выше дневного минимума на указанный процент, открывается или добавляется продажа.
  4. Дополнительные ордера ставятся каждый раз, когда цена идёт против позиции на Distance пунктов.
  5. Когда цена возвращается к средней цене плюс Correction для покупок или минус Correction для продаж, все ордера закрываются рыночным ордером.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// EMA trend + candle direction strategy (converted from grid).
/// </summary>
public class VrSetkaGridStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevClose;
	private bool _hasPrev;

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

	public VrSetkaGridStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Base candle series", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = 0;
		_prevClose = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		SubscribeCandles(CandleType)
			.Bind(ema, ProcessCandle)
			.Start();
	}

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

		var close = candle.ClosePrice;

		if (!_hasPrev)
		{
			_prevEma = emaValue;
			_prevClose = close;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevClose <= _prevEma && close > emaValue;
		var crossDown = _prevClose >= _prevEma && close < emaValue;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevEma = emaValue;
		_prevClose = close;
	}
}