VWAP RSI Strategie
VWAP RSI verwendet den volumengewichteten Durchschnittspreis zur Beurteilung des fairen Wertes während der Sitzung, während der RSI Momentum-Extreme anzeigt. Trades werden eingegangen, wenn sich der Kurs vom VWAP entfernt und der RSI überkaufte oder überverkaufte Niveaus erreicht.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 157%. Die Strategie funktioniert am besten auf dem Kryptomarkt.
Die Erwartung ist, dass der Kurs zum VWAP zurückkehrt, sobald das Momentum nachlässt.
Ein prozentualer Stop schützt vor Trends, die den Kurs weiter vom VWAP entfernen.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: VWAP, RSI
- Stops: Ja
- Komplexität: Mittel
- 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>
/// Strategy that uses VWAP as a reference point and RSI for oversold/overbought conditions.
/// Enters when price is below VWAP and RSI oversold (longs) or above VWAP and RSI overbought (shorts).
/// </summary>
public class VwapRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _cooldownBars;
private decimal _vwapValue;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public VwapRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetRange(7, 21)
.SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");
_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();
_vwapValue = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var vwap = new VolumeWeightedMovingAverage();
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
// Bind VWAP to capture value (candle-input indicator)
subscription.BindEx(vwap, OnVwap);
// Bind RSI for main logic
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, vwap);
DrawOwnTrades(area);
var rsiArea = CreateChartArea();
if (rsiArea != null)
DrawIndicator(rsiArea, rsi);
}
}
private void OnVwap(ICandleMessage candle, IIndicatorValue vwapValue)
{
if (vwapValue.IsFormed)
_vwapValue = vwapValue.ToDecimal();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_vwapValue == 0)
return;
var close = candle.ClosePrice;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Long: price below VWAP + RSI oversold
if (close < _vwapValue && rsiValue < RsiOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Short: price above VWAP + RSI overbought
else if (close > _vwapValue && rsiValue > RsiOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: price above VWAP
if (Position > 0 && close > _vwapValue)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: price below 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 VolumeWeightedMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class vwap_rsi_strategy(Strategy):
"""
VWAP + RSI strategy.
Enters when price is below VWAP and RSI oversold (longs)
or above VWAP and RSI overbought (shorts).
"""
def __init__(self):
super(vwap_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 30.0).SetDisplay("RSI Oversold", "RSI oversold level", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70.0).SetDisplay("RSI Overbought", "RSI overbought level", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 100).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._vwap_value = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vwap_rsi_strategy, self).OnReseted()
self._vwap_value = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(vwap_rsi_strategy, self).OnStarted2(time)
self._vwap_value = 0.0
self._cooldown = 0
vwap = VolumeWeightedMovingAverage()
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
# Bind VWAP with BindEx to capture value
subscription.BindEx(vwap, self._on_vwap)
# Bind RSI for main logic
subscription.Bind(rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, vwap)
self.DrawOwnTrades(area)
rsi_area = self.CreateChartArea()
if rsi_area is not None:
self.DrawIndicator(rsi_area, rsi)
def _on_vwap(self, candle, vwap_iv):
if vwap_iv.IsFormed:
self._vwap_value = float(vwap_iv.Value)
def _process_candle(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
if self._vwap_value == 0:
return
close = float(candle.ClosePrice)
rsi = float(rsi_val)
vwap = self._vwap_value
cd = self._cooldown_bars.Value
oversold = float(self._rsi_oversold.Value)
overbought = float(self._rsi_overbought.Value)
if self._cooldown > 0:
self._cooldown -= 1
return
# Long: price below VWAP + RSI oversold
if close < vwap and rsi < oversold and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
# Short: price above VWAP + RSI overbought
elif close > vwap and rsi > overbought and self.Position == 0:
self.SellMarket()
self._cooldown = cd
# Exit long: price above VWAP
if self.Position > 0 and close > vwap:
self.SellMarket()
self._cooldown = cd
# Exit short: price below VWAP
elif self.Position < 0 and close < vwap:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return vwap_rsi_strategy()