Ver en GitHub

VR Setka P2 Strategy

This strategy is a grid-based approach translated from the MetaTrader 4 expert VR---SETKAp2. It trades when the daily close deviates from the day's high or low by a given percentage. The strategy opens long positions after a significant drop from the daily high and short positions after a significant rise from the daily low. Once in a position it exits at a fixed take-profit distance. Volume can optionally increase using a simple martingale scheme.

Parameters

  • TakeProfit – distance to the profit target in price steps.
  • Lot – base volume for every trade.
  • Percent – percentage threshold calculated from the daily range.
  • UseMartingale – enable volume increase when adding to a losing position.
  • Slippage – allowed price slippage for orders.
  • Correlation – offset applied when calculating grid levels.
  • Candle Type – timeframe used for calculations (daily by default).

Logic

  1. Subscribe to daily candles.
  2. For each finished candle, calculate percentage deviations from the daily high and low.
  3. Enter long or short depending on the deviation and the previous candle direction.
  4. Close the position when the take-profit level is reached.

This implementation demonstrates how a classic MetaTrader grid expert can be ported to the StockSharp high-level API.

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;
	}
}