Estrategia WPR de Cruce de Nivel
Esta estrategia opera basándose en el oscilador Williams %R al cruzar niveles predefinidos de sobrecompra y sobreventa.
Cuando el indicador cruza por debajo del Low Level, señala una posible reversión desde una condición de sobreventa. Cuando cruza por encima del High Level, indica una posible reversión desde una condición de sobrecompra. Dependiendo del Trend Mode seleccionado, la estrategia puede operar en la dirección del indicador o invertir las señales para operar en contratendencia.
Parámetros
WprPeriod– período de lookback para Williams %R.HighLevel– umbral de sobrecompra.LowLevel– umbral de sobreventa.Trend–Directopera con las señales del indicador,Againstlas invierte.EnableBuyEntry/EnableSellEntry– permitir entrar en posiciones largas/cortas.EnableBuyExit/EnableSellExit– permitir cerrar posiciones cortas/largas.StopLoss– valor del stop-loss en unidades de precio.TakeProfit– valor del take-profit en unidades de precio.CandleType– marco temporal de las velas usadas para los cálculos.
Cómo Funciona
- La estrategia se suscribe a velas y calcula el indicador Williams %R.
- En cada vela terminada verifica si el indicador cruzó los niveles especificados.
- Dependiendo de
Trendy las acciones habilitadas, abre o cierra posiciones usando órdenes de mercado. - La protección opcional de stop-loss y take-profit se activa mediante
StartProtection.
Notas
- Los comentarios en el código están en inglés.
- Solo se implementa la versión C#; la versión Python se omite intencionalmente.
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 indicator crossing specified levels.
/// </summary>
public class WprLevelCrossStrategy : Strategy
{
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<TrendModes> _trend;
private readonly StrategyParam<bool> _enableBuyEntry;
private readonly StrategyParam<bool> _enableSellEntry;
private readonly StrategyParam<bool> _enableBuyExit;
private readonly StrategyParam<bool> _enableSellExit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevWr;
/// <summary>
/// Lookback period for Williams %R.
/// </summary>
public int WprPeriod
{
get => _wprPeriod.Value;
set => _wprPeriod.Value = value;
}
/// <summary>
/// Upper threshold to detect overbought levels.
/// </summary>
public decimal HighLevel
{
get => _highLevel.Value;
set => _highLevel.Value = value;
}
/// <summary>
/// Lower threshold to detect oversold levels.
/// </summary>
public decimal LowLevel
{
get => _lowLevel.Value;
set => _lowLevel.Value = value;
}
/// <summary>
/// Trend mode: Direct trades with indicator, Against inverts signals.
/// </summary>
public TrendModes Trend
{
get => _trend.Value;
set => _trend.Value = value;
}
/// <summary>
/// Enable opening of long positions.
/// </summary>
public bool EnableBuyEntry
{
get => _enableBuyEntry.Value;
set => _enableBuyEntry.Value = value;
}
/// <summary>
/// Enable opening of short positions.
/// </summary>
public bool EnableSellEntry
{
get => _enableSellEntry.Value;
set => _enableSellEntry.Value = value;
}
/// <summary>
/// Enable closing of short positions.
/// </summary>
public bool EnableBuyExit
{
get => _enableBuyExit.Value;
set => _enableBuyExit.Value = value;
}
/// <summary>
/// Enable closing of long positions.
/// </summary>
public bool EnableSellExit
{
get => _enableSellExit.Value;
set => _enableSellExit.Value = value;
}
/// <summary>
/// Stop loss value in price units.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit value in price units.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="WprLevelCrossStrategy"/>.
/// </summary>
public WprLevelCrossStrategy()
{
_wprPeriod = Param(nameof(WprPeriod), 14)
.SetDisplay("WPR Period", "Lookback period for Williams %R", "Indicators")
.SetOptimize(10, 20, 2);
_highLevel = Param(nameof(HighLevel), -20m)
.SetDisplay("High Level", "Overbought threshold", "Indicators");
_lowLevel = Param(nameof(LowLevel), -80m)
.SetDisplay("Low Level", "Oversold threshold", "Indicators");
_trend = Param(nameof(Trend), TrendModes.Direct)
.SetDisplay("Trend Mode", "Direct - trade with indicator; Against - inverse signals", "General");
_enableBuyEntry = Param(nameof(EnableBuyEntry), true)
.SetDisplay("Enable Buy Entry", "Allow opening long positions", "Trading");
_enableSellEntry = Param(nameof(EnableSellEntry), true)
.SetDisplay("Enable Sell Entry", "Allow opening short positions", "Trading");
_enableBuyExit = Param(nameof(EnableBuyExit), true)
.SetDisplay("Enable Buy Exit", "Allow closing short positions", "Trading");
_enableSellExit = Param(nameof(EnableSellExit), true)
.SetDisplay("Enable Sell Exit", "Allow closing long positions", "Trading");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit in price units", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevWr = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var wpr = new WilliamsR { Length = WprPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(wpr, ProcessCandle).Start();
StartProtection(
new Unit(TakeProfit, UnitTypes.Absolute),
new Unit(StopLoss, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, wpr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal wr)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevWr == 0m)
{
_prevWr = wr;
return;
}
var crossedBelowLow = _prevWr > LowLevel && wr <= LowLevel;
var crossedAboveHigh = _prevWr < HighLevel && wr >= HighLevel;
if (Trend == TrendModes.Direct)
{
if (crossedBelowLow && EnableBuyEntry && Position <= 0)
BuyMarket();
if (crossedAboveHigh && EnableSellEntry && Position >= 0)
SellMarket();
}
else
{
if (crossedBelowLow && EnableSellEntry && Position >= 0)
SellMarket();
if (crossedAboveHigh && EnableBuyEntry && Position <= 0)
BuyMarket();
}
_prevWr = wr;
}
/// <summary>
/// Trend modes for interpreting Williams %R signals.
/// </summary>
public enum TrendModes
{
/// <summary>
/// Trade in the direction of indicator signals.
/// </summary>
Direct,
/// <summary>
/// Invert indicator signals for counter-trend trading.
/// </summary>
Against
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import WilliamsR
from StockSharp.Algo.Strategies import Strategy
class wpr_level_cross_strategy(Strategy):
DIRECT = 0
AGAINST = 1
def __init__(self):
super(wpr_level_cross_strategy, self).__init__()
self._wpr_period = self.Param("WprPeriod", 14)
self._high_level = self.Param("HighLevel", -20.0)
self._low_level = self.Param("LowLevel", -80.0)
self._trend = self.Param("Trend", 0)
self._enable_buy_entry = self.Param("EnableBuyEntry", True)
self._enable_sell_entry = self.Param("EnableSellEntry", True)
self._enable_buy_exit = self.Param("EnableBuyExit", True)
self._enable_sell_exit = self.Param("EnableSellExit", True)
self._stop_loss = self.Param("StopLoss", 1000.0)
self._take_profit = self.Param("TakeProfit", 2000.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._prev_wr = 0.0
@property
def WprPeriod(self):
return self._wpr_period.Value
@WprPeriod.setter
def WprPeriod(self, value):
self._wpr_period.Value = value
@property
def HighLevel(self):
return self._high_level.Value
@HighLevel.setter
def HighLevel(self, value):
self._high_level.Value = value
@property
def LowLevel(self):
return self._low_level.Value
@LowLevel.setter
def LowLevel(self, value):
self._low_level.Value = value
@property
def Trend(self):
return self._trend.Value
@Trend.setter
def Trend(self, value):
self._trend.Value = value
@property
def EnableBuyEntry(self):
return self._enable_buy_entry.Value
@EnableBuyEntry.setter
def EnableBuyEntry(self, value):
self._enable_buy_entry.Value = value
@property
def EnableSellEntry(self):
return self._enable_sell_entry.Value
@EnableSellEntry.setter
def EnableSellEntry(self, value):
self._enable_sell_entry.Value = value
@property
def EnableBuyExit(self):
return self._enable_buy_exit.Value
@EnableBuyExit.setter
def EnableBuyExit(self, value):
self._enable_buy_exit.Value = value
@property
def EnableSellExit(self):
return self._enable_sell_exit.Value
@EnableSellExit.setter
def EnableSellExit(self, value):
self._enable_sell_exit.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(wpr_level_cross_strategy, self).OnStarted2(time)
self._prev_wr = 0.0
wpr = WilliamsR()
wpr.Length = self.WprPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(wpr, self.ProcessCandle).Start()
self.StartProtection(
Unit(self.TakeProfit, UnitTypes.Absolute),
Unit(self.StopLoss, UnitTypes.Absolute))
def ProcessCandle(self, candle, wr_value):
if candle.State != CandleStates.Finished:
return
wr = float(wr_value)
if self._prev_wr == 0.0:
self._prev_wr = wr
return
crossed_below_low = self._prev_wr > float(self.LowLevel) and wr <= float(self.LowLevel)
crossed_above_high = self._prev_wr < float(self.HighLevel) and wr >= float(self.HighLevel)
if self.Trend == self.DIRECT:
if crossed_below_low and self.EnableBuyEntry and self.Position <= 0:
self.BuyMarket()
if crossed_above_high and self.EnableSellEntry and self.Position >= 0:
self.SellMarket()
else:
if crossed_below_low and self.EnableSellEntry and self.Position >= 0:
self.SellMarket()
if crossed_above_high and self.EnableBuyEntry and self.Position <= 0:
self.BuyMarket()
self._prev_wr = wr
def OnReseted(self):
super(wpr_level_cross_strategy, self).OnReseted()
self._prev_wr = 0.0
def CreateClone(self):
return wpr_level_cross_strategy()