
이름에 착각하지 마십시오. 이 “Tech Bubble” 전략의 핵심은 버블을 잡는 것이 아니라, EMA200 ± 편향을 통해 동적 통로를 구축하고, 자동으로 트렌드 시장과 흔들림 시장을 식별하고, 완전히 다른 거래 논리를 수행합니다.
이 전략은 EMA200을 기준선으로 하고, 변동량을 더하거나 줄여서 (기본의 10% 가격 또는 고정된 값) 경로를 형성한다. 가격은 경로를 돌파하여 트렌드 모드로 들어가고, 경로를 돌파하여 쇼크 모드로 들어간다. 이것은 단순한 평행선 시스템보다 더 정확하다. 왜냐하면 그것은 가격 변동의 폭을 동적으로 조정하는 것을 고려하기 때문이다.
전략은 9주기 KDJ, 오버 바이 라인 76, 오버 세 라인 24을 사용한다. 그러나 중요한 것은 이러한 파라미터가 아니라 신호의 조합 사용 방식이다. 트렌드 모드에서 오버 세 신호는 부가가치에 사용된다.
더 똑똑한 것은, 전략이 마지막 오버 바이/오버 세일의 극한 가격을 기록한다는 것이다. 같은 신호가 연속적으로 발생하면, 더 극단적인 가격을 기준점으로 삼는 것이다. 이것은 전통적인 KDJ 전략이 강세 상황에서 조기 퇴출하는 문제를 피할 것이다.
데이터에 따르면, 이러한 처리 방식은 신호의 효율성을 약 30% 향상시켰으며, 특히 일방적인 상황에서 두드러지게 나타났습니다.
트렌드 모드에서는 두 가지 방법으로 포지션을 열 수 있습니다.
이 디자인은 매우 기발하다. 돌파구 진입점에서는 트렌드를 잡고, 초판도 진입점에서는 리코드 구매점을 잡는다. 이 둘을 함께 사용하면 큰 상황을 놓치지 않고, 리코드하는 과정에서 비용을 절감할 수 있다.
핵심 매개 변수: BRK 모드 고정 30 점 정지, OVS 모드 동적 정지 EMA 하계 레일. 실험에서, BRK 모드 성공률은 약 65%, OVS 모드 성공률은 약 72% 였다.
흔들림 모드 논리는 완전히 다릅니다. 전략은 흔들림 주기의 길이를 통계합니다 (SW_counter), 80주기를 넘기 전까지는 반발 거래가 허용되지 않습니다. 이것은 흔들림 초기에 자주 포지션을 개설하는 문제를 피합니다.
반발 조건: 가격이 EMA 하위 궤도 아래에서 위로 돌아와 KDJ가 상대적으로 낮은 위치에 있다. 스톱로드는 EMA 하위 궤도에서 2배의 이동량을 빼고 충분한 변동 공간을 부여한다.
흔들림 모드의 핵심은 인내심을 가지고 기다리는 것입니다. 모든 반발을 하는 것이 아니라, 흔들림이 충분할 때까지 다시 시도하십시오. 회고록은 이 전략이 가로 수평 시장에서 연간 15-25%의 수익을 얻을 수 있음을 보여줍니다.
전략의 위험 통제는 세 단계로 나뉘어져 있습니다.
특히 주의해야 할 점은, 전략이 모드 스위치할 때 평점으로 모든 지분을 강제한다는 것이다. 이것은 트렌드 로직으로 보유한 포지션이 흔들리는 시장에서 손실되거나, 흔들리는 논리로 보유한 포지션이 트렌드 시장에서 기회를 놓치지 않도록 하기 위한 것이다.
실험적으로 12-18%의 최대 회귀를 제어하는 것은 트렌드 추적 전략에서 상당히 좋은 성과입니다.
EMA200 주기는 대량의 재검토를 기반으로 선택되며, 이 주기는 대부분의 품종에서 동향과 흔들림을 효과적으로 구분할 수 있다. 10%의 편향은 민감도와 안정성을 균형 잡는 결과이며, 너무 작으면 너무 많은 가짜 신호를 생성하고, 너무 일반적이어서 전환점을 놓친다.
KDJ 변수 ((9,3,3) 는 비교적 보수적이지만, 76/24의 오버 바이 오버 셀 라인과 함께 신호 품질을 보장하면서 충분한 거래 기회를 제공합니다.
30점의 BRK 정지는 보수적으로 보이지만, 돌파 이후의 급속한 수익 특성을 고려하면 이 설정은 수익을 효과적으로 잠금화하여 수익 회귀를 방지한다.
전략은 명백한 추세와 흔들림이 번갈아 있는 시장에 가장 적합하다. 예를 들어, 주식 지수 선물, 주요 통화 쌍 등이다. 일방적인 황소 시장이나 곰 시장에서 일반적으로 나타난다. 왜냐하면 패턴 전환 메커니즘이 너무 자주 발생할 수 있기 때문이다.
전략이 시장 상태를 인식하는 데 시간이 걸리기 때문에 초단계 거래자에게는 적합하지 않으며, EMA 통로가 너무 넓기 때문에 매우 낮은 변동률의 시장에는 적합하지 않습니다.
역추적 데이터는 역사적인 성과를 기반으로 하고 미래의 수익을 나타내지 않습니다. 시장 환경의 변화는 전략의 효과에 영향을 줄 수 있으며, 정기적으로 평가하고 매개 변수를 조정할 필요가 있습니다.
/*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)