Estrategia Voss Predictor
Esta estrategia implementa el filtro predictivo Voss de John Ehlers con un filtro de paso de banda para anticipar el movimiento del precio. Una posición larga se abre cuando el filtro predictivo sube por encima de la salida del paso de banda, mientras que una posición corta se abre cuando cae por debajo.
Detalles
- Entrada: El filtro predictivo Voss cruza por encima del filtro de paso de banda.
- Salida: El filtro predictivo Voss cruza por debajo del filtro de paso de banda.
- Tipo: Seguimiento de tendencia.
- Stops: Ninguno.
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 John Ehlers' Voss predictor.
/// Buys when the predictive filter crosses above the band-pass filter and sells on the opposite cross.
/// </summary>
public class VossPredictorStrategy : Strategy
{
private readonly StrategyParam<int> _periodBandpass;
private readonly StrategyParam<decimal> _bandWidth;
private readonly StrategyParam<decimal> _barsPrediction;
private readonly StrategyParam<DataType> _candleType;
private decimal? _pricePrev1;
private decimal? _pricePrev2;
private decimal _bandPassPrev1;
private decimal _bandPassPrev2;
private readonly decimal[] _vossBuffer = new decimal[9];
private decimal _prevVpf;
private decimal _prevBpf;
/// <summary>
/// Band-pass period.
/// </summary>
public int PeriodBandpass { get => _periodBandpass.Value; set => _periodBandpass.Value = value; }
/// <summary>
/// Bandwidth coefficient.
/// </summary>
public decimal BandWidth { get => _bandWidth.Value; set => _bandWidth.Value = value; }
/// <summary>
/// Bars of prediction.
/// </summary>
public decimal BarsPrediction { get => _barsPrediction.Value; set => _barsPrediction.Value = value; }
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Constructor.
/// </summary>
public VossPredictorStrategy()
{
_periodBandpass = Param(nameof(PeriodBandpass), 20)
.SetGreaterThanZero()
.SetDisplay("Bandpass Period", "Period for band-pass filter", "Settings")
.SetOptimize(10, 40, 5);
_bandWidth = Param(nameof(BandWidth), 0.25m)
.SetGreaterThanZero()
.SetDisplay("Bandwidth", "Bandwidth coefficient", "Settings")
.SetOptimize(0.05m, 1.0m, 0.05m);
_barsPrediction = Param(nameof(BarsPrediction), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Bars of Prediction", "Look ahead bars", "Settings")
.SetOptimize(0.5m, 3.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_pricePrev1 = null;
_pricePrev2 = null;
_bandPassPrev1 = 0m;
_bandPassPrev2 = 0m;
Array.Clear(_vossBuffer, 0, _vossBuffer.Length);
_prevVpf = 0m;
_prevBpf = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var alpha = 2.0 * Math.PI / PeriodBandpass;
var cosAlpha = (decimal)Math.Cos(alpha);
var gamma = Math.Cos(alpha * (double)BandWidth);
var delta = 1.0 / gamma - Math.Sqrt(1.0 / (gamma * gamma) - 1.0);
var deltaDec = (decimal)delta;
var order = (int)(3m * Math.Min(3m, BarsPrediction));
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(candle =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var price = candle.ClosePrice;
var prev2 = _pricePrev2 ?? _pricePrev1 ?? price;
var whiten = 0.5m * (price - prev2);
_pricePrev2 = _pricePrev1;
_pricePrev1 = price;
var bandPass = (1m - deltaDec) * whiten
+ cosAlpha * (1m + deltaDec) * _bandPassPrev1
- deltaDec * _bandPassPrev2;
_bandPassPrev2 = _bandPassPrev1;
_bandPassPrev1 = bandPass;
decimal e = 0m;
for (var i = 0; i < order; i++)
{
e += _vossBuffer[order - i - 1] * (1m + i) / order;
}
var vpf = 0.5m * (3m + order) * bandPass - e;
for (var i = order - 1; i > 0; i--)
_vossBuffer[i] = _vossBuffer[i - 1];
_vossBuffer[0] = vpf;
var crossUp = _prevVpf <= _prevBpf && vpf > bandPass;
var crossDown = _prevVpf >= _prevBpf && vpf < bandPass;
if (crossUp && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (crossDown && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
_prevVpf = vpf;
_prevBpf = bandPass;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
import math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class voss_predictor_strategy(Strategy):
def __init__(self):
super(voss_predictor_strategy, self).__init__()
self._period_bandpass = self.Param("PeriodBandpass", 20) \
.SetDisplay("Bandpass Period", "Period for band-pass filter", "Settings")
self._band_width = self.Param("BandWidth", 0.25) \
.SetDisplay("Bandwidth", "Bandwidth coefficient", "Settings")
self._bars_prediction = self.Param("BarsPrediction", 3.0) \
.SetDisplay("Bars of Prediction", "Look ahead bars", "Settings")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._price_prev1 = None
self._price_prev2 = None
self._band_pass_prev1 = 0.0
self._band_pass_prev2 = 0.0
self._prev_vpf = 0.0
self._prev_bpf = 0.0
self._voss_buffer = [0.0] * 9
@property
def period_bandpass(self):
return self._period_bandpass.Value
@property
def band_width(self):
return self._band_width.Value
@property
def bars_prediction(self):
return self._bars_prediction.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(voss_predictor_strategy, self).OnReseted()
self._price_prev1 = None
self._price_prev2 = None
self._band_pass_prev1 = 0.0
self._band_pass_prev2 = 0.0
self._prev_vpf = 0.0
self._prev_bpf = 0.0
self._voss_buffer = [0.0] * 9
def OnStarted2(self, time):
super(voss_predictor_strategy, self).OnStarted2(time)
alpha = 2.0 * math.pi / float(self.period_bandpass)
self._cos_alpha = math.cos(alpha)
gamma = math.cos(alpha * float(self.band_width))
delta = 1.0 / gamma - math.sqrt(1.0 / (gamma * gamma) - 1.0)
self._delta_dec = delta
self._order = int(3.0 * min(3.0, float(self.bars_prediction)))
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
prev2 = self._price_prev2 if self._price_prev2 is not None else (self._price_prev1 if self._price_prev1 is not None else price)
whiten = 0.5 * (price - prev2)
self._price_prev2 = self._price_prev1
self._price_prev1 = price
band_pass = (1.0 - self._delta_dec) * whiten \
+ self._cos_alpha * (1.0 + self._delta_dec) * self._band_pass_prev1 \
- self._delta_dec * self._band_pass_prev2
self._band_pass_prev2 = self._band_pass_prev1
self._band_pass_prev1 = band_pass
e = 0.0
for i in range(self._order):
e += self._voss_buffer[self._order - i - 1] * (1.0 + i) / self._order
vpf = 0.5 * (3.0 + self._order) * band_pass - e
i = self._order - 1
while i > 0:
self._voss_buffer[i] = self._voss_buffer[i - 1]
i -= 1
self._voss_buffer[0] = vpf
cross_up = self._prev_vpf <= self._prev_bpf and vpf > band_pass
cross_down = self._prev_vpf >= self._prev_bpf and vpf < band_pass
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_vpf = vpf
self._prev_bpf = band_pass
def CreateClone(self):
return voss_predictor_strategy()