Esta estrategia es una traducción simplificada del asesor experto MQL5 original "DVD Level". Emplea el Range Action Verification Index (RAVI) para determinar la dirección del mercado. RAVI se calcula utilizando medias móviles exponenciales de 2 y 24 períodos en velas de 1 hora.
Parámetros
Volume – volumen de la orden utilizado para las operaciones.
Lógica
Suscribirse a velas de 1 hora y calcular EMA(2) y EMA(24).
Calcular RAVI = (EMA2 - EMA24) / EMA24 * 100.
Si RAVI cruza por debajo de cero, la estrategia compra si está plana o corta.
Si RAVI cruza por encima de cero, la estrategia vende si está plana o larga.
La protección de posición integrada se activa a través de StartProtection().
El enfoque captura posibles reversiones cuando el momentum a corto plazo diverge de la tendencia a largo plazo.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RAVI based level strategy. Opens long when the RAVI crosses below zero and short when above.
/// </summary>
public class DvdLevelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly ExponentialMovingAverage _emaFast = new() { Length = 2 };
private readonly ExponentialMovingAverage _emaSlow = new() { Length = 24 };
private decimal _prevRavi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DvdLevelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRavi = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRavi = 0m;
_hasPrev = false;
var sub = SubscribeCandles(CandleType);
sub.Bind(_emaFast, _emaSlow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, sub);
DrawIndicator(area, _emaFast);
DrawIndicator(area, _emaSlow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaFast, decimal emaSlow)
{
if (candle.State != CandleStates.Finished || emaSlow == 0)
return;
var ravi = (emaFast - emaSlow) / emaSlow * 100m;
if (!_hasPrev)
{
_prevRavi = ravi;
_hasPrev = true;
return;
}
var crossAbove = _prevRavi <= 0 && ravi > 0;
var crossBelow = _prevRavi >= 0 && ravi < 0;
if (crossBelow && Position <= 0)
BuyMarket();
else if (crossAbove && Position >= 0)
SellMarket();
_prevRavi = ravi;
}
}
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 as EMA
from StockSharp.Algo.Strategies import Strategy
class dvd_level_strategy(Strategy):
def __init__(self):
super(dvd_level_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._prev_ravi = 0.0
self._has_prev = False
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnStarted2(self, time):
super(dvd_level_strategy, self).OnStarted2(time)
self._prev_ravi = 0.0
self._has_prev = False
self._ema_fast = EMA()
self._ema_fast.Length = 2
self._ema_slow = EMA()
self._ema_slow.Length = 24
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self._ema_fast, self._ema_slow, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_fast, ema_slow):
if candle.State != CandleStates.Finished:
return
ef = float(ema_fast)
es = float(ema_slow)
if es == 0:
return
ravi = (ef - es) / es * 100.0
if not self._has_prev:
self._prev_ravi = ravi
self._has_prev = True
return
cross_above = self._prev_ravi <= 0 and ravi > 0
cross_below = self._prev_ravi >= 0 and ravi < 0
if cross_below and self.Position <= 0:
self.BuyMarket()
elif cross_above and self.Position >= 0:
self.SellMarket()
self._prev_ravi = ravi
def OnReseted(self):
super(dvd_level_strategy, self).OnReseted()
self._prev_ravi = 0.0
self._has_prev = False
def CreateClone(self):
return dvd_level_strategy()