VWAP Breakout busca que el precio cruce el Precio Promedio Ponderado por Volumen desde el lado opuesto. Una ruptura por encima del VWAP señala presión alcista, mientras que una caída por debajo del VWAP señala sentimiento bajista.
Las pruebas indican un retorno anual promedio de aproximadamente 181%. Funciona mejor en el mercado de criptomonedas.
La estrategia espera un cierre al otro lado del VWAP y luego opera en esa dirección. Las salidas ocurren cuando el precio revierte de nuevo a través del VWAP.
Dado que el VWAP representa el precio promedio de transacción, sus rupturas suelen generar movimientos de momentum.
Detalles
Criterios de entrada: El precio cierra al lado opuesto del VWAP.
Largo/Corto: Ambas direcciones.
Criterios de salida: El precio cruza de vuelta a través del VWAP o stop.
Stops: Sí.
Valores predeterminados:
CandleType = TimeSpan.FromMinutes(5)
Filtros:
Categoría: Ruptura
Dirección: Ambos
Indicadores: VWAP
Stops: Sí
Complejidad: Básico
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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>
/// VWAP Breakout strategy.
/// Enters long when price breaks above VWAP, short when below.
/// </summary>
public class VWAPBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _previousClosePrice;
private decimal _previousVWAP;
private int _cooldown;
/// <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 the VWAP Breakout strategy.
/// </summary>
public VWAPBreakoutStrategy()
{
_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;
_previousVWAP = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousClosePrice = 0;
_previousVWAP = 0;
_cooldown = 0;
var vwap = new VolumeWeightedMovingAverage();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(vwap, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, vwap);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal vwapPrice)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_previousClosePrice == 0)
{
_previousClosePrice = candle.ClosePrice;
_previousVWAP = vwapPrice;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_previousClosePrice = candle.ClosePrice;
_previousVWAP = vwapPrice;
return;
}
var breakoutUp = _previousClosePrice <= _previousVWAP && candle.ClosePrice > vwapPrice;
var breakoutDown = _previousClosePrice >= _previousVWAP && candle.ClosePrice < vwapPrice;
if (Position == 0 && breakoutUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && breakoutDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < vwapPrice)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > vwapPrice)
{
BuyMarket();
_cooldown = CooldownBars;
}
_previousClosePrice = candle.ClosePrice;
_previousVWAP = vwapPrice;
}
}
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 vwap_breakout_strategy(Strategy):
"""
VWAP Breakout strategy.
Enters long when price breaks above VWAP, short when below.
"""
def __init__(self):
super(vwap_breakout_strategy, self).__init__()
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_vwap = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vwap_breakout_strategy, self).OnReseted()
self._previous_close = 0.0
self._previous_vwap = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(vwap_breakout_strategy, self).OnStarted2(time)
self._previous_close = 0.0
self._previous_vwap = 0.0
self._cooldown = 0
vwap = VolumeWeightedMovingAverage()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(vwap, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, vwap)
self.DrawOwnTrades(area)
def _process_candle(self, candle, vwap_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
vp = float(vwap_val)
if self._previous_close == 0:
self._previous_close = close
self._previous_vwap = vp
return
if self._cooldown > 0:
self._cooldown -= 1
self._previous_close = close
self._previous_vwap = vp
return
cd = self._cooldown_bars.Value
breakout_up = self._previous_close <= self._previous_vwap and close > vp
breakout_down = self._previous_close >= self._previous_vwap and close < vp
if self.Position == 0 and breakout_up:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and breakout_down:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and close < vp:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > vp:
self.BuyMarket()
self._cooldown = cd
self._previous_close = close
self._previous_vwap = vp
def CreateClone(self):
return vwap_breakout_strategy()