Start
/
Strategie-Beispiele
Auf GitHub ansehen
Strategie CCI VWAP
Der CCI VWAP-Ansatz versucht, Intraday-Umkehrungen zu erfassen, wenn Momentum und Preis vom volumengewichteten Durchschnittspreis abweichen. Durch die Beobachtung des Commodity Channel Index neben dem VWAP-Level misst das System die Stärke der jüngsten Bewegungen im Verhältnis zu einem fairen Wert.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 70%. Sie funktioniert am besten auf dem Aktienmarkt.
Ein Kaufsignal entsteht, wenn der CCI unter -100 fällt und der Markt unter dem VWAP handelt, was darauf hinweist, dass der Verkaufsdruck erschöpft sein könnte. Ein Short entsteht, wenn der CCI über +100 steigt und der Preis über dem VWAP liegt, was eine überdehnte Rally hervorhebt, die anfällig für einen Rücksetzer ist. Positionen werden geschlossen, sobald der Preis den VWAP in die entgegengesetzte Richtung zurückerobert.
Diese Strategie eignet sich für Daytrader, die extreme Positionen handeln möchten, aber dennoch auf objektive Levels für Ausstiege vertrauen. Der definierte Stop-Loss hilft, das Risiko zu managen, wenn das Momentum nicht schnell zur Mitte revertiert.
Details
Einstiegskriterien :
Long : CCI < -100 && Price < VWAP (oversold below VWAP)
Short : CCI > 100 && Price > VWAP (overbought above VWAP)
Long/Short : Beide Seiten.
Ausstiegskriterien :
Long : Long schließen, wenn der Preis über den VWAP steigt
Short : Short schließen, wenn der Preis unter den VWAP fällt
Stops : Ja.
Standardwerte :
CciPeriod = 20
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filter :
Kategorie: Gemischt
Richtung: Beide
Indikatoren: CCI VWAP
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 that uses CCI and VWAP indicators to identify oversold and overbought conditions.
/// Enters long when CCI is below -100 and price is below VWAP.
/// Enters short when CCI is above 100 and price is above VWAP.
/// </summary>
public class CciVwapStrategy : Strategy
{
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private CommodityChannelIndex _cci;
private int _cooldown;
private DateTime _vwapDate;
private decimal _vwapCumPv;
private decimal _vwapCumVol;
/// <summary>
/// CCI period parameter.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop-loss percentage parameter.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public CciVwapStrategy()
{
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("CCI period", "CCI indicator period", "Indicators")
.SetOptimize(10, 30, 5);
_cooldownBars = Param(nameof(CooldownBars), 60)
.SetRange(1, 200)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetGreaterThanZero()
.SetDisplay("Stop-loss %", "Stop-loss as percentage of entry price", "Risk Management")
.SetOptimize(1m, 3m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
_cci = null;
_cooldown = 0;
_vwapDate = default;
_vwapCumPv = 0m;
_vwapCumVol = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize CCI indicator
_cci = new CommodityChannelIndex
{
Length = CciPeriod
};
var dummyEma = new ExponentialMovingAverage { Length = 10 };
// Bind CCI to candle subscription
var candlesSubscription = SubscribeCandles(CandleType)
.Bind(_cci, dummyEma, ProcessCandle)
.Start();
// Setup chart if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, candlesSubscription);
DrawIndicator(area, _cci);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cci, decimal dummyValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
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 currentVwap = _vwapCumPv / _vwapCumVol;
if (currentVwap == 0)
return;
if (_cooldown > 0)
_cooldown--;
// Long signal: CCI below -100 and price below VWAP
if (_cooldown == 0 && cci < -100 && candle.ClosePrice < currentVwap && Position <= 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (_cooldown == 0 && cci > 100 && candle.ClosePrice > currentVwap && Position >= 0)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice > currentVwap)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice < currentVwap)
{
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 CommodityChannelIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cci_vwap_strategy(Strategy):
"""
CCI + VWAP strategy.
Enters long when CCI < -100 and price < VWAP.
Enters short when CCI > 100 and price > VWAP.
"""
def __init__(self):
super(cci_vwap_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI period", "CCI indicator period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 60) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle type", "Type of candles to use", "General")
self._cooldown = 0
self._vwap_date = None
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cci_vwap_strategy, self).OnReseted()
self._cooldown = 0
self._vwap_date = None
self._vwap_cum_pv = 0.0
self._vwap_cum_vol = 0.0
def OnStarted2(self, time):
super(cci_vwap_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
dummy_ema = ExponentialMovingAverage()
dummy_ema.Length = 10
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, dummy_ema, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def on_process(self, candle, cci_val, dummy_val):
if candle.State != CandleStates.Finished:
return
date = candle.ServerTime.Date
if 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
current_vwap = self._vwap_cum_pv / self._vwap_cum_vol
if current_vwap == 0:
return
if self._cooldown > 0:
self._cooldown -= 1
close = float(candle.ClosePrice)
if self._cooldown == 0 and cci_val < -100 and close < current_vwap and self.Position <= 0:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
elif self._cooldown == 0 and cci_val > 100 and close > current_vwap and self.Position >= 0:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position > 0 and close > current_vwap:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position < 0 and close < current_vwap:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
def CreateClone(self):
return cci_vwap_strategy()