Chiến lược theo dõi xu hướng bộ lọc hai phạm vi

Tác giả:ChaoZhang, Ngày: 2024-02-05 11:15:28
Tags:

img

Tổng quan

Chiến lược theo dõi xu hướng bộ lọc hai phạm vi là một chiến lược giao dịch định lượng sử dụng bộ lọc phạm vi EMA kép để xác định hướng xu hướng và theo dõi xu hướng.

Chiến lược logic

Cốt lõi của chiến lược này là lọc phạm vi EMA kép. Nó tính toán phạm vi ATR của các nến và làm mịn nó, sau đó sử dụng hai EMA để xác định vị trí của nến trong phạm vi để xác định xem nó có đang trong xu hướng hay không. Khi giá vượt qua phạm vi, nó báo hiệu một sự thay đổi trong xu hướng.

Đặc biệt, chiến lược đầu tiên tính toán kích thước phạm vi ATR của các nến, và sau đó làm mịn nó với hai EMA. Dải ATR đại diện cho phạm vi biến động bình thường của nến. Khi giá vượt quá phạm vi này, điều đó có nghĩa là một sự thay đổi trong xu hướng đã xảy ra. Chiến lược ghi lại hướng khi giá vượt qua phạm vi EMA. Khi hướng thay đổi, điều đó có nghĩa là một sự đảo ngược xu hướng đã xảy ra, và đó là khi nó có thể chọn để vào thị trường.

Sau khi bước vào thị trường, chiến lược sử dụng lệnh dừng buông để khóa lợi nhuận. Trong thời gian giữ, nó liên tục đánh giá liệu cây nến đã rơi ra khỏi phạm vi. Nếu có sự rút lui, nó sẽ thoát khỏi vị trí hiện tại. Điều này có thể khóa hiệu quả lợi nhuận từ giao dịch xu hướng.

Phân tích lợi thế

Chiến lược theo dõi xu hướng bộ lọc hai phạm vi kết hợp các lợi thế của việc lọc trung bình động và tính toán phạm vi để xác định chính xác hướng xu hướng và tránh thường xuyên vào và ra khỏi thị trường trong các thị trường dao động.

  1. Sử dụng nguyên tắc ATR để đánh giá phạm vi biến động nến, tránh đi vào thị trường mà không có hướng trong thị trường dao động
  2. Bộ lọc EMA kép cải thiện độ chính xác phán đoán và giảm tín hiệu sai
  3. Thời gian thực lưu động dừng lỗ có thể khóa hiệu quả trong lợi nhuận xu hướng
  4. Logic chiến lược đơn giản và rõ ràng, dễ hiểu và tối ưu hóa

Phân tích rủi ro

Ngoài ra, có một số rủi ro với chiến lược này, chủ yếu là trong các khía cạnh sau:

  1. Những khoảng trống lớn có thể phá vỡ phạm vi ATR, dẫn đến việc nhập cảnh sớm
  2. Trong các thị trường có xu hướng mạnh, lệnh dừng lỗ có thể được kích hoạt sớm
  3. Cài đặt tham số không chính xác cũng ảnh hưởng đến hiệu suất chiến lược

Để giải quyết các rủi ro này, các phương pháp như tối ưu hóa các tham số một cách thích hợp, ngăn chặn các sự đột phá sai, đánh giá sức mạnh xu hướng có thể được sử dụng để giải quyết chúng.

Các đề xuất tối ưu hóa

Chiến lược theo dõi xu hướng bộ lọc hai phạm vi cũng có tiềm năng tối ưu hóa hơn nữa, với các hướng tối ưu hóa chính bao gồm:

  1. Tối ưu hóa các thông số ATR để làm trơn tru phạm vi biến động nến
  2. Tích hợp các chỉ số khối lượng để tránh sự đột phá sai
  3. Đánh giá sức mạnh xu hướng để phân biệt các sự đột phá một lần và xu hướng bền vững
  4. Tối ưu hóa giá dừng lỗ để theo dõi xu hướng dài trong khi đảm bảo lợi nhuận

Thông qua các tối ưu hóa này, chiến lược có thể đạt được lợi nhuận ổn định trong nhiều môi trường thị trường hơn.

Tóm lại

