Start
/
Strategie-Beispiele
Auf GitHub ansehen
Strategie VWAP Williams R
Die VWAP Williams %R-Strategie konzentriert sich auf die Intraday-Reversion rund um den volumengewichteten Durchschnittspreis. Sie beobachtet, wenn der Preis vom VWAP abdriftet, während der Williams %R-Oszillator überverkaufte oder überkaufte Bereiche erreicht. Die Annahme ist, dass extreme Werte nahe dem VWAP oft zu einem Rückschlag zum Mittelwert führen.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 40%. Die Strategie funktioniert am besten auf dem Kryptomarkt.
Wenn der Oszillator unter -80 fällt und der Preis unter dem VWAP handelt, impliziert das Setup, dass der Verkaufsdruck nachlässt und eine Erholung folgen kann. Umgekehrt warnt ein Wert über -20, während der Preis über dem VWAP liegt, dass Käufer erschöpft sind und ein Rückgang wahrscheinlich ist. Die Strategie eröffnet Trades in Richtung einer potenziellen Rückkehr zum VWAP und wartet darauf, dass diese Bewegung abgeschlossen wird.
Dieser Ansatz eignet sich für aktive Intraday-Trader, die häufige Mean-Reversion-Möglichkeiten bevorzugen. Ein kleiner Stop‑Loss relativ zum VWAP hält das Risiko begrenzt und lässt gleichzeitig genug Raum für Preisschwankungen vor der Umkehr.
Details
Einstiegskriterien :
Long : Price < VWAP && Williams %R < -80 (überverkauft unterhalb VWAP)
Short : Price > VWAP && Williams %R > -20 (überkauft oberhalb VWAP)
Long/Short : Beide Seiten.
Ausstiegskriterien :
Long : Long-Position schließen, wenn der Preis über VWAP steigt
Short : Short-Position schließen, wenn der Preis unter VWAP fällt
Stops : Ja.
Standardwerte :
WilliamsRPeriod = 14
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filter :
Kategorie: Gemischt
Richtung: Beide
Indikatoren: VWAP Williams R
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on VWAP and Williams %R indicators
/// </summary>
public class VwapWilliamsRStrategy : Strategy
{
private readonly StrategyParam<int> _williamsRPeriod;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
// Store previous values
private decimal _previousWilliamsR;
private int _cooldown;
private DateTime _vwapDate;
private decimal _vwapCumPv;
private decimal _vwapCumVol;
/// <summary>
/// Williams %R period
/// </summary>
public int WilliamsRPeriod
{
get => _williamsRPeriod.Value;
set => _williamsRPeriod.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop-loss percentage
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type for strategy
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor
/// </summary>
public VwapWilliamsRStrategy()
{
_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
.SetRange(5, 50)
.SetDisplay("Williams %R Period", "Period for Williams %R indicator", "Indicators")
;
_cooldownBars = Param(nameof(CooldownBars), 60)
.SetRange(1, 200)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetRange(0.5m, 5m)
.SetDisplay("Stop-Loss %", "Stop-loss percentage from entry price", "Risk Management")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousWilliamsR = default;
_cooldown = 0;
_vwapDate = default;
_vwapCumPv = 0m;
_vwapCumVol = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize indicator
var williamsR = new WilliamsR { Length = WilliamsRPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(williamsR, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, williamsR);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal williamsRValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
var date = candle.ServerTime.Date;
if (_vwapDate != date)
{
_vwapDate = date;
_vwapCumPv = 0m;
_vwapCumVol = 0m;
}
_vwapCumPv += candle.ClosePrice * candle.TotalVolume;
_vwapCumVol += candle.TotalVolume;
if (_vwapCumVol <= 0m)
return;
var vwapValue = _vwapCumPv / _vwapCumVol;
// Store previous value to detect changes
var previousWilliamsR = _previousWilliamsR;
_previousWilliamsR = williamsRValue;
var price = candle.ClosePrice;
var crossedIntoOversold = previousWilliamsR > -80m && williamsRValue <= -80m;
var crossedIntoOverbought = previousWilliamsR < -20m && williamsRValue >= -20m;
if (_cooldown > 0)
_cooldown--;
if (_cooldown == 0 && price < vwapValue * 0.999m && crossedIntoOversold && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = CooldownBars;
}
else if (_cooldown == 0 && price > vwapValue * 1.001m && crossedIntoOverbought && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import WilliamsR
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class vwap_williams_r_strategy(Strategy):
"""
Strategy based on VWAP and Williams %R indicators.
Long when price below VWAP and Williams %R crosses into oversold.
Short when price above VWAP and Williams %R crosses into overbought.
"""
def __init__(self):
super(vwap_williams_r_strategy, self).__init__()
self._williams_r_period = self.Param("WilliamsRPeriod", 14) \
.SetRange(5, 50) \
.SetDisplay("Williams %R Period", "Period for Williams %R indicator", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 60) \
.SetRange(1, 200) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetRange(0.5, 5.0) \
.SetDisplay("Stop-Loss %", "Stop-loss percentage from entry price", "Risk Management")
self._candle_type = self.Param("CandleType", tf(30)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._previous_williams_r = 0.0
self._cooldown = 0
self._vwap_date = None
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
@property
def CandleType(self):
return self._candle_type.Value
def OnReseted(self):
super(vwap_williams_r_strategy, self).OnReseted()
self._previous_williams_r = 0.0
self._cooldown = 0
self._vwap_date = None
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
def OnStarted2(self, time):
super(vwap_williams_r_strategy, self).OnStarted2(time)
self._previous_williams_r = 0.0
self._cooldown = 0
self._vwap_date = None
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
williams_r = WilliamsR()
williams_r.Length = self._williams_r_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(williams_r, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, williams_r)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, williams_r_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
date = candle.ServerTime.Date
if self._vwap_date is None or self._vwap_date != date:
self._vwap_date = date
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
self._vwap_cum_pv += float(candle.ClosePrice) * float(candle.TotalVolume)
self._vwap_cum_vol += float(candle.TotalVolume)
if self._vwap_cum_vol <= 0:
return
vwap_value = self._vwap_cum_pv / self._vwap_cum_vol
previous_wr = self._previous_williams_r
self._previous_williams_r = float(williams_r_value)
wr = float(williams_r_value)
price = float(candle.ClosePrice)
crossed_into_oversold = previous_wr > -80 and wr <= -80
crossed_into_overbought = previous_wr < -20 and wr >= -20
if self._cooldown > 0:
self._cooldown -= 1
cooldown_val = int(self._cooldown_bars.Value)
if self._cooldown == 0 and price < vwap_value * 0.999 and crossed_into_oversold and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = cooldown_val
elif self._cooldown == 0 and price > vwap_value * 1.001 and crossed_into_overbought and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = cooldown_val
def CreateClone(self):
return vwap_williams_r_strategy()