Lux Clara EMA + VWAP-Strategie
Die Lux Clara EMA + VWAP-Strategie handelt den Crossover einer schnellen und einer langsamen EMA, gefiltert durch VWAP und ein Zeitfenster. Eine Long-Position wird eröffnet, wenn die schnelle EMA die langsame EMA von unten kreuzt, während die langsame EMA über dem VWAP liegt und die aktuelle Zeit innerhalb der Sitzung liegt. Eine Short-Position wird unter umgekehrten Bedingungen eröffnet. Positionen werden geschlossen, wenn die EMAs in die entgegengesetzte Richtung kreuzen.
Details
- Einstiegskriterien:
- Schnelle EMA kreuzt die langsame EMA von unten, langsame EMA über VWAP und aktuelle Zeit innerhalb der Sitzung.
- Short: Schnelle EMA kreuzt die langsame EMA von oben, langsame EMA unter VWAP und aktuelle Zeit innerhalb der Sitzung.
- Long/Short: Beide.
- Ausstiegskriterien:
- Entgegengesetzter EMA-Crossover.
- Stops: Keine.
- Standardwerte:
FastEmaLength= 8SlowEmaLength= 50StartTime= 07:30EndTime= 14:30CandleType= 5 Minuten
- Filter:
- Kategorie: Trendfolge
- Richtung: Long und Short
- Indikatoren: EMA, VWAP
- Stops: Keine
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Niedrig
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()