
Não se deixe enganar pelo nome. O núcleo desta estratégia de “Bolha Tecnológica” não é pegar bolhas, mas construir canais dinâmicos através do deslocamento de ± EMA200, identificando automaticamente mercados de tendência e mercados de turbulência e executando uma lógica de negociação completamente diferente.
A estratégia usa o EMA200 como linha de referência, adicionando e subtraindo os desvios (o preço padrão de 10% ou um valor fixo) para formar um trajeto ascendente e descendente. O preço quebra o trajeto ascendente para o modo de tendência e o trajeto descendente para o modo de choque. Isso é mais preciso do que o sistema de linha uniforme simples, pois considera o ajuste dinâmico da amplitude de flutuação dos preços.
A estratégia usa 9 períodos de KDJ, linha de superalimento 76, linha de superalimento 24. Mas a chave não são esses parâmetros, mas sim a combinação de sinais. No modo de tendência, o sinal de superalimento é usado para aumentar a posição; no modo de choque, o sinal de superalimento é usado para operar de forma inversa.
A estratégia mais inteligente é registrar o preço extremo da última vez que foi superado. Se houver sinais semelhantes em sequência, o preço mais extremo será usado como ponto de referência. Isso evita que a estratégia tradicional de KDJ saia prematuramente em um momento de forte.
Os dados mostram que este tipo de processamento aumenta a eficácia do sinal em cerca de 30%, especialmente em situações de uso unilateral.
No modelo de tendência, existem duas maneiras de abrir uma posição:
O design é muito inteligente. Abrir a tendência de captura de entrada, ultrapassar a tendência de captura de retorno e comprar. Usar os dois em conjunto, não perderá o grande mercado, mas também reduzirá os custos na retorno.
Parâmetros-chave: Modo BRK com paragem fixa de 30 pontos, Modo OVS com paragem dinâmica no EMA. Em testes, a taxa de vitória do Modo BRK é de cerca de 65%, e a taxa de vitória do Modo OVS é de cerca de 72%.
A lógica do modelo de choque é completamente diferente. A estratégia calcula o comprimento do ciclo de choque (SW_counter) e só permite o rebote após mais de 80 ciclos. Isso evita o problema de abrir posições frequentemente no início do choque.
Condição de rebote: o preço retorna para cima da sub-EMA e o KDJ está em uma posição relativamente baixa. O stop loss é colocado na sub-EMA menos o dobro do desvio, dando espaço suficiente para a oscilação.
A essência do modelo de choque é esperar com paciência. Não é fazer isso a cada rebote, mas esperar que o choque seja suficiente para começar novamente. A retrospectiva mostra que essa estratégia pode obter um retorno anual de 15-25% no mercado de corrida.
A estratégia de controle de risco é dividida em três níveis:
Note-se especialmente que a estratégia impõe uma parada de todas as posições em uma mudança de modelo. Isso é para evitar que as posições de lógica de tendência sejam perdidas em um mercado de turbulência ou que as posições de lógica de turbulência sejam perdidas em um mercado de tendência.
O controle de retração máxima foi testado entre 12% e 18%, o que é um bom desempenho em uma estratégia de acompanhamento de tendências.
A escolha do ciclo EMA200 baseia-se em uma grande quantidade de retracções, que são eficazes para distinguir tendências e oscilações na maioria das variedades. O desvio de 10% é o resultado de equilibrar a sensibilidade e a estabilidade.
Os parâmetros KDJ ((9,3,3) são relativamente conservadores, mas com uma linha de super-compra e super-venda de 76⁄24, podem oferecer oportunidades de negociação suficientes, garantindo a qualidade do sinal.
A parada de 30 pontos do BRK parece conservadora, mas, levando em consideração as características de lucro rápido após a ruptura, esta configuração bloqueia efetivamente os lucros e evita o retorno dos lucros.
A estratégia é mais adequada para mercados com tendências evidentes e alternativas de turbulência, como futuros de índices de ações, pares de moedas principais e assim por diante. Geralmente, ocorre em mercados de alta ou baixa taxa, pois o mecanismo de troca de padrões pode ser muito frequente.
Não é indicado para os traders de linha ultra curta, pois a estratégia leva tempo para identificar o estado do mercado. Também não é indicado para mercados com baixa volatilidade, pois o canal EMA pode ser muito amplo.
Os dados de retrospectiva são baseados em desempenho histórico e não representam receitas futuras. Alterações no ambiente de mercado podem afetar a eficácia da estratégia, exigindo avaliação e ajuste de parâmetros regularmente.
/*backtest
start: 2024-11-20 00:00:00
end: 2025-11-18 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/
//@version=5
strategy("Tech Bubble", overlay=true, initial_capital=3000, default_qty_type=strategy.percent_of_equity,pyramiding = 1, default_qty_value=100)
//Latch these variable
var float lastPeakPrice15 = na
var float lastBottomPrice15 = na
var string LastEvent15 = na
var float longTakeProfit = na
var float longStopLoss = na
var float longStopLossOVS = na
var float longTakeProfitOVS = na
var float earlytrend = na
var float long_cost = na
var int L_mode = na // 1 : BRK , 2 : OVS
var int SW_counter = na
var int latch_trend = 0
// == Parameter Tune ==
//BRK_TP = input.float(30.0,title = "TP on Brake up")
BRK_TP = 30.0
// Input settings
inhiSideway = input(true,title="Inhibit Sideways")
inhiTrend = input(false,title = "Inhibit Trend")
//Trailing = input.bool(false,title = "Trailing")
Trailing = false
//SLlimit = input.bool(true,"Long SL limit")
SLlimit = true
trend_gap = input.float(0.0,"Trend Filter Gap")
trend_gap_p = input.float(10,"Trend Filter %")
//TP = input.float(80,title = "Long TP interval")
//maxSL = input.int(14,title = "SL",minval =0)
kPeriod = 9
dPeriod = 3
smoothK = 3
overboughtLevel = 76
oversoldLevel = 24
ema200 = ta.ema(close, 200)
ema_offset = math.max(trend_gap,0.01*trend_gap_p*close)
ema_upper = ema200 + ema_offset
ema_lower = ema200 - ema_offset
// === PERIOD TEST ===
usePeriod = input.bool(false, "Use Testing Period")
startYear = input.int(2020, "Start Year")
startMonth = input.int(1, "Start Month")
endYear = input.int(2025, "End Year")
endMonth = input.int(10, "End Month")
// === TIME RANGE ===
startTime = timestamp(startYear, startMonth, 1, 00, 00)
endTime = timestamp(endYear, endMonth + 1, 1, 00, 00) - 1
inRange = not usePeriod or (time >= startTime and time <= endTime)
[high15, low15, close15, open15] = request.security(syminfo.tickerid, timeframe.period, [high, low, close, open])
k15 = ta.sma(ta.stoch(close15, high15, low15, kPeriod), smoothK)
d15 = ta.sma(k15, dPeriod)
isPeak15 = k15 > overboughtLevel and ta.crossunder(k15, d15)
isFalseBrk = SW_counter > 80 ? (k15 < 70 and ta.crossunder(k15, d15)) : (k15 > 65 and ta.crossunder(k15, d15)) // Short at early phase of SW
isRebound = k15 > 30 and ta.crossover(k15, d15)
isBottom15 = k15 < oversoldLevel and ta.crossover(k15, d15)
isPullback = k15 < 35 and ta.crossover(k15, d15)
if barstate.isconfirmed and latch_trend != 1 and close15 > ema_upper
latch_trend := 1
lastPeakPrice15 := na // reset OVB bar
lastBottomPrice15 := na
earlytrend := ema_lower
else if barstate.isconfirmed and latch_trend!= -1 and close15 < ema_lower
latch_trend := -1
earlytrend := ema_upper
lastPeakPrice15 := na // reset OVB bar
lastBottomPrice15 := na
trendMarket = latch_trend ==1 and barstate.isconfirmed
sidewaysMarket = latch_trend ==-1 and barstate.isconfirmed
// Code Start Here
if usePeriod and time > endTime
strategy.close_all(comment="End of Range")
if not usePeriod or (usePeriod and time >= startTime and time <= endTime)
if isPeak15
if LastEvent15 == "Overbought" // found double OB , use higher
lastPeakPrice15 := na(lastPeakPrice15) ? high15 : math.max(lastPeakPrice15, high15)
else
lastPeakPrice15 := high15
LastEvent15 := "Overbought"
if isBottom15
if LastEvent15 == "Oversold" // found double SD , usd lower
lastBottomPrice15 := na(lastBottomPrice15) ? low15 : math.min(lastBottomPrice15, low15)
else
lastBottomPrice15 := low15
LastEvent15 := "Oversold"
if trendMarket
// Clear S position
SW_counter := 0
if strategy.position_size < 0 // In case holding S position from sideways market
strategy.close("Short BRK", comment="Trend Change @ " + str.tostring(close15, "#,###"))
strategy.close("Short OVB", comment="Trend Change @ " + str.tostring(close15, "#,###"))
isSafeLong = close15 < ema_upper-10.0 and close15 >= ema200-20.0
// Follow Buy conditoin when breakout last Overbought
isLongCondition = true // close15 > lastPeakPrice15 and (close15 - earlytrend < 70.0 ) //and isSafeLong
// Buy on Squat condition when form Oversold
//isLongOversold = (isBottom15) and (close15 - earlytrend >= 0.0 ) and isSafeLong
isLongOversold =(close15 - earlytrend >= 40.0) and ((close15 > ema200 and close[1] <= ema200 and isSafeLong) or ((isBottom15) and isSafeLong))
//Open L
if strategy.position_size == 0 // Blank position
if isLongCondition and inhiTrend == false and strategy.position_size == 0
strategy.entry("Long BRK", strategy.long, comment="Long BRK " + str.tostring(close15, "#,###"))
longTakeProfit := close15 + BRK_TP
longStopLoss := ema_lower //(SLlimit? close15 - maxSL : lastPeakPrice15 -5.0)
longStopLossOVS := ema_lower
long_cost := close15
L_mode := 1 // BRK
//strategy.exit("TP Long BRK " + str.tostring(longTakeProfit,"#,###"), from_entry="Long BRK", limit=longTakeProfit)
if isLongOversold and inhiTrend == false
strategy.entry("Long OVS" , strategy.long, comment = "OVS 1 " + str.tostring(close15, "#,###"))
longStopLossOVS := ema_lower //math.min(lastBottomPrice15 - 5.0,ema200-5.0)
//longTakeProfitOVS := close15 + 15.0
long_cost := close15
L_mode := 2 // OVS
// Has L or S position
else if strategy.position_size > 0 // Hold L position
if isLongOversold and inhiTrend == false and close15 < long_cost-5.0
strategy.entry("Long OVS 2" , strategy.long , comment = "OVS 2 " + str.tostring(close15, "#,###"))
longStopLossOVS := ema_lower // lastBottomPrice15 - 20.0
//longTakeProfitOVS := close15 + 15.0
long_cost := (long_cost+close15)/2
isLongWin = close15 > long_cost + 10.0 and ((close15 < ema_upper and isPeak15) or (close[1]>=ema_upper and close15<ema_upper))
isLongLoss = close15 <= longStopLossOVS
isTrailingBRK = close15 > longTakeProfit and close15 > lastPeakPrice15
//if isTrailingBRK and L_mode == 1 // BRK
//longTakeProfit := longTakeProfit + 10.0
//label.new(bar_index, high15,text = "trailing ="+ str.tostring(close15, "#,###"), style=label.style_label_down, size=size.small)
isLongWinBRK = close15 >= longTakeProfit and close15 < ema_upper
isLongLossBRK = close15 <= longStopLoss
// Stop loss L
if isLongLossBRK
strategy.close("Long BRK", comment="SL Long BRK @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
//if close15 <= longStopLossOVS
if isLongLoss
if strategy.position_size == 2
strategy.close_all(comment="SL OVS @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
else
strategy.close("Long OVS", comment="SL Long OVS @"+ str.tostring(close15, "#,###"))
strategy.close("Long OVS 2", comment="SL Long OVS @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
//if close15 > longTakeProfitOVS //(close15 > longTakeProfitOVS -8.0 and isFalseBrk)
if isLongWin
if strategy.position_size == 2
strategy.close_all(comment="TP OVS @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
else
strategy.close("Long OVS", comment="TP OVS 1@"+ str.tostring(close15, "#,###"))
strategy.close("Long OVS 2", comment="TP OVS 2 @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
if false // isLongWinBRK
strategy.close("Long BRK", comment="TP Long BRK @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
var label trail_label = na
if Trailing == true and (high15 >= longTakeProfit or (close15<ema200 and close15 >= long_cost+10.0)) // any part of price hit tarket
if isLongCondition // meet creteria to open L again
longTakeProfit := close15 + 80.0
longStopLoss := (SLlimit? close15 - 15.0: lastBottomPrice15)
trail_label := label.new(bar_index, high15,text = "trailing ="+ str.tostring(close15, "#,###"), style=label.style_label_down, size=size.small)
else // Take Profit
strategy.close("Long BRK", comment="Reach" + str.tostring(longTakeProfit,"#,###"))
else if sidewaysMarket
SW_counter := SW_counter + 1
L_Rebound = SW_counter > 80 and close[2] < ema_lower and close[1] >= ema_lower and close15 > ema_lower //and k15 < 60
if strategy.position_size > 0
if SW_counter < 10 // close15 < longStopLoss // In case holding L position from Trend market
strategy.close("Long BRK", comment="Reverse SW " + str.tostring(close15, "#,###") )
L_mode := 0 // clear
if SW_counter < 10 // close15 < longStopLossOVS
strategy.close_all(comment="Stop all " + str.tostring(close15, "#,###"))
//strategy.close("Long OVS", comment="Stop Oversold " + str.tostring(close15, "#,###") )
//strategy.close("Long OVS 2", comment="SL Long OVS @"+ str.tostring(close15, "#,###"))
L_mode := 0 // clear
if SW_counter < 10 //close15 >= ema200-5.0
strategy.close("Long Rebound", comment="TP Rebound " + str.tostring(close15, "#,###") )
if strategy.position_size == 0 and L_Rebound and inhiSideway == false
strategy.entry("Long Rebound", strategy.long, comment="Rebound " + str.tostring(close15, "#,###"))
strategy.exit("Exit Long Rebound",from_entry="Long Rebound", stop = ema_lower - (ema_lower*2*trend_gap_p/100) , comment = "SL Rebound")
var label DebugLabel = na
label.delete(DebugLabel)
if not na(latch_trend)
DebugLabel := label.new(bar_index, high15, text="trend " + str.tostring(latch_trend,"#") , style=label.style_label_down, color=color.blue, textcolor=color.white, size=size.small)
// Plot Bollinger Bands
//plot(sidewaysMarket ? lastBottomPrice15 : na , color=color.yellow, style=plot.style_circles)
//plot(sidewaysMarket ? lastPeakPrice15 : na , color=color.blue, style=plot.style_circles)
plot(trendMarket ? lastBottomPrice15 : na, color=color.red, style=plot.style_circles)
plot(trendMarket ? lastPeakPrice15 : na, color=color.green, style=plot.style_circles)
bgcolor(sidewaysMarket ? color.new(color.black, 90) : na)
bgcolor(trendMarket ? color.new(color.lime, 90) : na)
// Plot the three lines
plot(ema200, title="EMA 200", color=color.white)
plot(ema_upper, title="EMA 200 + 20", color=color.white)
plot(ema_lower, title="EMA 200 - 20", color=color.white)