Strategie Vwap Stochastic
Strategie, die VWAP- und Stochastic-Indikatoren kombiniert. Kauft, wenn der Preis unter dem VWAP liegt und Stochastic überverkauft ist. Verkauft, wenn der Preis über dem VWAP liegt und Stochastic überkauft ist.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 187%. Sie funktioniert am besten im Aktienmarkt.
VWAP markiert das durchschnittliche Handelsniveau und Stochastic zeigt überkaufte oder überverkaufte Bedingungen. Longs werden unter dem VWAP mit einem steigenden Oszillator ausgelöst, Shorts über dem VWAP mit einem fallenden.
Intraday-Trader, die intraday Wertniveaus beobachten, können von diesem Stil profitieren. Stops werden mit einem ATR-Vielfachen platziert.
Details
- Einstiegskriterien:
- Long:
Close < VWAP && StochK < OversoldLevel - Short:
Close > VWAP && StochK > OverboughtLevel
- Long:
- Long/Short: Beide
- Ausstiegskriterien:
- Long:
Close > VWAP - Short:
Close < VWAP
- Long:
- Stops: Prozentbasiert mit
StopLossPercent - Standardwerte:
StochPeriod= 14StochKPeriod= 3StochDPeriod= 3OverboughtLevel= 80mOversoldLevel= 20mStopLossPercent= 2mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: VWAP, Stochastic Oscillator
- 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 and manual Stochastic %K.
/// Buys when price is below VWAP and Stochastic is oversold.
/// Sells when price is above VWAP and Stochastic is overbought.
/// </summary>
public class VwapStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _stochPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<int> _cooldownBars;
private readonly List<decimal> _highs = new();
private readonly List<decimal> _lows = new();
private readonly List<decimal> _closes = new();
private readonly List<decimal> _volumes = new();
private readonly List<decimal> _typicalPriceVol = new();
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Stochastic lookback period.
/// </summary>
public int StochPeriod
{
get => _stochPeriod.Value;
set => _stochPeriod.Value = value;
}
/// <summary>
/// Overbought level for stochastic (0-100).
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// Oversold level for stochastic (0-100).
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize strategy.
/// </summary>
public VwapStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_stochPeriod = Param(nameof(StochPeriod), 14)
.SetRange(5, 30)
.SetDisplay("Stoch Period", "Lookback period for Stochastic %K", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 80m)
.SetDisplay("Overbought Level", "Level considered overbought", "Trading Levels");
_oversoldLevel = Param(nameof(OversoldLevel), 20m)
.SetDisplay("Oversold Level", "Level considered oversold", "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();
_highs.Clear();
_lows.Clear();
_closes.Clear();
_volumes.Clear();
_typicalPriceVol.Clear();
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Use EMA as binding indicator
var ema = new ExponentialMovingAverage { Length = 20 };
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 high = candle.HighPrice;
var low = candle.LowPrice;
var close = candle.ClosePrice;
var volume = candle.TotalVolume;
var typicalPrice = (high + low + close) / 3m;
_highs.Add(high);
_lows.Add(low);
_closes.Add(close);
_volumes.Add(volume);
_typicalPriceVol.Add(typicalPrice * volume);
var period = StochPeriod;
if (_closes.Count < period)
{
if (_cooldown > 0) _cooldown--;
return;
}
// Manual VWAP (cumulative)
decimal sumTpv = 0;
decimal sumVol = 0;
for (int i = 0; i < _typicalPriceVol.Count; i++)
{
sumTpv += _typicalPriceVol[i];
sumVol += _volumes[i];
}
var vwapValue = sumVol > 0 ? sumTpv / sumVol : close;
// Manual Stochastic %K
decimal highestHigh = decimal.MinValue;
decimal lowestLow = decimal.MaxValue;
var count = _highs.Count;
for (int i = count - period; i < count; i++)
{
if (_highs[i] > highestHigh) highestHigh = _highs[i];
if (_lows[i] < lowestLow) lowestLow = _lows[i];
}
var range = highestHigh - lowestLow;
var stochK = range > 0 ? 100m * (close - lowestLow) / range : 50m;
// Keep stochastic lists manageable (but keep all data for VWAP)
if (_highs.Count > period * 3)
{
// For VWAP we need all data, but for stochastic just recent
// Keep all volumes/tpv for VWAP, trim only H/L/C for stochastic
}
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Buy: price below VWAP + Stochastic oversold
if (close < vwapValue && stochK < OversoldLevel && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Sell: price above VWAP + Stochastic overbought
else if (close > vwapValue && stochK > OverboughtLevel && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: price above VWAP or stoch overbought
if (Position > 0 && (close > vwapValue || stochK > OverboughtLevel))
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: price below VWAP or stoch oversold
else if (Position < 0 && (close < vwapValue || stochK < OversoldLevel))
{
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_stochastic_strategy(Strategy):
"""
Strategy combining VWAP and manual Stochastic %K.
Buys when price is below VWAP and Stochastic is oversold.
Sells when price is above VWAP and Stochastic is overbought.
"""
def __init__(self):
super(vwap_stochastic_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._stoch_period = self.Param("StochPeriod", 14) \
.SetRange(5, 30) \
.SetDisplay("Stoch Period", "Lookback period for Stochastic %K", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 80.0) \
.SetDisplay("Overbought Level", "Level considered overbought", "Trading Levels")
self._oversold_level = self.Param("OversoldLevel", 20.0) \
.SetDisplay("Oversold Level", "Level considered oversold", "Trading Levels")
self._cooldown_bars = self.Param("CooldownBars", 100) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General") \
.SetRange(5, 500)
self._highs = []
self._lows = []
self._closes = []
self._volumes = []
self._typical_price_vol = []
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def stoch_period(self):
return self._stoch_period.Value
@property
def overbought_level(self):
return self._overbought_level.Value
@property
def oversold_level(self):
return self._oversold_level.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnStarted2(self, time):
super(vwap_stochastic_strategy, self).OnStarted2(time)
self._highs = []
self._lows = []
self._closes = []
self._volumes = []
self._typical_price_vol = []
self._cooldown = 0
ema = ExponentialMovingAverage()
ema.Length = 20
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
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
volume = float(candle.TotalVolume)
typical_price = (high + low + close) / 3.0
self._highs.append(high)
self._lows.append(low)
self._closes.append(close)
self._volumes.append(volume)
self._typical_price_vol.append(typical_price * volume)
period = self.stoch_period
if len(self._closes) < period:
if self._cooldown > 0:
self._cooldown -= 1
return
# Manual VWAP (cumulative)
sum_tpv = sum(self._typical_price_vol)
sum_vol = sum(self._volumes)
vwap_value = sum_tpv / sum_vol if sum_vol > 0 else close
# Manual Stochastic %K
count = len(self._highs)
start = count - period
highest_high = max(self._highs[start:count])
lowest_low = min(self._lows[start:count])
rng = highest_high - lowest_low
stoch_k = 100.0 * (close - lowest_low) / rng if rng > 0 else 50.0
if self._cooldown > 0:
self._cooldown -= 1
return
# Buy: price below VWAP + Stochastic oversold
if close < vwap_value and stoch_k < self.oversold_level and self.Position == 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
# Sell: price above VWAP + Stochastic overbought
elif close > vwap_value and stoch_k > self.overbought_level and self.Position == 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit long: price above VWAP or stoch overbought
if self.Position > 0 and (close > vwap_value or stoch_k > self.overbought_level):
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit short: price below VWAP or stoch oversold
elif self.Position < 0 and (close < vwap_value or stoch_k < self.oversold_level):
self.BuyMarket()
self._cooldown = self.cooldown_bars
def OnReseted(self):
super(vwap_stochastic_strategy, self).OnReseted()
self._highs = []
self._lows = []
self._closes = []
self._volumes = []
self._typical_price_vol = []
self._cooldown = 0
def CreateClone(self):
return vwap_stochastic_strategy()