Estratégia Rsi Williams R
Implementação da estratégia - RSI + Williams %R. Compra quando o RSI está abaixo de 30 e o Williams %R está abaixo de -80 (condição de dupla sobrevenda). Vende quando o RSI está acima de 70 e o Williams %R está acima de -20 (condição de dupla sobrecompra).
Os testes indicam um retorno anual médio de aproximadamente 76%. Funciona melhor no mercado forex.
O RSI descreve o momentum geral, enquanto o Williams %R fornece um sinal mais rápido de reversão. As operações são ativadas quando os dois osciladores concordam.
Bom para traders ativos que buscam oscilações curtas. Stops baseados em ATR são empregados.
Detalhes
- Critérios de entrada:
- Comprado:
RSI < RsiOversold && WilliamsR < WilliamsROversold - Vendido:
RSI > RsiOverbought && WilliamsR > WilliamsROverbought
- Comprado:
- Comprado/Vendido: Ambos
- Critérios de saída:
- RSI retorna à zona neutra
- Stops: Baseados em porcentagem usando
StopLoss - Valores padrão:
RsiPeriod= 14RsiOversold= 30mRsiOverbought= 70mWilliamsRPeriod= 14WilliamsROversold= -80mWilliamsROverbought= -20mStopLoss= new Unit(2, UnitTypes.Percent)CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: RSI, 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.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;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Implementation of strategy - RSI + Williams %R.
/// Buy when RSI is below 30 and Williams %R is below -80 (double oversold condition).
/// Sell when RSI is above 70 and Williams %R is above -20 (double overbought condition).
/// </summary>
public class RsiWilliamsRStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _williamsRPeriod;
private readonly StrategyParam<decimal> _williamsROversold;
private readonly StrategyParam<decimal> _williamsROverbought;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<Unit> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private int _cooldown;
private decimal _prevRsi;
private decimal _prevWilliams;
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Williams %R period.
/// </summary>
public int WilliamsRPeriod
{
get => _williamsRPeriod.Value;
set => _williamsRPeriod.Value = value;
}
/// <summary>
/// Williams %R oversold level (usually below -80).
/// </summary>
public decimal WilliamsROversold
{
get => _williamsROversold.Value;
set => _williamsROversold.Value = value;
}
/// <summary>
/// Williams %R overbought level (usually above -20).
/// </summary>
public decimal WilliamsROverbought
{
get => _williamsROverbought.Value;
set => _williamsROverbought.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop-loss value.
/// </summary>
public Unit StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Candle type used for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="RsiWilliamsRStrategy"/>.
/// </summary>
public RsiWilliamsRStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period for Relative Strength Index", "RSI Parameters");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetRange(1, 100)
.SetDisplay("RSI Oversold", "RSI level to consider market oversold", "RSI Parameters");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetRange(1, 100)
.SetDisplay("RSI Overbought", "RSI level to consider market overbought", "RSI Parameters");
_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Period for Williams %R", "Williams %R Parameters");
_williamsROversold = Param(nameof(WilliamsROversold), -80m)
.SetRange(-100, 0)
.SetDisplay("Williams %R Oversold", "Williams %R level to consider market oversold", "Williams %R Parameters");
_williamsROverbought = Param(nameof(WilliamsROverbought), -20m)
.SetRange(-100, 0)
.SetDisplay("Williams %R Overbought", "Williams %R level to consider market overbought", "Williams %R Parameters");
_cooldownBars = Param(nameof(CooldownBars), 180)
.SetRange(5, 500)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_stopLoss = Param(nameof(StopLoss), new Unit(2, UnitTypes.Percent))
.SetDisplay("Stop Loss", "Stop loss percent or value", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = 0;
_prevRsi = 0;
_prevWilliams = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var williamsR = new WilliamsR { Length = WilliamsRPeriod };
// Setup candle subscription
var subscription = SubscribeCandles(CandleType);
// Bind indicators to candles
subscription
.Bind(rsi, williamsR, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
// Create separate area for oscillators
var oscillatorArea = CreateChartArea();
if (oscillatorArea != null)
{
DrawIndicator(oscillatorArea, rsi);
DrawIndicator(oscillatorArea, williamsR);
}
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal williamsRValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevRsi == 0 && _prevWilliams == 0)
{
_prevRsi = rsiValue;
_prevWilliams = williamsRValue;
return;
}
LogInfo($"Candle: {candle.OpenTime}, Close: {candle.ClosePrice}, " +
$"RSI: {rsiValue} , Williams %R: {williamsRValue}");
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsiValue;
_prevWilliams = williamsRValue;
return;
}
var oversoldCross = _prevRsi >= RsiOversold && rsiValue < RsiOversold
&& _prevWilliams >= WilliamsROversold && williamsRValue < WilliamsROversold;
var overboughtCross = _prevRsi <= RsiOverbought && rsiValue > RsiOverbought
&& _prevWilliams <= WilliamsROverbought && williamsRValue > WilliamsROverbought;
// Trading rules
if (oversoldCross && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
LogInfo($"Buy signal: Double oversold condition - RSI: {rsiValue} < {RsiOversold} and Williams %R: {williamsRValue} < {WilliamsROversold}.");
}
else if (overboughtCross && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
LogInfo($"Sell signal: Double overbought condition - RSI: {rsiValue} > {RsiOverbought} and Williams %R: {williamsRValue} > {WilliamsROverbought}.");
}
// Exit conditions
else if (rsiValue > 50 && Position > 0)
{
// Exit long position when RSI returns to neutral zone
SellMarket();
_cooldown = CooldownBars;
LogInfo($"Exit long: RSI returned to neutral zone ({rsiValue} > 50). Position: {Position}");
}
else if (rsiValue < 50 && Position < 0)
{
// Exit short position when RSI returns to neutral zone
BuyMarket();
_cooldown = CooldownBars;
LogInfo($"Exit short: RSI returned to neutral zone ({rsiValue} < 50). Position: {Position}");
}
_prevRsi = rsiValue;
_prevWilliams = williamsRValue;
}
}
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 RelativeStrengthIndex, WilliamsR
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class rsi_williams_r_strategy(Strategy):
"""
RSI + Williams %R strategy.
Buy when both RSI and Williams %R cross into oversold.
Sell when both cross into overbought.
"""
def __init__(self):
super(rsi_williams_r_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Period for RSI", "RSI Parameters")
self._rsi_oversold = self.Param("RsiOversold", 30.0) \
.SetRange(1, 100) \
.SetDisplay("RSI Oversold", "RSI oversold level", "RSI Parameters")
self._rsi_overbought = self.Param("RsiOverbought", 70.0) \
.SetRange(1, 100) \
.SetDisplay("RSI Overbought", "RSI overbought level", "RSI Parameters")
self._williams_r_period = self.Param("WilliamsRPeriod", 14) \
.SetDisplay("Williams %R Period", "Period for Williams %R", "Williams %R Parameters")
self._williams_r_oversold = self.Param("WilliamsROversold", -80.0) \
.SetRange(-100, 0) \
.SetDisplay("Williams %R Oversold", "Williams %R oversold level", "Williams %R Parameters")
self._williams_r_overbought = self.Param("WilliamsROverbought", -20.0) \
.SetRange(-100, 0) \
.SetDisplay("Williams %R Overbought", "Williams %R overbought level", "Williams %R Parameters")
self._cooldown_bars = self.Param("CooldownBars", 180) \
.SetRange(5, 500) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle type for strategy", "General")
self._cooldown = 0
self._prev_rsi = 0.0
self._prev_williams = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(rsi_williams_r_strategy, self).OnStarted2(time)
self._cooldown = 0
self._prev_rsi = 0.0
self._prev_williams = 0.0
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
williams_r = WilliamsR()
williams_r.Length = self._williams_r_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, williams_r, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
osc_area = self.CreateChartArea()
if osc_area is not None:
self.DrawIndicator(osc_area, rsi)
self.DrawIndicator(osc_area, williams_r)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, rsi_value, williams_r_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
wv = float(williams_r_value)
if self._prev_rsi == 0 and self._prev_williams == 0:
self._prev_rsi = rv
self._prev_williams = wv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_rsi = rv
self._prev_williams = wv
return
cd = self._cooldown_bars.Value
rsi_os = self._rsi_oversold.Value
rsi_ob = self._rsi_overbought.Value
wr_os = self._williams_r_oversold.Value
wr_ob = self._williams_r_overbought.Value
oversold_cross = (self._prev_rsi >= rsi_os and rv < rsi_os
and self._prev_williams >= wr_os and wv < wr_os)
overbought_cross = (self._prev_rsi <= rsi_ob and rv > rsi_ob
and self._prev_williams <= wr_ob and wv > wr_ob)
if oversold_cross and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
elif overbought_cross and self.Position == 0:
self.SellMarket()
self._cooldown = cd
elif rv > 50 and self.Position > 0:
self.SellMarket()
self._cooldown = cd
elif rv < 50 and self.Position < 0:
self.BuyMarket()
self._cooldown = cd
self._prev_rsi = rv
self._prev_williams = wv
def OnReseted(self):
super(rsi_williams_r_strategy, self).OnReseted()
self._cooldown = 0
self._prev_rsi = 0.0
self._prev_williams = 0.0
def CreateClone(self):
return rsi_williams_r_strategy()