Импульс Williams %R
Стратегия Williams R Momentum основана на индикаторе Williams %R с фильтром Momentum.
Сигналы формируются, когда индикатор Williams подтверждает смену импульса на внутридневных данных (5м). Такой метод подходит активным трейдерам.
Стопы рассчитываются на основе кратных ATR и параметров WilliamsRPeriod, MomentumPeriod. Настройте эти значения для баланса риска и прибыли.
Подробности
- Критерии входа: см. реализацию условий индикаторов.
- Длинные/короткие: обе стороны.
- Критерии выхода: противоположный сигнал или логика стопов.
- Стопы: да, расчёт на основе индикаторов.
- Значения по умолчанию:
WilliamsRPeriod = 14MomentumPeriod = 14WilliamsROversold = -80mWilliamsROverbought = -20mCandleType = TimeSpan.FromMinutes(5).TimeFrame()
- Фильтры:
- Категория: Следование за трендом
- Направление: Оба
- Индикаторы: Williams %R
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Внутридневной (5м)
- Сезонность: Нет
- Нейронные сети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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()