O BOS (Rompimento de Estrutura) é um conceito do Smart Money Concepts (SMC) que identifica quando o preço rompe um ponto significativo.
Podendo sinalizar continuação do movimento ou reversão de tendência.
⚠️ Nota: Este backtest opera na continuação:
- Quando rompe um topo local, compramos esperando que continue subindo;
- Quando rompe um fundo local, vendemos esperando que continue caindo.
📍 Topos e Fundos Locais
O preço nunca se move em linha reta - normalmente se move em zigue-zague, criando topos e fundos:
| Termo | Descrição |
|---|---|
| Topo Local | Candle com máxima superior às máximas dos candles vizinhos |
| Fundo Local | Candle com mínima inferior às mínimas dos candles vizinhos |
<br>
📈 Estrutura de Mercado
Nada mais é do que a tendência de mercado, onde esses topos e fundos indicam a direção geral do preço.
| Tendência | Estrutura |
|---|---|
| ⬆️ Alta | Topos mais altos & Fundos mais altos |
| ⬇️ Baixa | Topos mais baixos & Fundos mais baixos |
O BOS ocorre quando o preço rompe um topo ou fundo local, por tanto, sinalizando rompimento de estrutura.
Nós iremos interpretar o BOS como uma continuação ou reversão de tendência, dependendo da nossa estratégia.
1️⃣ Detecta Topos e Fundos Locais
Topo local: se a máxima do candle for a maior entre ele e seus vizinhos.
Fundo local se a mínima do candle for a menor entre ele e seus vizinhos.
TopoLocal = Maxima[n] é a maior dos últimos (2n + 1) candles FundoLocal = Minima[n] é a menor dos últimos (2n + 1) candles
n candles de cada lado, totalizando uma janela de (2n + 1) candles.<br>
2️⃣ Armazena último topo/fundo confirmado
Quando um topo ou fundo local é detectado, guardamos seu preço para comparação futura.
Se TopoLocal detectado → UltimoTopoLocal := Maxima[n] Se FundoLocal detectado → UltimoFundoLocal := Minima[n]
<br>
3️⃣ Detecta BOS (Rompimento de Estrutura)
O BOS ocorre quando o fechamento atual cruza o último extremo, mas o fechamento anterior ainda não havia cruzado.
BOS Alta = Fechamento > UltimoTopoLocal E Fechamento[1] <= UltimoTopoLocal BOS Baixa = Fechamento < UltimoFundoLocal E Fechamento[1] >= UltimoFundoLocal
<br>
4️⃣ Executa entrada com gestão de risco
Ao detectar um BOS, entra na operação calculando stop e alvo baseados no ATR (ver seção Gestão de Risco).
| Parâmetro | Padrão | Descrição |
|---|---|---|
| PeriodoLocal | 5 | Candles para confirmar topo/fundo local (cada lado) |
| PeriodoATR | 14 | Período do ATR para cálculo de volatilidade |
| FatorStop | 2.0 | Multiplicador do ATR para stop loss |
| FatorAlvo | 2.0 | Multiplicador do risco para alvo (risco:retorno) |
// ============================================
// BACKTEST DE ROMPIMENTO DE ESTRUTURA (BOS)
// Opera continuação na direção do rompimento
// ============================================
parametro
PeriodoLocal(5); // Candles para confirmar topo/fundo (cada lado)
PeriodoATR(14); // Período do ATR
FatorStop(2.0); // Fator ATR para stop
FatorAlvo(2.0); // Fator do risco para alvo
var
ultimoTopoLocal, ultimoFundoLocal : real;
ehTopoLocal, ehFundoLocal : booleano;
bosAlta, bosBaixa : booleano;
valorATR, stopLoss, takeProfit, risco, offset : real;
janelaLocal, t, d : inteiro;
inicio
// ========== ATR PARA STOPS DINÂMICOS ==========
valorATR := AvgTrueRange(PeriodoATR, 0);
janelaLocal := 2 * PeriodoLocal + 1;
// ========== IDENTIFICAÇÃO DE TOPO LOCAL ==========
// Topo Local: a máxima do candle central é a maior da janela
ehTopoLocal := Maxima[PeriodoLocal] >= Highest(Maxima, janelaLocal);
se ehTopoLocal entao
ultimoTopoLocal := Maxima[PeriodoLocal];
// ========== IDENTIFICAÇÃO DE FUNDO LOCAL ==========
// Fundo Local: a mínima do candle central é a menor da janela
ehFundoLocal := Minima[PeriodoLocal] <= Lowest(Minima, janelaLocal);
se ehFundoLocal entao
ultimoFundoLocal := Minima[PeriodoLocal];
// ========== DETECÇÃO DE BOS ==========
bosAlta := (Fechamento > ultimoTopoLocal) e (Fechamento[1] <= ultimoTopoLocal);
bosBaixa := (Fechamento < ultimoFundoLocal) e (Fechamento[1] >= ultimoFundoLocal);
// ========== ENTRADA NA COMPRA (BOS ALTA) ==========
se bosAlta e nao(HasPosition) e (CurrentBar >= PeriodoATR) entao
inicio
risco := valorATR * FatorStop;
offset := valorATR * 0.1;
stopLoss := Fechamento - risco;
takeProfit := Fechamento + (risco * FatorAlvo);
BuyAtMarket;
ultimoTopoLocal := -1;
fim;
// ========== ENTRADA NA VENDA (BOS BAIXA) ==========
se bosBaixa e nao(HasPosition) e (CurrentBar >= PeriodoATR) entao
inicio
risco := valorATR * FatorStop;
offset := valorATR * 0.1;
stopLoss := Fechamento + risco;
takeProfit := Fechamento - (risco * FatorAlvo);
SellShortAtMarket;
ultimoFundoLocal := -1;
fim;
// ========== SAÍDA DA COMPRA ==========
se IsBought entao
inicio
SellToCoverStop(stopLoss, stopLoss - offset);
SellToCoverLimit(takeProfit);
fim;
// ========== SAÍDA DA VENDA ==========
se IsSold entao
inicio
BuyToCoverStop(stopLoss, stopLoss + offset);
BuyToCoverLimit(takeProfit);
fim;
// ========== PLOTAGENS ==========
se bosAlta entao
PlotText("BOS", clVerdeLimao, 0, 14);
se bosBaixa entao
PlotText("BOS", clVermelho, 0, 14);
d := Date[PeriodoLocal*2];
t := Time[PeriodoLocal*2];
se ehTopoLocal entao
inicio
HorizontalLineCustom(ultimoTopoLocal, clVerdeLimao, 1, 0, "", 14, 0, d, Date, 0, t, Time);
// PlotText("T", clVerdeLimao, 2, 14);
fim;
se ehFundoLocal entao
inicio
HorizontalLineCustom(ultimoFundoLocal, clVermelho, 1, 0, "", 14, 0, d, Date, 0, t, Time);
// PlotText("F", clVermelho, 0, 14);
fim;
fim;
Usamos o ATR (Average True Range) para calcular stop, alvo e offset de forma dinâmica, adaptando-se à volatilidade do ativo.
Por que ATR?
Como calculamos:
| Variável | Cálculo | Descrição |
|---|---|---|
| Risco | ATR × FatorStop | Distância do stop em pontos |
| Stop | Entrada ± Risco | Preço de acionamento do stop |
| Alvo | Entrada ± (Risco × FatorAlvo) | Take profit baseado no risco |
| Offset | ATR × 0.1 | Margem entre gatilho e execução do stop |
Por que o offset?
Em ordens de stop temos dois preços:
Se forem iguais, em mercados voláteis ou com gaps a ordem pode não ser executada. O offset garante execução mesmo com slippage.
ChoCH (Mudança de Caráter)
ChoCH é quando o BOS indica mudança de tendência:
Para filtrar apenas ChoCH, seria necessário:
Isso adiciona complexidade, mas pode melhorar a precisão dos sinais.