Chiến lược theo dõi xu hướng bộ lọc hai phạm vi tích hợp các lợi thế khác nhau của việc lọc trung bình động và phán đoán phạm vi ATR, và có thể xác định hiệu quả hướng và thời gian nhập cảnh của các xu hướng trung hạn và dài hạn bền vững. Nó chỉ vào thị trường khi xu hướng thay đổi và sử dụng lệnh dừng lỗ nổi để khóa lợi nhuận. Chiến lược này có logic đơn giản và rõ ràng và rất phù hợp với giao dịch xu hướng trung hạn và dài hạn. Thông qua tối ưu hóa liên tục các thông số và quy tắc phán đoán, chiến lược này có thể đạt được lợi nhuận tốt trên các thị trường khác nhau.


/*backtest
start: 2023-01-29 00:00:00
end: 2024-02-04 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
strategy("Range Filter [DW] & Labels", shorttitle="RF [DW] & Labels", overlay=true)

//Conditional Sampling EMA Function 
Cond_EMA(x, cond, n)=>
    var val     = array.new_float(0)
    var ema_val = array.new_float(1)
    if cond
        array.push(val, x)
        if array.size(val) > 1
            array.remove(val, 0)
        if na(array.get(ema_val, 0))
            array.fill(ema_val, array.get(val, 0))
        array.set(ema_val, 0, (array.get(val, 0) - array.get(ema_val, 0))*(2/(n + 1)) + array.get(ema_val, 0))
    EMA = array.get(ema_val, 0)
    EMA

//Conditional Sampling SMA Function
Cond_SMA(x, cond, n)=>
    var vals = array.new_float(0)
    if cond
        array.push(vals, x)
        if array.size(vals) > n
            array.remove(vals, 0)
    SMA = array.avg(vals)
    SMA

//Standard Deviation Function
Stdev(x, n)=>
    sqrt(Cond_SMA(pow(x, 2), 1, n) - pow(Cond_SMA(x, 1, n), 2))

//Range Size Function
rng_size(x, scale, qty, n)=> 
    ATR      = Cond_EMA(tr(true), 1, n)
    AC       = Cond_EMA(abs(x - x[1]), 1, n)
    SD       = Stdev(x, n)
    rng_size = scale=="Pips" ? qty*0.0001 : scale=="Points" ? qty*syminfo.pointvalue : scale=="% of Price" ? close*qty/100 : scale=="ATR" ? qty*ATR :
               scale=="Average Change" ? qty*AC : scale=="Standard Deviation" ? qty*SD : scale=="Ticks" ? qty*syminfo.mintick : qty   

//Two Type Range Filter Function
rng_filt(h, l, rng_, n, type, smooth, sn, av_rf, av_n)=>
    rng_smooth = Cond_EMA(rng_, 1, sn)
    r          = smooth ? rng_smooth : rng_
    var rfilt  = array.new_float(2, (h + l)/2)
    array.set(rfilt, 1, array.get(rfilt, 0))
    if type=="Type 1"
        if h - r > array.get(rfilt, 1)
            array.set(rfilt, 0, h - r)
        if l + r < array.get(rfilt, 1)
            array.set(rfilt, 0, l + r)
    if type=="Type 2"
        if h >= array.get(rfilt, 1) + r
            array.set(rfilt, 0, array.get(rfilt, 1) + floor(abs(h - array.get(rfilt, 1))/r)*r)
        if l <= array.get(rfilt, 1) - r
            array.set(rfilt, 0, array.get(rfilt, 1) - floor(abs(l - array.get(rfilt, 1))/r)*r)
    rng_filt1 = array.get(rfilt, 0)
    hi_band1  = rng_filt1 + r
    lo_band1  = rng_filt1 - r
    rng_filt2 = Cond_EMA(rng_filt1, rng_filt1 != rng_filt1[1], av_n)
    hi_band2  = Cond_EMA(hi_band1, rng_filt1 != rng_filt1[1], av_n)
    lo_band2  = Cond_EMA(lo_band1, rng_filt1 != rng_filt1[1], av_n)
    rng_filt  = av_rf ? rng_filt2 : rng_filt1
    hi_band   = av_rf ? hi_band2 : hi_band1
    lo_band   = av_rf ? lo_band2 : lo_band1
    [hi_band, lo_band, rng_filt]
 
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Inputs
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------

//Filter Type
f_type = input(defval="Type 1", options=["Type 1", "Type 2"], title="Filter Type")

//Movement Source
mov_src = input(defval="Close", options=["Wicks", "Close"], title="Movement Source")

//Range Size Inputs
rng_qty   = input(defval=2.618, minval=0.0000001, title="Range Size")
rng_scale = input(defval="Average Change", options=["Points", "Pips", "Ticks", "% of Price", "ATR", "Average Change", "Standard Deviation", "Absolute"], title="Range Scale")

//Range Period
rng_per = input(defval=14, minval=1, title="Range Period (for ATR, Average Change, and Standard Deviation)")

//Range Smoothing Inputs
smooth_range = input(defval=true, title="Smooth Range")
smooth_per   = input(defval=27, minval=1, title="Smoothing Period")

//Filter Value Averaging Inputs
av_vals    = input(defval=true, title="Average Filter Changes")
av_samples = input(defval=2, minval=1, title="Number Of Changes To Average")

// New inputs for take profit and stop loss
take_profit_percent = input(defval=100.0, minval=0.1, maxval=1000.0, title="Take Profit Percentage", step=0.1)
stop_loss_percent = input(defval=100, minval=0.1, maxval=1000.0, title="Stop Loss Percentage", step=0.1)

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Definitions
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------

//High And Low Values
h_val = mov_src=="Wicks" ? high : close
l_val = mov_src=="Wicks" ? low : close

//Range Filter Values
[h_band, l_band, filt] = rng_filt(h_val, l_val, rng_size((h_val + l_val)/2, rng_scale, rng_qty, rng_per), rng_per, f_type, smooth_range, smooth_per, av_vals, av_samples)

//Direction Conditions
var fdir = 0.0
fdir    := filt > filt[1] ? 1 : filt < filt[1] ? -1 : fdir
upward   = fdir==1 ? 1 : 0
downward = fdir==-1 ? 1 : 0

//Colors
filt_color = upward ? #05ff9b : downward ? #ff0583 : #cccccc
bar_color  = upward and (close > filt) ? (close > close[1] ? #05ff9b : #00b36b) :
             downward and (close < filt) ? (close < close[1] ? #ff0583 : #b8005d) : #cccccc

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Outputs
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------

//Filter Plot
filt_plot = plot(filt, color=filt_color, transp=0, linewidth=3,  title="Filter")

//Band Plots
h_band_plot = plot(h_band, color=#05ff9b, transp=100, title="High Band")
l_band_plot = plot(l_band, color=#ff0583, transp=100, title="Low Band")

//Band Fills
fill(h_band_plot, filt_plot, color=#00b36b, transp=85, title="High Band Fill")
fill(l_band_plot, filt_plot, color=#b8005d, transp=85, title="Low Band Fill")

//Bar Color
barcolor(bar_color)

//External Trend Output
plot(fdir, transp=100, editable=false, display=display.none, title="External Output - Trend Signal")

// Trading Conditions Logic
longCond = close > filt and close > close[1] and upward > 0 or close > filt and close < close[1] and upward > 0 
shortCond = close < filt and close < close[1] and downward > 0 or close < filt and close > close[1] and downward > 0

CondIni = 0
CondIni := longCond ? 1 : shortCond ? -1 : CondIni[1]
longCondition = longCond and CondIni[1] == -1
shortCondition = shortCond and CondIni[1] == 1

// Strategy Entry and Exit
strategy.entry("Buy", strategy.long, when = longCondition)
strategy.entry("Sell", strategy.short, when = shortCondition)

// New: Close conditions based on percentage change
long_take_profit_condition = close > strategy.position_avg_price * (1 + take_profit_percent / 100)
short_take_profit_condition = close < strategy.position_avg_price * (1 - take_profit_percent / 100)

long_stop_loss_condition = close < strategy.position_avg_price * (1 - stop_loss_percent / 100)
short_stop_loss_condition = close > strategy.position_avg_price * (1 + stop_loss_percent / 100)

strategy.close("Buy", when = shortCondition or long_take_profit_condition or long_stop_loss_condition)
strategy.close("Sell", when = longCondition or short_take_profit_condition or short_stop_loss_condition)

// Plot Buy and Sell Labels
plotshape(longCondition, title = "Buy Signal", text ="BUY", textcolor = color.white, style=shape.labelup, size = size.normal, location=location.belowbar, color = color.green, transp = 0)
plotshape(shortCondition, title = "Sell Signal", text ="SELL", textcolor = color.white, style=shape.labeldown, size = size.normal, location=location.abovebar, color = color.red, transp = 0)

// Alerts
alertcondition(longCondition, title="Buy Alert", message = "BUY")
alertcondition(shortCondition, title="Sell Alert", message = "SELL")


Thêm nữa