Estratégia WPR de Cruzamento de Nível
Esta estratégia opera com base no oscilador Williams %R ao cruzar níveis predefinidos de sobrecompra e sobrevenda.
Quando o indicador cruza abaixo do Low Level, sinaliza uma possível reversão de uma condição de sobrevenda. Quando cruza acima do High Level, indica uma possível reversão de uma condição de sobrecompra. Dependendo do Trend Mode selecionado, a estratégia pode operar na direção do indicador ou inverter os sinais para negociação contra-tendência.
Parâmetros
WprPeriod– período de lookback para Williams %R.HighLevel– limite de sobrecompra.LowLevel– limite de sobrevenda.Trend–Directopera com os sinais do indicador,Againstos inverte.EnableBuyEntry/EnableSellEntry– permitir entrar em posições compradas/vendidas.EnableBuyExit/EnableSellExit– permitir fechar posições vendidas/compradas.StopLoss– valor do stop-loss em unidades de preço.TakeProfit– valor do take-profit em unidades de preço.CandleType– período dos candles usados para cálculos.
Como Funciona
- A estratégia subscreve candles e calcula o indicador Williams %R.
- Em cada candle concluído, verifica se o indicador cruzou os níveis especificados.
- Dependendo de
Trende das ações habilitadas, abre ou fecha posições usando ordens de mercado. - A proteção opcional de stop-loss e take-profit é ativada através de
StartProtection.
Notas
- Os comentários no código estão em inglês.
- Apenas a versão C# está implementada; a versão Python é omitida 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()