Estrategia Lux Clara EMA + VWAP
La estrategia Lux Clara EMA + VWAP opera el cruce de una EMA rápida y una lenta, filtrado por VWAP y una ventana de tiempo. Se abre una posición larga cuando la EMA rápida cruza por encima de la EMA lenta mientras la EMA lenta está por encima del VWAP durante la sesión. Se abre una posición corta en condiciones opuestas. Las posiciones se cierran cuando las EMA cruzan en dirección contraria.
Detalles
- Criterios de entrada:
- EMA rápida cruza por encima de la EMA lenta, EMA lenta por encima del VWAP y hora actual dentro de la sesión.
- Corto: EMA rápida cruza por debajo de la EMA lenta, EMA lenta por debajo del VWAP y hora actual dentro de la sesión.
- Largo/Corto: Ambos.
- Criterios de salida:
- Cruce opuesto de EMA.
- Stops: Ninguno.
- Valores predeterminados:
FastEmaLength= 8SlowEmaLength= 50StartTime= 07:30EndTime= 14:30CandleType= 5 minutos
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Largo y Corto
- Indicadores: EMA, VWAP
- Stops: Ninguno
- Complejidad: Bajo
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Bajo
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>
/// Lux Clara EMA + VWAP strategy.
/// Buys on fast EMA crossing above slow EMA when above VWAP, sells on opposite.
/// </summary>
public class LuxClaraEmaVwapStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private VolumeWeightedMovingAverage _vwap;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isInitialized;
private int _cooldown;
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LuxClaraEmaVwapStrategy()
{
_fastEmaLength = Param(nameof(FastEmaLength), 8)
.SetDisplay("Fast EMA Length", "Length of fast EMA", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 21)
.SetDisplay("Slow EMA Length", "Length of slow EMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of data for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_isInitialized = false;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
_slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
_vwap = new VolumeWeightedMovingAverage { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastEma, _slowEma, _vwap, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawIndicator(area, _vwap);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal vwap)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastEma.IsFormed || !_slowEma.IsFormed)
return;
if (!_isInitialized)
{
_prevFast = fast;
_prevSlow = slow;
_isInitialized = true;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast;
_prevSlow = slow;
return;
}
var fastCrossAbove = _prevFast <= _prevSlow && fast > slow;
var fastCrossBelow = _prevFast >= _prevSlow && fast < slow;
// Use VWAP as additional confirmation when formed
var aboveVwap = !_vwap.IsFormed || candle.ClosePrice > vwap;
var belowVwap = !_vwap.IsFormed || candle.ClosePrice < vwap;
if (Position <= 0 && fastCrossAbove && aboveVwap)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_cooldown = 12;
}
else if (Position >= 0 && fastCrossBelow && belowVwap)
{
if (Position > 0)
SellMarket();
SellMarket();
_cooldown = 12;
}
// Exit without VWAP condition
else if (Position > 0 && fastCrossBelow)
{
SellMarket();
_cooldown = 12;
}
else if (Position < 0 && fastCrossAbove)
{
BuyMarket();
_cooldown = 12;
}
_prevFast = fast;
_prevSlow = slow;
}
}
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, VolumeWeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class lux_clara_ema_vwap_strategy(Strategy):
"""
Lux Clara EMA + VWAP strategy.
Buys on fast EMA crossing above slow EMA when above VWAP.
"""
def __init__(self):
super(lux_clara_ema_vwap_strategy, self).__init__()
self._fast_length = self.Param("FastEmaLength", 8) \
.SetDisplay("Fast EMA", "Fast EMA length", "Indicators")
self._slow_length = self.Param("SlowEmaLength", 21) \
.SetDisplay("Slow EMA", "Slow EMA length", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(lux_clara_ema_vwap_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown = 0
def OnStarted2(self, time):
super(lux_clara_ema_vwap_strategy, self).OnStarted2(time)
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self._fast_length.Value
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self._slow_length.Value
self._vwap = VolumeWeightedMovingAverage()
self._vwap.Length = 20
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ema, self._slow_ema, self._vwap, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ema)
self.DrawIndicator(area, self._slow_ema)
self.DrawIndicator(area, self._vwap)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val, vwap_val):
if candle.State != CandleStates.Finished:
return
if not self._fast_ema.IsFormed or not self._slow_ema.IsFormed:
return
f = float(fast_val)
s = float(slow_val)
v = float(vwap_val)
close = float(candle.ClosePrice)
if not self._initialized:
self._prev_fast = f
self._prev_slow = s
self._initialized = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = f
self._prev_slow = s
return
cross_above = self._prev_fast <= self._prev_slow and f > s
cross_below = self._prev_fast >= self._prev_slow and f < s
above_vwap = not self._vwap.IsFormed or close > v
below_vwap = not self._vwap.IsFormed or close < v
if self.Position <= 0 and cross_above and above_vwap:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown = 12
elif self.Position >= 0 and cross_below and below_vwap:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown = 12
elif self.Position > 0 and cross_below:
self.SellMarket()
self._cooldown = 12
elif self.Position < 0 and cross_above:
self.BuyMarket()
self._cooldown = 12
self._prev_fast = f
self._prev_slow = s
def CreateClone(self):
return lux_clara_ema_vwap_strategy()