Estratégia de Momentum Williams %R
A estratégia Williams R Momentum é construída em torno do Williams %R com filtro de Momentum.
Os sinais são acionados quando Williams confirma mudanças de momentum em dados intradiários (5m). Isso torna o método adequado para traders ativos.
Os stops dependem de múltiplos de ATR e fatores como WilliamsRPeriod, MomentumPeriod. Ajuste esses valores padrão para equilibrar risco e recompensa.
Detalhes
- Critérios de entrada: ver implementação para condições dos indicadores.
- Comprado/Vendido: Ambos.
- Critérios de saída: sinal oposto ou lógica de stops.
- Stops: Sim, usando cálculos baseados em indicadores.
- Valores padrão:
WilliamsRPeriod = 14MomentumPeriod = 14WilliamsROversold = -80mWilliamsROverbought = -20mCandleType = TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoria: Seguidor de tendência
- Direção: Ambos
- Indicadores: Williams %R
- Stops: Sim
- Complexidade: Intermediário
- Período: Intradiário (5m)
- 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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Williams %R with Momentum filter.
/// </summary>
public class WilliamsPercentRWithMomentumStrategy : Strategy
{
private readonly StrategyParam<int> _williamsRPeriod;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<decimal> _williamsROversold;
private readonly StrategyParam<decimal> _williamsROverbought;
private readonly StrategyParam<DataType> _candleType;
private WilliamsR _williamsR;
private Momentum _momentum;
private SimpleMovingAverage _momentumSma;
/// <summary>
/// Williams %R period parameter.
/// </summary>
public int WilliamsRPeriod
{
get => _williamsRPeriod.Value;
set => _williamsRPeriod.Value = value;
}
/// <summary>
/// Momentum period parameter.
/// </summary>
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
/// <summary>
/// Williams %R oversold level parameter.
/// </summary>
public decimal WilliamsROversold
{
get => _williamsROversold.Value;
set => _williamsROversold.Value = value;
}
/// <summary>
/// Williams %R overbought level parameter.
/// </summary>
public decimal WilliamsROverbought
{
get => _williamsROverbought.Value;
set => _williamsROverbought.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public WilliamsPercentRWithMomentumStrategy()
{
_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Period for Williams %R calculation", "Indicators")
.SetOptimize(5, 30, 5);
_momentumPeriod = Param(nameof(MomentumPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Period for Momentum calculation", "Indicators")
.SetOptimize(5, 30, 5);
_williamsROversold = Param(nameof(WilliamsROversold), -80m)
.SetDisplay("Williams %R Oversold", "Williams %R oversold level", "Indicators")
.SetOptimize(-90, -70, 5);
_williamsROverbought = Param(nameof(WilliamsROverbought), -20m)
.SetDisplay("Williams %R Overbought", "Williams %R overbought level", "Indicators")
.SetOptimize(-30, -10, 5);
_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();
_williamsR?.Reset();
_momentum?.Reset();
_momentumSma?.Reset();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_williamsR = new WilliamsR { Length = WilliamsRPeriod };
_momentum = new Momentum { Length = MomentumPeriod };
_momentumSma = new SMA { Length = MomentumPeriod };
// Subscribe to candles and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_williamsR, _momentum, (candle, williamsRValue, momentumValue) =>
{
// Calculate momentum average
var momentumAvg = _momentumSma.Process(new DecimalIndicatorValue(_momentumSma, momentumValue, candle.ServerTime)).ToDecimal();
// Process the strategy logic
ProcessStrategy(candle, williamsRValue, momentumValue, momentumAvg);
})
.Start();
// Setup chart if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _williamsR);
DrawIndicator(area, _momentum);
DrawOwnTrades(area);
}
// Setup position protection
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessStrategy(ICandleMessage candle, decimal williamsRValue, decimal momentumValue, decimal momentumAvg)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready for trading
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Check momentum - rising or falling
var isMomentumRising = momentumValue > momentumAvg;
// Trading logic
if (williamsRValue < WilliamsROversold && isMomentumRising && Position <= 0)
{
// Williams %R oversold with rising momentum - Go long
CancelActiveOrders();
// Calculate position size
var volume = Volume + Math.Abs(Position);
// Enter long position
BuyMarket(volume);
}
else if (williamsRValue > WilliamsROverbought && !isMomentumRising && Position >= 0)
{
// Williams %R overbought with falling momentum - Go short
CancelActiveOrders();
// Calculate position size
var volume = Volume + Math.Abs(Position);
// Enter short position
SellMarket(volume);
}
// Exit logic - when Williams %R crosses the middle (-50) level
if ((Position > 0 && williamsRValue > -50) || (Position < 0 && williamsRValue < -50))
{
// Close position
ClosePosition();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import WilliamsR, Momentum, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class williams_percent_r_with_momentum_strategy(Strategy):
"""
Strategy based on Williams %R with Momentum filter.
"""
def __init__(self):
super(williams_percent_r_with_momentum_strategy, self).__init__()
self._williams_r_period = self.Param("WilliamsRPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Williams %R Period", "Period for Williams %R calculation", "Indicators")
self._momentum_period = self.Param("MomentumPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Momentum Period", "Period for Momentum calculation", "Indicators")
self._williams_r_oversold = self.Param("WilliamsROversold", -80.0) \
.SetDisplay("Williams %R Oversold", "Williams %R oversold level", "Indicators")
self._williams_r_overbought = self.Param("WilliamsROverbought", -20.0) \
.SetDisplay("Williams %R Overbought", "Williams %R overbought level", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(williams_percent_r_with_momentum_strategy, self).OnReseted()
def OnStarted2(self, time):
super(williams_percent_r_with_momentum_strategy, self).OnStarted2(time)
williams_r = WilliamsR()
williams_r.Length = int(self._williams_r_period.Value)
momentum = Momentum()
momentum.Length = int(self._momentum_period.Value)
self._momentum_sma = SimpleMovingAverage()
self._momentum_sma.Length = int(self._momentum_period.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(williams_r, momentum, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, williams_r)
self.DrawIndicator(area, momentum)
self.DrawOwnTrades(area)
self.StartProtection(
Unit(2, UnitTypes.Percent),
Unit(1, UnitTypes.Percent)
)
def _process_candle(self, candle, williams_r_value, momentum_value):
momentum_avg = float(process_float(self._momentum_sma, Decimal(float(momentum_value)), candle.ServerTime, True))
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
wr = float(williams_r_value)
mom = float(momentum_value)
is_momentum_rising = mom > momentum_avg
oversold = float(self._williams_r_oversold.Value)
overbought = float(self._williams_r_overbought.Value)
if wr < oversold and is_momentum_rising and self.Position <= 0:
volume = self.Volume + Math.Abs(self.Position)
self.BuyMarket(volume)
elif wr > overbought and not is_momentum_rising and self.Position >= 0:
volume = self.Volume + Math.Abs(self.Position)
self.SellMarket(volume)
if self.Position > 0 and wr > -50:
self.SellMarket(Math.Abs(self.Position))
elif self.Position < 0 and wr < -50:
self.BuyMarket(Math.Abs(self.Position))
def CreateClone(self):
return williams_percent_r_with_momentum_strategy()