Williams %R モメンタム戦略
Williams R Momentum 戦略は、Williams %R とモメンタムフィルターを中心に構築されています。
インジケーターがイントラデイ (5m) データ上のモメンタムの転換を Williams が確認したときにシグナルが発動します。これにより、この手法はアクティブトレーダーに適しています。
ストップは ATR の倍数と WilliamsRPeriod、MomentumPeriod などの要素に依存します。リスクとリワードのバランスをとるためにこれらのデフォルト値を調整してください。
詳細
- エントリー条件: インジケーター条件については実装を参照してください。
- ロング/ショート: 両方。
- エグジット条件: 反対のシグナルまたはストップロジック。
- ストップ: はい、インジケーターベースの計算を使用。
- デフォルト値:
WilliamsRPeriod = 14MomentumPeriod = 14WilliamsROversold = -80mWilliamsROverbought = -20mCandleType = TimeSpan.FromMinutes(5).TimeFrame()
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: Williams %R
- ストップ: はい
- 複雑さ: 中級
- 時間軸: イントラデイ (5m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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()