El oscilador Williams %R mide las condiciones de sobrecompra y sobreventa. Cuando el precio marca un nuevo mínimo pero el %R forma un mínimo más alto, o cuando el precio imprime un nuevo máximo pero el %R gira a la baja, el impulso puede revertirse. Esta estrategia busca tales divergencias en los extremos del indicador.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 109%. Funciona mejor en el mercado de criptomonedas.
En cada barra, el sistema registra el último cierre y el valor de %R para compararlo con la lectura anterior. Una divergencia alcista combinada con un nivel por debajo de -80 activa una entrada larga, mientras que una divergencia bajista y una lectura por encima de -20 genera una posición corta. Los stops se establecen usando un porcentaje del precio.
Las posiciones se cierran cuando el oscilador vuelve al extremo opuesto, capturando el rebote desde la señal de divergencia.
Detalles
Criterios de entrada: Divergencia Precio/Williams %R con %R por debajo de -80 para largos o por encima de -20 para cortos.
Largo/Corto: Ambos.
Criterios de salida: Williams %R alcanzando el extremo opuesto o stop-loss.
Stops: Sí, basados en porcentaje.
Valores predeterminados:
WilliamsRPeriod = 14
DivergencePeriod = 5
CandleType = 5 minute
StopLossPercent = 2
Filtros:
Categoría: Divergencia
Dirección: Ambos
Indicadores: Williams %R
Stops: Sí
Complejidad: Intermedio
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: Sí
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>
/// Williams %R Divergence strategy.
/// Detects divergences between price and Williams %R for reversal signals.
/// Bullish: price falling but Williams %R rising (oversold zone).
/// Bearish: price rising but Williams %R falling (overbought zone).
/// </summary>
public class WilliamsPercentRDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _williamsRPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevPrice;
private decimal _prevWR;
private int _cooldown;
/// <summary>
/// Williams %R period.
/// </summary>
public int WilliamsRPeriod
{
get => _williamsRPeriod.Value;
set => _williamsRPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public WilliamsPercentRDivergenceStrategy()
{
_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Period for Williams %R", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPrice = default;
_prevWR = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPrice = 0;
_prevWR = 0;
_cooldown = 0;
var williamsR = new WilliamsR { Length = WilliamsRPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(williamsR, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, williamsR);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal wrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevPrice == 0)
{
_prevPrice = candle.ClosePrice;
_prevWR = wrValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevPrice = candle.ClosePrice;
_prevWR = wrValue;
return;
}
// Bullish divergence: price lower but WR higher (in oversold zone)
var bullishDiv = candle.ClosePrice < _prevPrice && wrValue > _prevWR;
// Bearish divergence: price higher but WR lower (in overbought zone)
var bearishDiv = candle.ClosePrice > _prevPrice && wrValue < _prevWR;
if (Position == 0 && bullishDiv && wrValue < -80)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && bearishDiv && wrValue > -20)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && wrValue > -20)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && wrValue < -80)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevPrice = candle.ClosePrice;
_prevWR = wrValue;
}
}
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 WilliamsR
from StockSharp.Algo.Strategies import Strategy
class williams_percent_r_divergence_strategy(Strategy):
"""
Williams %R Divergence strategy.
Detects divergences between price and Williams %R for reversal signals.
Bullish: price falling but Williams %R rising (oversold zone).
Bearish: price rising but Williams %R falling (overbought zone).
"""
def __init__(self):
super(williams_percent_r_divergence_strategy, self).__init__()
self._wr_period = self.Param("WilliamsRPeriod", 14).SetDisplay("Williams %R Period", "Period for Williams %R", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_price = 0.0
self._prev_wr = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(williams_percent_r_divergence_strategy, self).OnReseted()
self._prev_price = 0.0
self._prev_wr = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(williams_percent_r_divergence_strategy, self).OnStarted2(time)
self._prev_price = 0.0
self._prev_wr = 0.0
self._cooldown = 0
wr = WilliamsR()
wr.Length = self._wr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(wr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, wr)
self.DrawOwnTrades(area)
def _process_candle(self, candle, wr_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
wv = float(wr_val)
if self._prev_price == 0:
self._prev_price = close
self._prev_wr = wv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_price = close
self._prev_wr = wv
return
cd = self._cooldown_bars.Value
# Bullish divergence: price lower but WR higher (in oversold zone)
bullish_div = close < self._prev_price and wv > self._prev_wr
# Bearish divergence: price higher but WR lower (in overbought zone)
bearish_div = close > self._prev_price and wv < self._prev_wr
if self.Position == 0 and bullish_div and wv < -80:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and bearish_div and wv > -20:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and wv > -20:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and wv < -80:
self.BuyMarket()
self._cooldown = cd
self._prev_price = close
self._prev_wr = wv
def CreateClone(self):
return williams_percent_r_divergence_strategy()