Ver en GitHub

Estrategia VR Setka P2

Esta estrategia es un enfoque de cuadrícula traducido del experto MetaTrader 4 VR---SETKAp2. Opera cuando el cierre diario se desvía del máximo o mínimo del día en un porcentaje determinado. La estrategia abre posiciones largas tras una caída significativa desde el máximo diario y posiciones cortas tras un alza significativa desde el mínimo diario. Una vez en posición, sale con una distancia de take profit fija. El volumen puede aumentar opcionalmente mediante un esquema simple de Martingale.

Parámetros

  • TakeProfit – distancia al objetivo de ganancia en pasos de precio.
  • Lot – volumen base para cada operación.
  • Percent – umbral porcentual calculado a partir del rango diario.
  • UseMartingale – activa el aumento de volumen al añadir a una posición perdedora.
  • Slippage – deslizamiento de precio permitido para las órdenes.
  • Correlation – desplazamiento aplicado al calcular los niveles de cuadrícula.
  • Candle Type – marco temporal usado para los cálculos (diario por defecto).

Lógica

  1. Suscribirse a velas diarias.
  2. Para cada vela finalizada, calcular las desviaciones porcentuales desde el máximo y mínimo diarios.
  3. Entrar en largo o corto según la desviación y la dirección de la vela anterior.
  4. Cerrar la posición cuando se alcanza el nivel de take profit.

Esta implementación demuestra cómo se puede portar un experto de cuadrícula clásico de MetaTrader a la API de alto nivel de StockSharp.

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>
/// Grid based strategy using candle direction and EMA trend.
/// </summary>
public class VrSetkaP2Strategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevOpen;
	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 VrSetkaP2Strategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for analysis", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOpen = 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)
		{
			_prevOpen = candle.OpenPrice;
			_prevClose = close;
			_hasPrev = true;
			return;
		}

		// Previous candle bullish + close above EMA => buy
		if (_prevClose > _prevOpen && close > emaValue && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Previous candle bearish + close below EMA => sell
		else if (_prevClose < _prevOpen && close < emaValue && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevOpen = candle.OpenPrice;
		_prevClose = close;
	}
}