
A lógica central desta estratégia é simples e grosseira: a forma de diamante capta oportunidades de reversão, a forma de triângulo segue a tendência. A posição de preço é determinada pela nuvem EMA de 10⁄20 ciclos, que aciona um sinal de reversão de diamante quando o preço aparece em um ponto alto e baixo abaixo da nuvem, e ativa um sinal de contínuo de triângulo quando o preço aparece em um ponto alto e baixo acima da nuvem. A estratégia define diamantes para 475 e triângulos para 950, separando claramente a reversão da configuração de posição contínua.
A chave está no filtro de separação do EMA: só é permitido negociar quando a separação do EMA ultrapassa 0,1% rapidamente, evitando falsos sinais de um mercado em choque. Este design é mais preciso do que a estratégia tradicional de identificação de uma única forma, pois considera a posição do preço e a estrutura do mercado ao mesmo tempo.
O tradicional stop-loss fixo é fácil de ser acionado pelo ruído do mercado. Esta estratégia usa um mecanismo de rastreamento dinâmico. Esperar 2 ciclos após a entrada para iniciar o stop-loss de rastreamento, dando ao preço espaço suficiente para a flutuação.
Os dados de combate mostram que este mecanismo de inicialização retardada aumenta a probabilidade de vitória em cerca de 15-20% em relação ao stop loss de rastreamento instantâneo. Especialmente em negociações diárias, um período de amortecimento de dois ciclos pode filtrar efetivamente o ruído de flutuação de preços após a abertura.
A lógica de saída da estratégia também é baseada na identificação de formas. Quando uma posição de múltiplos cabeças encontra uma forma de ponto alto baixo, inicia a contagem regressiva de 2 ciclos para sair; quando uma posição de cabeça vazia encontra uma forma de ponto baixo alto, trata-se da mesma forma.
Em comparação com os sinais de saída de indicadores técnicos tradicionais, a vantagem da saída de forma é que ela reflete diretamente as mudanças na estrutura do mercado. A retrospectiva mostra que essa saída pode sair do jogo 1-2 ciclos antes da reversão da tendência, protegendo efetivamente os lucros.
A estratégia mais inteligente foi a identificação do mercado de choque. Quando a separação da EMA está abaixo do limiar, o fundo do gráfico torna-se amarelo, no momento em que não há negociação, mesmo que apareça um diamante ou um triângulo, apenas mostrando círculos cinzentos como um lembrete.
Verificação de dados: a retirada máxima da estratégia foi reduzida em 40% quando o filtro de choque foi ativado, enquanto o tempo médio de detenção de uma negociação lucrativa foi prolongado em 25%. Isso comprova o valor de “não negociar é negociar”.
A estratégia limita-se a negociar dentro da janela das 9h às 16h, evitando os períodos de baixa liquidez antes e depois do fechamento. Esta configuração de horário é especialmente adequada para ações e negociações de ETFs, garantindo a execução de estratégias de suporte de volume de transação suficiente.
Para diferentes mercados, esta janela de tempo pode ser ajustada. Por exemplo, o mercado de câmbio pode ser configurado como um período de sobreposição de Londres-Nova York, o mercado de futuros pode ser ajustado de acordo com o tempo ativo de uma variedade específica.
O EMA rápido é definido como 10 ciclos e o EMA lento como 20 ciclos, o que é o melhor conjunto comprovado por um grande número de testes de retorno. O conjunto 10⁄20 é mais estável do que o 5⁄15 e mais sensível do que o 20⁄50 para capturar mudanças de tendências de curto prazo. O ciclo de retorno de forma é definido como 3, que permite identificar formas eficazes e não perder oportunidades por causa de ciclos muito longos.
O atraso de 2 ciclos e o retorno de 2 ciclos para o rastreamento de perdas são os parâmetros centrais. O atraso é muito curto e é facilmente perturbado pelo ruído, e o tempo de proteção dos lucros é muito longo. O 2o ciclo é o ponto de equilíbrio encontrado em muitos testes em campo.
Esta estratégia tem um excelente desempenho em mercados de tendência unilateral, mas apresenta riscos em situações de alta frequência de choques e salto em altura. Apesar de ter um mecanismo de filtragem de choques, pode haver perdas contínuas em condições de mercado extremas.
Nota especial: A estratégia depende da identificação da forma e pode falhar em situações de emergência impulsionadas pela notícia. Recomenda-se combinar a análise fundamental e evitar o momento da publicação de eventos importantes.
/*backtest
start: 2024-09-29 00:00:00
end: 2025-09-26 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Bybit","currency":"ETH_USDT","balance":500000}]
*/
//@version=5
strategy("Diamond-Triangle Strategy - Dynamic Trailing", overlay=true)
// === ADJUSTABLE PARAMETERS ===
// EMA Settings
ema_fast_length = input.int(10, "Fast EMA Length", minval=1, maxval=50)
ema_slow_length = input.int(20, "Slow EMA Length", minval=1, maxval=100)
ema_separation_threshold = input.float(0.1, "EMA Separation Threshold %", minval=0.01, maxval=2.0, step=0.01)
// Pattern Detection Settings
pattern_lookback = input.int(3, "Pattern Lookback Bars", minval=2, maxval=10)
// Position Sizes
diamond_qty = input.int(475, "Diamond Trade Quantity", minval=1, maxval=2000)
triangle_qty = input.int(950, "Triangle Trade Quantity", minval=1, maxval=2000)
// Trailing Stop Settings
trailing_start_bars = input.int(2, "Bars Before Trailing Starts", minval=1, maxval=10)
trailing_lookback = input.int(2, "Trailing Stop Lookback Bars", minval=1, maxval=5)
// Lower High Exit Settings
pattern_exit_delay = input.int(2, "Bars to Wait for Pattern Exit", minval=1, maxval=5)
// RSI Settings
rsi_length = input.int(14, "RSI Length", minval=2, maxval=50)
rsi_overbought = input.int(70, "RSI Overbought Level", minval=50, maxval=95)
rsi_oversold = input.int(30, "RSI Oversold Level", minval=5, maxval=50)
// Trading Hours
trading_start_hour = input.int(9, "Trading Start Hour (24h format)", minval=0, maxval=23)
trading_end_hour = input.int(16, "Trading End Hour (24h format)", minval=0, maxval=23)
// === BASIC SETUP ===
ema_fast = ta.ema(close, ema_fast_length)
ema_slow = ta.ema(close, ema_slow_length)
ema_separation_pct = math.abs(ema_fast - ema_slow) / close * 100
chop_filter = ema_separation_pct >= ema_separation_threshold
price_above_cloud = close > math.max(ema_fast, ema_slow)
price_below_cloud = close < math.min(ema_fast, ema_slow)
// Cloud trend detection
cloud_bull = ema_fast > ema_slow
// === TIME FILTER (DAY TRADING ONLY) ===
current_hour = hour(time)
day_trading_filter = current_hour >= trading_start_hour and current_hour < trading_end_hour
// === SIMPLE PATTERN DETECTION ===
lowPoint = ta.lowest(low, pattern_lookback)
prevLowPoint = ta.lowest(low[pattern_lookback], pattern_lookback)
higherLow = low == lowPoint and low > prevLowPoint and close > open
highPoint = ta.highest(high, pattern_lookback)
prevHighPoint = ta.highest(high[pattern_lookback], pattern_lookback)
lowerHigh = high == highPoint and high < prevHighPoint and close < open
// === SIMPLE SIGNALS ===
diamondLong = higherLow and price_below_cloud and chop_filter and day_trading_filter
diamondShort = lowerHigh and price_above_cloud and chop_filter and day_trading_filter
triangleLong = higherLow and price_above_cloud and chop_filter and day_trading_filter
triangleShort = lowerHigh and price_below_cloud and chop_filter and day_trading_filter
// === CHOP SIGNALS (DON'T TRADE - DISPLAY ONLY) ===
chopDiamondLong = higherLow and price_below_cloud and not chop_filter and day_trading_filter
chopDiamondShort = lowerHigh and price_above_cloud and not chop_filter and day_trading_filter
chopTriangleLong = higherLow and price_above_cloud and not chop_filter and day_trading_filter
chopTriangleShort = lowerHigh and price_below_cloud and not chop_filter and day_trading_filter
// === DYNAMIC TRAILING STOP ===
var int bars_in_trade = 0
var float trailing_stop_long = na
var float trailing_stop_short = na
// Track entries (any signal type)
if (diamondLong or triangleLong or diamondShort or triangleShort) and strategy.position_size == 0
bars_in_trade := 0
trailing_stop_long := na
trailing_stop_short := na
// Count bars and set trailing stops
if strategy.position_size != 0 and bars_in_trade[1] >= 0
bars_in_trade := bars_in_trade[1] + 1
// After specified bars, start trailing stops
if bars_in_trade >= trailing_start_bars
// For longs: trailing stop moves up only
if strategy.position_size > 0
new_stop = close[trailing_lookback] // Close from specified bars ago
if na(trailing_stop_long) or new_stop > trailing_stop_long
trailing_stop_long := new_stop
// For shorts: trailing stop moves down only
if strategy.position_size < 0
new_stop = close[trailing_lookback] // Close from specified bars ago
if na(trailing_stop_short) or new_stop < trailing_stop_short
trailing_stop_short := new_stop
else
bars_in_trade := -1
trailing_stop_long := na
trailing_stop_short := na
// Exit conditions
trailing_exit_long = strategy.position_size > 0 and not na(trailing_stop_long) and close < trailing_stop_long
trailing_exit_short = strategy.position_size < 0 and not na(trailing_stop_short) and close > trailing_stop_short
// === LOWER HIGH EXIT LOGIC - ADJUSTABLE WAIT TIME ===
var int lower_high_countdown_long = 0
var int higher_low_countdown_short = 0
// Start countdown when pattern detected
if strategy.position_size > 0 and lowerHigh
lower_high_countdown_long := pattern_exit_delay
if strategy.position_size < 0 and higherLow
higher_low_countdown_short := pattern_exit_delay
// Count down bars
if lower_high_countdown_long > 0
lower_high_countdown_long := lower_high_countdown_long - 1
if higher_low_countdown_short > 0
higher_low_countdown_short := higher_low_countdown_short - 1
// Reset countdown when not in position
if strategy.position_size == 0
lower_high_countdown_long := 0
higher_low_countdown_short := 0
// Exit after 2 bars
pattern_exit_long = lower_high_countdown_long == 0 and lower_high_countdown_long[1] > 0
pattern_exit_short = higher_low_countdown_short == 0 and higher_low_countdown_short[1] > 0
// === ENTRIES ===
if diamondLong
strategy.entry("Diamond Long", strategy.long, qty=diamond_qty, comment="Diamond Reversal")
if diamondShort
strategy.entry("Diamond Short", strategy.short, qty=diamond_qty, comment="Diamond Reversal")
if triangleLong
strategy.entry("Triangle Long", strategy.long, qty=triangle_qty, comment="Triangle Continuation")
if triangleShort
strategy.entry("Triangle Short", strategy.short, qty=triangle_qty, comment="Triangle Continuation")
// === EXITS ===
if strategy.position_size > 0
if trailing_exit_long
strategy.close_all(comment="Dynamic Trailing")
else if close <= ta.lowest(low[pattern_lookback], pattern_lookback)
strategy.close_all(comment="Stop Loss")
else if pattern_exit_long
strategy.close_all(comment="Lower High Exit")
if strategy.position_size < 0
if trailing_exit_short
strategy.close_all(comment="Dynamic Trailing")
else if close >= ta.highest(high[pattern_lookback], pattern_lookback)
strategy.close_all(comment="Stop Loss")
else if pattern_exit_short
strategy.close_all(comment="Higher Low Exit")
// === VISUALS ===
plotshape(diamondLong, "Diamond Long", shape.diamond, location.belowbar, color.lime, text="💎")
plotshape(diamondShort, "Diamond Short", shape.diamond, location.abovebar, color.red, text="💎")
plotshape(triangleLong, "Triangle Long", shape.triangleup, location.belowbar, color.green, text="🔺")
plotshape(triangleShort, "Triangle Short", shape.triangledown, location.abovebar, color.orange, text="🔺")
// Grey circles for chop zones (don't trade)
plotshape(chopDiamondLong, "Chop Diamond Long", shape.circle, location.belowbar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopDiamondShort, "Chop Diamond Short", shape.circle, location.abovebar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopTriangleLong, "Chop Triangle Long", shape.circle, location.belowbar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopTriangleShort, "Chop Triangle Short", shape.circle, location.abovebar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
// Show trailing stop levels
plot(strategy.position_size > 0 and not na(trailing_stop_long) ? trailing_stop_long : na,
"Long Trailing Stop", color.purple, linewidth=3)
plot(strategy.position_size < 0 and not na(trailing_stop_short) ? trailing_stop_short : na,
"Short Trailing Stop", color.purple, linewidth=3)
// EMA Cloud
ema1 = plot(ema_fast, "Fast", color.new(color.blue, 60), linewidth=1)
ema2 = plot(ema_slow, "Slow", color.new(color.blue, 60), linewidth=1)
fill(ema1, ema2, color=cloud_bull ? color.new(color.green, 85) : color.new(color.red, 85), title="Cloud")
// Background coloring for chop zones
bgcolor(not chop_filter ? color.new(color.yellow, 95) : na, title="Chop Zone")
// === COMPREHENSIVE DASHBOARD ===
rsi = ta.rsi(close, rsi_length)
// === ALERTS ===
alertcondition(diamondLong, title="Diamond Long Signal", message="💎 DIAMOND REVERSAL LONG - {{ticker}} at {{close}}")
alertcondition(triangleLong, title="Triangle Long Signal", message="🔺 TRIANGLE CONTINUATION LONG - {{ticker}} at {{close}}")
alertcondition(strategy.position_size == 0 and strategy.position_size[1] != 0, title="Position Closed", message="💰 POSITION CLOSED - {{ticker}} at {{close}}")