Estratégia Bollinger Williams R
Estratégia baseada nos indicadores Bollinger Bands e Williams %R. Entra comprado quando o preço está na banda inferior e o Williams %R está sobrevendido (< -80). Entra vendido quando o preço está na banda superior e o Williams %R está sobrecomprado (> -20).
Os testes indicam um retorno anual médio de aproximadamente 103%. Funciona melhor no mercado de ações.
As bandas de Bollinger expõem rompimentos de volatilidade e o Williams %R garante que o momentum seja extremo. As posições abrem quando o preço fecha fora de uma banda com uma leitura correspondente do Williams %R.
Melhor para traders de expansão de volatilidade. Stops de ATR lidam com reversões adversas.
Detalhes
- Critérios de entrada:
- Comprado:
Close < LowerBand && WilliamsR < -80 - Vendido:
Close > UpperBand && WilliamsR > -20
- Comprado:
- Comprado/Vendido: Ambos
- Critérios de saída: O preço retorna à banda do meio
- Stops: Baseados em ATR usando
AtrMultiplier - Valores padrão:
BollingerPeriod= 20BollingerDeviation= 2.0mWilliamsRPeriod= 14WilliamsROversold= -80WilliamsROverbought= -20AtrPeriod= 14AtrMultiplier= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame() Os valores -80 e -20 das regras são os padrões de WilliamsROversold e WilliamsROverbought. O stop fica a AtrMultiplier ATR (AtrPeriod) do fechamento de entrada e é verificado nos fechamentos dos candles. Um sinal de entrada contra uma posição aberta a inverte.
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: Bollinger Bands, Williams %R, R
- Stops: Sim
- Complexidade: Intermediário
- Período: Médio prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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()