Ver en GitHub

Estrategia de Cuadrícula VR Setka

Esta estrategia es una implementación en StockSharp del sistema de cuadrícula "VR---SETKAa3hM" de MetaTrader. Abre una secuencia de órdenes de compra o venta basadas en la desviación porcentual del rango diario y opcionalmente incrementa el volumen usando un multiplicador de martingala. El precio de entrada promedio de todas las órdenes abiertas se rastrea para colocar un objetivo unificado de take-profit.

Parámetros

  • Distance: Distancia en puntos entre los niveles de la cuadrícula.
  • TakeProfit: Objetivo de beneficio en puntos para la orden inicial.
  • Correction: Beneficio adicional en puntos añadido al precio promedio cuando hay más de una orden abierta.
  • SignalPercent: Umbral porcentual usado para detectar desviación del rango diario.
  • UseMartingale: Multiplicar el volumen por el número de órdenes abiertas.
  • CandleType: Marco temporal de velas usado para los cálculos de señal.

Lógica

  1. Cuando aparece una vela finalizada, se calcula el cierre actual en relación con el máximo y mínimo del día.
  2. Si la vela anterior era alcista y el cierre está suficientemente por debajo del máximo del día, se inicia o continúa una cuadrícula de compra.
  3. Si la vela anterior era bajista y el cierre está suficientemente por encima del mínimo del día, se inicia o continúa una cuadrícula de venta.
  4. Se colocan órdenes adicionales cada vez que el precio se mueve en contra de la posición en Distance puntos.
  5. Una vez que el precio regresa al precio de entrada promedio más Correction para compras o menos Correction para ventas, todas las posiciones se cierran con una orden a mercado.
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;
	}
}