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
Suscribirse a velas diarias.
Para cada vela finalizada, calcular las desviaciones porcentuales desde el máximo y mínimo diarios.
Entrar en largo o corto según la desviación y la dirección de la vela anterior.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class vr_setka_p2_strategy(Strategy):
def __init__(self):
super(vr_setka_p2_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA trend period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vr_setka_p2_strategy, self).OnReseted()
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(vr_setka_p2_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if not self._has_prev:
self._prev_open = candle.OpenPrice
self._prev_close = close
self._has_prev = True
return
# Previous candle bullish + close above EMA => buy
if self._prev_close > self._prev_open and close > ema_value and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Previous candle bearish + close below EMA => sell
elif self._prev_close < self._prev_open and close < ema_value and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_open = candle.OpenPrice
self._prev_close = close
def CreateClone(self):
return vr_setka_p2_strategy()