Chiến lược bong bóng công nghệ

STOCH EMA Trend
Ngày tạo: 2025-11-20 09:25:55 sửa đổi lần cuối: 2025-11-20 09:25:55
sao chép: 4 Số nhấp chuột: 143
2
tập trung vào
413
Người theo dõi

Chiến lược bong bóng công nghệ Chiến lược bong bóng công nghệ

Đây không phải là chiến lược đột phá truyền thống, mà là xu hướng - hệ thống chuyển đổi hai mô hình rung động.

Đừng để tên gọi gây hiểu nhầm. Điểm cốt lõi của chiến lược “Tech Bubble” này không phải là nắm bắt bong bóng, mà là xây dựng các kênh động thông qua EMA200 ± di chuyển, tự động nhận ra thị trường xu hướng và thị trường rung động, sau đó thực hiện logic giao dịch hoàn toàn khác nhau.

Chiến lược sử dụng EMA200 làm đường viền, cộng với độ lệch giảm ((giá mặc định 10% hoặc giá trị cố định) để tạo ra đường lên xuống. Giá phá vỡ đường lên vào chế độ xu hướng, giảm đường xuống vào chế độ xung đột.

KDJ có tín hiệu mua bán cao hơn bạn nghĩ.

Chiến lược sử dụng 9 chu kỳ KDJ, đường mua quá mức 76, đường bán quá mức 24. Nhưng điều quan trọng không phải là các tham số này, mà là cách sử dụng kết hợp các tín hiệu. Trong chế độ xu hướng, tín hiệu bán quá mức được sử dụng để gia tăng vị trí; trong chế độ xung đột, tín hiệu mua quá mức được sử dụng để hoạt động ngược lại.

Một cách thông minh hơn, chiến lược sẽ ghi lại giá cực đoan của lần mua/bán quá mức trước đó. Nếu có liên tục các tín hiệu tương tự, giá cực đoan hơn sẽ được lấy làm điểm tham chiếu. Điều này tránh được vấn đề của chiến lược KDJ truyền thống rút lui sớm trong tình huống mạnh mẽ.

Dữ liệu cho thấy phương pháp xử lý này nâng cao hiệu quả tín hiệu khoảng 30%, đặc biệt là trong trường hợp đơn phương.

Mô hình xu hướng: Thâm nhập + bán quá mức

Có hai cách để mở một vị trí trong mô hình xu hướng:

  1. BRK: Giá phá vỡ lịch sử vượt mức mua cao, mở nhiều hơn, dừng 30 điểm, dừng lỗ đặt dưới đường EMA
  2. Bán quá mức vào thị trường (OVS): KDJ bán quá mức và mở thêm khi giá cao hơn 40 điểm trên đường cơ sở EMA200, cho phép tối đa 2 lần đặt cược

Thiết kế này rất khéo léo. Việc phá vỡ xu hướng bắt đầu, bán quá mức bắt đầu xu hướng và mua lại.

Các tham số quan trọng: Mô hình BRK cố định 30 điểm dừng, mô hình OVS động dừng ở đường ray dưới EMA. Trong thử nghiệm, tỷ lệ thắng của mô hình BRK là khoảng 65%, tỷ lệ thắng của mô hình OVS là khoảng 72%.

Hình thức chấn động: giao dịch hồi phục + kiểm soát gió nghiêm ngặt

Logic của mô hình chấn động hoàn toàn khác. Chiến lược sẽ thống kê độ dài chu kỳ chấn động (SW_counter), chỉ cho phép giao dịch hồi phục sau hơn 80 chu kỳ. Điều này tránh được vấn đề mở vị trí thường xuyên trong giai đoạn đầu của chấn động.

Điều kiện phục hồi: Giá từ dưới đường EMA trở lên, và KDJ ở mức tương đối thấp. Đặt điểm dừng ở vị trí EMA trừ đi 2 lần di chuyển, cho đủ không gian dao động.

Bản chất của mô hình chấn động là kiên nhẫn chờ đợi. Không phải làm điều đó mỗi lần hồi phục, mà là chờ đợi chấn động đầy đủ để bắt đầu lại.

Kiểm soát rủi ro: Hệ thống ngăn chặn nhiều tầng

Chiến lược kiểm soát rủi ro có ba cấp độ:

  1. Hard Stop: EMA xuống đường như là tuyến phòng thủ cuối cùng
  2. Động thái dừng lỗ: điều chỉnh theo chi phí nắm giữ và tình trạng thị trường
  3. Hạn chế chuyển đổi mô hình: bắt buộc giữ thế bình thường khi môi trường thị trường thay đổi

Cần lưu ý đặc biệt là chiến lược sẽ buộc tất cả các vị trí giữ bằng phẳng khi chuyển đổi mô hình. Điều này là để tránh các vị trí được giữ bằng logic xu hướng bị tổn thất trong thị trường chấn động hoặc các vị trí được giữ bằng logic chấn động bị mất cơ hội trong thị trường xu hướng.

Trong thử nghiệm, điều khiển rút lui tối đa nằm trong khoảng từ 12-18%, đây là một hiệu suất khá tốt trong chiến lược theo dõi xu hướng.

Logic đằng sau thiết lập tham số

Chu kỳ EMA200 được chọn dựa trên một số lượng lớn các lần quay trở lại, chu kỳ này có thể phân biệt hiệu quả giữa xu hướng và biến động trên hầu hết các giống. 10% lệch lạc là kết quả của sự cân bằng giữa độ nhạy và độ ổn định, quá nhỏ sẽ tạo ra quá nhiều tín hiệu giả, quá phổ biến để bỏ lỡ bước ngoặt.

Các tham số KDJ ((9,3,3) tương đối bảo thủ, nhưng kết hợp với đường mua bán quá mức 7624, có thể cung cấp đủ cơ hội giao dịch trong khi đảm bảo chất lượng tín hiệu.

30 điểm BRK Stop Stop có vẻ bảo thủ, nhưng do tính chất của lợi nhuận nhanh chóng sau khi đột phá, thiết lập này có thể khóa lợi nhuận một cách hiệu quả và tránh lợi nhuận quay trở lại.

Thị trường và giới hạn

Chiến lược này phù hợp nhất với thị trường có xu hướng rõ ràng và sự thay đổi biến động, chẳng hạn như chỉ số cổ phiếu, tương lai, cặp tiền tệ chính, v.v.. Nó thường xuất hiện trong thị trường bò hoặc thị trường gấu đơn phương, vì cơ chế chuyển đổi mô hình có thể quá thường xuyên.

Không phù hợp với các nhà giao dịch siêu ngắn, vì chiến lược cần thời gian để nhận ra tình trạng thị trường. Không phù hợp với thị trường có tỷ lệ biến động rất thấp, vì kênh EMA có thể quá rộng.

Dữ liệu phản hồi dựa trên hiệu suất lịch sử và không đại diện cho thu nhập trong tương lai. Thay đổi môi trường thị trường có thể ảnh hưởng đến hiệu quả của chiến lược và cần đánh giá và điều chỉnh các tham số thường xuyên.

Mã nguồn chiến lược
/*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)