VWAP Volume Strategie
Strategie, die VWAP und Volumen-Indikatoren kombiniert. Kauft/verkauft bei VWAP-Ausbrüchen, die durch überdurchschnittliches Volumen bestätigt werden.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 52%. Am besten geeignet für den Kryptomarkt.
Diese Strategie nutzt den VWAP zur Bewertung des fairen Wertes und erfordert eine Volumenbestätigung vor dem Trade. Die Idee ist, sich Bewegungen anzuschließen, die durch starke Marktteilnahme unterstützt werden.
Intraday-Trader, die sich auf Volumenkennzahlen konzentrieren, können diese Methode anwenden. Verluste werden durch einen ATR-basierten Stop begrenzt.
Details
- Einstiegskriterien:
- Long:
Close < VWAP && Volume > AvgVolume * VolumeThreshold - Short:
Close > VWAP && Volume > AvgVolume * VolumeThreshold
- Long:
- Long/Short: Beide
- Ausstiegskriterien:
- Preis kreuzt zurück durch den VWAP
- Stops: Prozentbasiert mit
StopLossPercent - Standardwerte:
VolumePeriod= 20VolumeThreshold= 1.5mStopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: VWAP, Volumen
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Mittelfristig
- 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>
/// Strategy combining VWAP with volume confirmation.
/// Buys on VWAP breakout with above-average volume, sells on breakdown.
/// </summary>
public class VwapVolumeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _volumePeriod;
private readonly StrategyParam<decimal> _volumeThreshold;
private readonly StrategyParam<int> _cooldownBars;
private readonly List<decimal> _volumes = new();
private readonly List<decimal> _typicalPriceVol = new();
private decimal _cumVol;
private decimal _cumTpv;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Period for volume moving average.
/// </summary>
public int VolumePeriod
{
get => _volumePeriod.Value;
set => _volumePeriod.Value = value;
}
/// <summary>
/// Volume threshold multiplier.
/// </summary>
public decimal VolumeThreshold
{
get => _volumeThreshold.Value;
set => _volumeThreshold.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize strategy.
/// </summary>
public VwapVolumeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_volumePeriod = Param(nameof(VolumePeriod), 20)
.SetRange(10, 50)
.SetDisplay("Volume MA Period", "Period for volume moving average", "Indicators");
_volumeThreshold = Param(nameof(VolumeThreshold), 1.5m)
.SetDisplay("Volume Threshold", "Multiplier for average volume", "Trading Levels");
_cooldownBars = Param(nameof(CooldownBars), 100)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_volumes.Clear();
_typicalPriceVol.Clear();
_cumVol = 0;
_cumTpv = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = VolumePeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var vol = candle.TotalVolume;
var typicalPrice = (high + low + close) / 3m;
_volumes.Add(vol);
_cumVol += vol;
_cumTpv += typicalPrice * vol;
var volPrd = VolumePeriod;
if (_volumes.Count < volPrd)
{
if (_cooldown > 0) _cooldown--;
return;
}
// Manual VWAP (cumulative)
var vwapValue = _cumVol > 0 ? _cumTpv / _cumVol : close;
// Manual volume average
decimal sumVol = 0;
var count = _volumes.Count;
for (int i = count - volPrd; i < count; i++)
sumVol += _volumes[i];
var avgVol = sumVol / volPrd;
var highVolume = vol > avgVol * VolumeThreshold;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Buy: price above VWAP + high volume
if (close > vwapValue && highVolume && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Sell: price below VWAP + high volume
else if (close < vwapValue && highVolume && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: price below VWAP
if (Position > 0 && close < vwapValue)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: price above VWAP
else if (Position < 0 && close > vwapValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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
from datatype_extensions import *
class vwap_volume_strategy(Strategy):
"""
Strategy combining VWAP with volume confirmation.
"""
def __init__(self):
super(vwap_volume_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._volume_period = self.Param("VolumePeriod", 20) \
.SetRange(10, 50) \
.SetDisplay("Volume MA Period", "Period for volume moving average", "Indicators")
self._volume_threshold = self.Param("VolumeThreshold", 1.5) \
.SetDisplay("Volume Threshold", "Multiplier for average volume", "Trading Levels")
self._cooldown_bars = self.Param("CooldownBars", 100) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General") \
.SetRange(5, 500)
self._volumes = []
self._cum_vol = 0.0
self._cum_tpv = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(vwap_volume_strategy, self).OnStarted2(time)
self._volumes = []
self._cum_vol = 0.0
self._cum_tpv = 0.0
self._cooldown = 0
ema = ExponentialMovingAverage()
ema.Length = self._volume_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
vol = float(candle.TotalVolume)
typical_price = (high + low + close) / 3.0
self._volumes.append(vol)
self._cum_vol += vol
self._cum_tpv += typical_price * vol
vol_prd = self._volume_period.Value
if len(self._volumes) < vol_prd:
if self._cooldown > 0:
self._cooldown -= 1
return
# Manual VWAP (cumulative)
vwap_value = self._cum_tpv / self._cum_vol if self._cum_vol > 0 else close
# Manual volume average
count = len(self._volumes)
sum_vol = sum(self._volumes[count - vol_prd:count])
avg_vol = sum_vol / vol_prd
high_volume = vol > avg_vol * self._volume_threshold.Value
if self._cooldown > 0:
self._cooldown -= 1
return
cd = self._cooldown_bars.Value
# Buy: price above VWAP + high volume
if close > vwap_value and high_volume and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
elif close < vwap_value and high_volume and self.Position == 0:
self.SellMarket()
self._cooldown = cd
# Exit long: price below VWAP
if self.Position > 0 and close < vwap_value:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > vwap_value:
self.BuyMarket()
self._cooldown = cd
def OnReseted(self):
super(vwap_volume_strategy, self).OnReseted()
self._volumes = []
self._cum_vol = 0.0
self._cum_tpv = 0.0
self._cooldown = 0
def CreateClone(self):
return vwap_volume_strategy()