Strategie VWMA Cross
Der volumengewichtete gleitende Durchschnitt (VWMA) betont Preisniveaus mit höherem Handelsvolumen. Diese Strategie handelt Kreuzungen zwischen dem Preis und dem VWMA.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 184%. Am besten funktioniert es im Kryptomarkt.
Ein Schlusskurs über dem VWMA nach einer Phase darunter erzeugt ein Long-Signal, während ein Rückfall unter den VWMA einen Short-Trade auslöst. Positionen enden, wenn der Preis wieder in die entgegengesetzte Richtung kreuzt.
Die Verwendung eines volumengewichteten Durchschnitts reduziert das Rauschen aus Perioden mit niedrigem Volumen.
Details
- Einstiegskriterien: Preis kreuzt VWMA von unten oder oben.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Umgekehrtes Kreuz oder Stop.
- Stops: Ja.
- Standardwerte:
VWMAPeriod= 14CandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Trend
- Richtung: Beide
- Indikatoren: VWMA
- Stops: Ja
- Komplexität: Grundlegend
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Volume Weighted Moving Average (VWMA) Strategy.
/// Long entry: Price crosses above VWMA.
/// Short entry: Price crosses below VWMA.
/// </summary>
public class VWMAStrategy : Strategy
{
private readonly StrategyParam<int> _vwmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _previousClosePrice;
private decimal _previousVWMA;
private int _cooldown;
/// <summary>
/// VWMA Period.
/// </summary>
public int VWMAPeriod
{
get => _vwmaPeriod.Value;
set => _vwmaPeriod.Value = value;
}
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize <see cref="VWMAStrategy"/>.
/// </summary>
public VWMAStrategy()
{
_vwmaPeriod = Param(nameof(VWMAPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("VWMA Period", "Period for Volume Weighted Moving Average", "Indicators")
.SetOptimize(5, 30, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousClosePrice = default;
_previousVWMA = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousClosePrice = 0;
_previousVWMA = 0;
_cooldown = 0;
var vwma = new VolumeWeightedMovingAverage { Length = VWMAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(vwma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, vwma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal vwmaPrice)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_previousClosePrice == 0)
{
_previousClosePrice = candle.ClosePrice;
_previousVWMA = vwmaPrice;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_previousClosePrice = candle.ClosePrice;
_previousVWMA = vwmaPrice;
return;
}
var crossoverUp = _previousClosePrice <= _previousVWMA && candle.ClosePrice > vwmaPrice;
var crossoverDown = _previousClosePrice >= _previousVWMA && candle.ClosePrice < vwmaPrice;
if (Position == 0 && crossoverUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && crossoverDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && crossoverDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && crossoverUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
_previousClosePrice = candle.ClosePrice;
_previousVWMA = vwmaPrice;
}
}
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 VolumeWeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class vwma_strategy(Strategy):
"""
Volume Weighted Moving Average (VWMA) Strategy.
Long entry: Price crosses above VWMA.
Short entry: Price crosses below VWMA.
"""
def __init__(self):
super(vwma_strategy, self).__init__()
self._vwma_period = self.Param("VWMAPeriod", 14).SetDisplay("VWMA Period", "Period for Volume Weighted Moving Average", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._previous_close = 0.0
self._previous_vwma = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vwma_strategy, self).OnReseted()
self._previous_close = 0.0
self._previous_vwma = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(vwma_strategy, self).OnStarted2(time)
self._previous_close = 0.0
self._previous_vwma = 0.0
self._cooldown = 0
vwma = VolumeWeightedMovingAverage()
vwma.Length = self._vwma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(vwma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, vwma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, vwma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
vp = float(vwma_val)
if self._previous_close == 0:
self._previous_close = close
self._previous_vwma = vp
return
if self._cooldown > 0:
self._cooldown -= 1
self._previous_close = close
self._previous_vwma = vp
return
cd = self._cooldown_bars.Value
crossover_up = self._previous_close <= self._previous_vwma and close > vp
crossover_down = self._previous_close >= self._previous_vwma and close < vp
if self.Position == 0 and crossover_up:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and crossover_down:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and crossover_down:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and crossover_up:
self.BuyMarket()
self._cooldown = cd
self._previous_close = close
self._previous_vwma = vp
def CreateClone(self):
return vwma_strategy()