Uma barra externa ocorre quando o intervalo de uma vela excede o da vela anterior, criando um breve aumento de volatilidade. Esta estratégia opera contra o movimento se a barra externa fechar na direção oposta à tendência anterior, esperando um retorno ao equilíbrio.
Os testes indicam um retorno anual médio de aproximadamente 121%. Funciona melhor no mercado de criptomoedas.
Quando uma barra externa se forma, o algoritmo determina se a vela é de alta ou de baixa. Uma barra externa de alta após uma queda abre uma posição comprada com stop abaixo da mínima da barra. Uma barra externa de baixa após uma alta aciona uma posição vendida com stop acima de sua máxima. As operações são encerradas se o preço posteriormente romper esse extremo.
A configuração busca reversões rápidas após um impulso exaustivo e é melhor utilizada quando os mercados estão agitados em vez de seguirem uma tendência forte.
Detalhes
Critérios de entrada: Barra externa fechando em sentido oposto ao movimento anterior.
Comprado/Vendido: Ambos.
Critérios de saída: Preço rompendo a máxima/mínima da barra externa ou stop-loss.
Stops: Sim, colocados além do padrão.
Valores padrão:
CandleType = 5 minute
StopLossPercent = 1
Um stop de proteção a essa porcentagem do preço de entrada, vigiado também entre as velas; a posição também é fechada quando um fechamento rompe o extremo oposto da barra externa.
Filtros:
Categoria: Padrão
Direção: Ambos
Indicadores: Candlestick
Stops: Sim
Complexidade: Intermediário
Período: Intradiário
Sazonalidade: Não
Redes neurais: Não
Divergência: Não
Nível de risco: Médio
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Outside Bar Reversal strategy.
/// An outside bar's high and low both exceed the previous candle's. While flat, a bullish outside bar after a bearish candle buys
/// and a bearish one after a bullish candle sells. The position closes when a close breaks through the outside bar's opposite
/// extreme, and a percent stop from the entry price, watched between candles, limits the loss.
/// </summary>
public class OutsideBarReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _prevCandle;
private decimal _exitLevel;
/// <summary>
/// Stop-loss percentage from the entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type and timeframe.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public OutsideBarReversalStrategy()
{
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_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();
_prevCandle = null;
_exitLevel = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_exitLevel = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var previous = _prevCandle;
_prevCandle = candle;
if (previous == null || !IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close < _exitLevel)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (close > _exitLevel)
BuyMarket(-Position);
return;
}
var isOutsideBar = candle.HighPrice > previous.HighPrice && candle.LowPrice < previous.LowPrice;
if (!isOutsideBar)
return;
var afterDecline = previous.ClosePrice < previous.OpenPrice;
var afterRally = previous.ClosePrice > previous.OpenPrice;
if (close > candle.OpenPrice && afterDecline)
{
BuyMarket(Volume);
_exitLevel = candle.LowPrice;
}
else if (close < candle.OpenPrice && afterRally)
{
SellMarket(Volume);
_exitLevel = candle.HighPrice;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class outside_bar_reversal_strategy(Strategy):
"""
Outside Bar Reversal strategy.
An outside bar's high and low both exceed the previous candle's. While flat, a bullish outside bar after a bearish candle buys
and a bearish one after a bullish candle sells. The position closes when a close breaks through the outside bar's opposite
extreme, and a percent stop from the entry price, watched between candles, limits the loss.
"""
def __init__(self):
super(outside_bar_reversal_strategy, self).__init__()
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_candle = None
self._exit_level = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(outside_bar_reversal_strategy, self).OnReseted()
self._prev_candle = None
self._exit_level = Decimal(0)
def OnStarted2(self, time):
super(outside_bar_reversal_strategy, self).OnStarted2(time)
self._prev_candle = None
self._exit_level = Decimal(0)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
previous = self._prev_candle
self._prev_candle = candle
if previous is None or not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if self.Position > 0:
if close < self._exit_level:
self.SellMarket(self.Position)
return
if self.Position < 0:
if close > self._exit_level:
self.BuyMarket(-self.Position)
return
is_outside_bar = candle.HighPrice > previous.HighPrice and candle.LowPrice < previous.LowPrice
if not is_outside_bar:
return
after_decline = previous.ClosePrice < previous.OpenPrice
after_rally = previous.ClosePrice > previous.OpenPrice
if close > candle.OpenPrice and after_decline:
self.BuyMarket(self.Volume)
self._exit_level = candle.LowPrice
elif close < candle.OpenPrice and after_rally:
self.SellMarket(self.Volume)
self._exit_level = candle.HighPrice
def CreateClone(self):
return outside_bar_reversal_strategy()