Estrategia Bollinger Williams R
Estrategia basada en los indicadores Bollinger Bands y Williams %R. Entra largo cuando el precio está en la banda inferior y el Williams %R está sobrevendido (< -80). Entra corto cuando el precio está en la banda superior y el Williams %R está sobrecomprado (> -20).
Las pruebas indican un rendimiento anual promedio de aproximadamente 103%. Funciona mejor en el mercado de acciones.
Las bandas de Bollinger exponen las rupturas de volatilidad y el Williams %R asegura que el impulso sea extremo. Las posiciones se abren cuando el precio cierra fuera de una banda con una lectura de Williams %R correspondiente.
La mejor opción para traders de expansión de volatilidad. Los stops de ATR manejan los giros adversos.
Detalles
- Criterios de entrada:
- Largo:
Close < LowerBand && WilliamsR < -80 - Corto:
Close > UpperBand && WilliamsR > -20
- Largo:
- Largo/Corto: Ambos
- Criterios de salida: El precio regresa a la banda media
- Stops: Basados en ATR usando
AtrMultiplier - Valores predeterminados:
BollingerPeriod= 20BollingerDeviation= 2.0mWilliamsRPeriod= 14WilliamsROversold= -80WilliamsROverbought= -20AtrPeriod= 14AtrMultiplier= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame() Los valores -80 y -20 de las reglas son los predeterminados de WilliamsROversold y WilliamsROverbought. El stop está a AtrMultiplier ATR (AtrPeriod) del cierre de entrada y se comprueba en los cierres de vela. Una señal de entrada contra una posición abierta la invierte.
- Filtros:
- Categoría: Reversión a la media
- Dirección: Ambos
- Indicadores: Bollinger Bands, Williams %R, R
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Medio plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Bollinger Williams %R strategy.
/// A close below the lower band with Williams %R below WilliamsROversold goes long and a close above the upper band with %R above
/// WilliamsROverbought goes short, reversing an opposite position. The position closes when price returns to the middle band.
/// The stop lies AtrMultiplier ATR from the entry close and is checked on candle closes.
/// </summary>
public class BollingerWilliamsRStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _williamsRPeriod;
private readonly StrategyParam<decimal> _williamsROversold;
private readonly StrategyParam<decimal> _williamsROverbought;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<DataType> _candleType;
private decimal _stopPrice;
/// <summary>
/// Period of the Bollinger Bands.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier of the bands.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Period of Williams %R.
/// </summary>
public int WilliamsRPeriod
{
get => _williamsRPeriod.Value;
set => _williamsRPeriod.Value = value;
}
/// <summary>
/// Williams %R level for longs.
/// </summary>
public decimal WilliamsROversold
{
get => _williamsROversold.Value;
set => _williamsROversold.Value = value;
}
/// <summary>
/// Williams %R level for shorts.
/// </summary>
public decimal WilliamsROverbought
{
get => _williamsROverbought.Value;
set => _williamsROverbought.Value = value;
}
/// <summary>
/// Period of the stop ATR.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Stop distance from the entry in ATRs.
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerWilliamsRStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Period of the Bollinger Bands", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier of the bands", "Indicators");
_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Period of Williams %R", "Indicators");
_williamsROversold = Param(nameof(WilliamsROversold), -80m)
.SetDisplay("Williams %R Oversold", "Williams %R level for longs", "Indicators");
_williamsROverbought = Param(nameof(WilliamsROverbought), -20m)
.SetDisplay("Williams %R Overbought", "Williams %R level for shorts", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Period of the stop ATR", "Risk");
_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
.SetNotNegative()
.SetDisplay("ATR Multiplier", "Stop distance from the entry in ATRs", "Risk");
_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();
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_stopPrice = default;
var bollinger = new BollingerBands { Length = BollingerPeriod, Width = BollingerDeviation };
var williams = new WilliamsR { Length = WilliamsRPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, williams, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, williams);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue williamsValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerValue.IsFormed || !williamsValue.IsFormed || !atrValue.IsFormed)
return;
var bands = (BollingerBandsValue)bollingerValue;
if (bands.UpBand is not decimal upper || bands.LowBand is not decimal lower || bands.MovingAverage is not decimal middle)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var atr = atrValue.GetValue<decimal>();
var close = candle.ClosePrice;
var williams = williamsValue.GetValue<decimal>();
if (close < lower && williams < WilliamsROversold && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_stopPrice = close - AtrMultiplier * atr;
}
else if (close > upper && williams > WilliamsROverbought && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_stopPrice = close + AtrMultiplier * atr;
}
else if (Position > 0 && (close >= middle || (AtrMultiplier > 0 && close <= _stopPrice)))
{
SellMarket(Position);
}
else if (Position < 0 && (close <= middle || (AtrMultiplier > 0 && close >= _stopPrice)))
{
BuyMarket(-Position);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, WilliamsR, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class bollinger_williams_r_strategy(Strategy):
"""
Bollinger Williams %R strategy.
A close below the lower band with Williams %R below WilliamsROversold goes long and a close above the upper band with %R above
WilliamsROverbought goes short, reversing an opposite position. The position closes when price returns to the middle band.
The stop lies AtrMultiplier ATR from the entry close and is checked on candle closes.
"""
def __init__(self):
super(bollinger_williams_r_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20).SetGreaterThanZero().SetDisplay("Bollinger Period", "Period of the Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0).SetGreaterThanZero().SetDisplay("Bollinger Deviation", "Standard deviation multiplier of the bands", "Indicators")
self._williams_r_period = self.Param("WilliamsRPeriod", 14).SetGreaterThanZero().SetDisplay("Williams %R Period", "Period of Williams %R", "Indicators")
self._williams_r_oversold = self.Param("WilliamsROversold", -80.0).SetDisplay("Williams %R Oversold", "Williams %R level for longs", "Indicators")
self._williams_r_overbought = self.Param("WilliamsROverbought", -20.0).SetDisplay("Williams %R Overbought", "Williams %R level for shorts", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14).SetGreaterThanZero().SetDisplay("ATR Period", "Period of the stop ATR", "Risk")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0).SetNotNegative().SetDisplay("ATR Multiplier", "Stop distance from the entry in ATRs", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._stop_price = Decimal(0)
def OnReseted(self):
super(bollinger_williams_r_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(bollinger_williams_r_strategy, self).OnStarted2(time)
self._reset_state()
bollinger = BollingerBands()
bollinger.Length = self._bollinger_period.Value
bollinger.Width = Decimal(self._bollinger_deviation.Value)
williams = WilliamsR()
williams.Length = self._williams_r_period.Value
atr = AverageTrueRange()
atr.Length = self._atr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, williams, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, williams)
def _process_candle(self, candle, bollinger_value, williams_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not bollinger_value.IsFormed or not williams_value.IsFormed or not atr_value.IsFormed:
return
if bollinger_value.UpBand is None or bollinger_value.LowBand is None or bollinger_value.MovingAverage is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
upper = bollinger_value.UpBand
lower = bollinger_value.LowBand
middle = bollinger_value.MovingAverage
atr = atr_value.GetValue[Decimal](None)
close = candle.ClosePrice
williams = williams_value.GetValue[Decimal](None)
stop_atr = Decimal(self._atr_multiplier.Value)
if close < lower and williams < Decimal(self._williams_r_oversold.Value) and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._stop_price = close - stop_atr * atr
elif close > upper and williams > Decimal(self._williams_r_overbought.Value) and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._stop_price = close + stop_atr * atr
elif self.Position > 0 and (close >= middle or (stop_atr > 0 and close <= self._stop_price)):
self.SellMarket(self.Position)
elif self.Position < 0 and (close <= middle or (stop_atr > 0 and close >= self._stop_price)):
self.BuyMarket(-self.Position)
def CreateClone(self):
return bollinger_williams_r_strategy()