Chiến lược định lượng MACD siêu xu hướng

Tác giả:ChaoZhang, Ngày: 2023-12-26 11:13:24
Tags:

img

Tổng quan

Chiến lược này kết hợp các tín hiệu đảo ngược xu hướng tiềm năng từ chỉ số Supertrend và chỉ số MACD, cùng với các tín hiệu mua quá mức / bán quá mức từ chỉ số RSI, để tạo thành một hệ thống tương đối ổn định và hiệu quả cho các tín hiệu vào và ra.

Chiến lược logic

Lý thuyết cốt lõi của chiến lược này nằm trong việc sử dụng kết hợp chỉ số Supertrend và chỉ số MACD làm tiêu chí cho các tín hiệu đầu vào.

Về phần Supertrend, chiến lược sử dụng sự thay đổi hướng của chỉ số Supertrend làm tín hiệu đảo ngược tiềm năng. Khi hướng Supertrend quay từ trên xuống, một tín hiệu mua được tạo ra. Khi hướng quay từ dưới lên, một tín hiệu bán được tạo ra.

Về phần MACD, chiến lược sử dụng độ dốc và đường không chéo của chỉ số MACD trên khung thời gian thấp hơn (ngày) để xác định các cơ hội đảo ngược tiềm năng. Khi giá trị tuyệt đối của độ dốc MACD lớn (trên ngưỡng) và độ dốc duy trì xu hướng tăng, một tín hiệu được tạo ra. Nếu đường MACD vượt qua đường không, một tín hiệu phụ được tạo ra.

Đối với tín hiệu nhập cảnh, chiến lược yêu cầu tín hiệu Supertrend và tín hiệu MACD ở cùng một hướng trước khi gửi lệnh giao dịch.

Ngoài ra, đối với tín hiệu thoát, chiến lược cũng áp dụng các tín hiệu mua quá mức / bán quá mức từ chỉ số RSI. Khi RSI vượt trên 80, một tín hiệu bán được tạo ra. Khi RSI giảm xuống dưới 20, một tín hiệu mua được tạo ra. Chúng giúp xác định thời gian đảo ngược.

Phân tích lợi thế

Ưu điểm lớn nhất của chiến lược này là sự đa dạng của các tín hiệu chỉ số.

Các tín hiệu đảo ngược siêu xu hướng có thể nắm bắt các xu hướng ngắn hạn tương đối mạnh; độ dốc MACD có thể đánh giá sức mạnh xu hướng trung dài hạn để tránh bị sai lệch bởi các sự đảo ngược sai; chỉ số RSI có thể cung cấp thời gian vào và ra tốt nhất trong thị trường giới hạn phạm vi bằng cách chỉ ra mức mua quá mức / bán quá mức. Đặt các tín hiệu từ nhiều chỉ số có thể lọc ra một số giao dịch ồn ào và đạt tỷ lệ thắng cao hơn.

Ngoài ra, thiết kế khung thời gian cũng hợp lý. Supertrend sử dụng khung thời gian hàng giờ trong khi MACD sử dụng khung thời gian hàng ngày. Điều này đảm bảo cả tần suất giao dịch và sự ổn định trong phán đoán xu hướng.

Phân tích rủi ro

Rủi ro chính của chiến lược này là khả năng nhầm lẫn tín hiệu giữa các chỉ số khác nhau. Ví dụ, Supertrend có thể đưa ra sự đảo ngược sai trong khi tín hiệu MACD không đồng bộ. Điều này có thể dẫn đến tổn thất không cần thiết.

Ngoài ra, chỉ số RSI để xác định thời gian thoát cũng có thể quá sớm hoặc quá muộn, ngăn chặn thời gian giữ tối đa.

Cuối cùng, ngưỡng độ dốc MACD quá lớn cũng có thể bỏ lỡ các cơ hội đảo ngược yếu hơn.

Hướng dẫn tối ưu hóa

Chiến lược này có thể được tối ưu hóa thêm từ các khía cạnh sau:

  1. Thiết lập cơ chế dừng lỗ khi lỗ vượt quá một tỷ lệ nhất định.

  2. Thêm ngưỡng động cho đánh giá độ dốc MACD. Tăng ngưỡng độ dốc khi biến động thị trường cao và giảm ngưỡng khi thị trường ổn định.

  3. Thêm điều kiện pullback cho phán đoán thoát RSI. Yêu cầu một cuộc gọi trở lại đáng kể sau khi RSI vượt quá 80 trước khi xem xét đóng vị trí.

  4. Kiểm tra MACD với khối lượng và xem liệu nó có cải thiện độ tin cậy tín hiệu không

  5. Cố gắng điều chỉnh tham số tự động để tìm các thiết lập tối ưu

Kết luận

Chiến lược định lượng Supertrend MACD kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra. Supertrend MACD Quantitative Strategy kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra. Supertrend MACD Quantitative Strategy kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra. Supertrend MACD Quantitative Strategy kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra. Supertrend MACD Quantitative Strategy kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra. Supertrend MACD Quantitative Strategy kết hợp các tín hiệu từ nhiều chỉ số để cung cấp tín hiệu vào và ra.


/*backtest
start: 2022-12-19 00:00:00
end: 2023-12-25 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5

strategy("SuperTrend.MACD Strategy", overlay=false, default_qty_type=strategy.percent_of_equity, default_qty_value=100, initial_capital=100000, pyramiding=5, process_orders_on_close=true)

// ---------------- Utility Functions ----------------
getArrayValue(float[] arr, int ago) =>
    if ago >= 0
        array.get(arr, ago >= array.size(arr) ? na: array.size(arr) + -1 * ago -1)
    else
        na

filterNA(float[] a, s, int y) =>
    int x = 0
    if not na(s[0])
        array.push(a, s[0])
        if array.size(a) > y
            array.shift(a)
    a

pine_rsi(float[] x, int y) =>
    x0 = getArrayValue(x, 0)
    x1 = getArrayValue(x, 1)

    u = math.max(x0 - x1, 0) // upward ta.change
    d = math.max(x1 - x0, 0) // downward ta.change
    rs = ta.rma(u, y) / ta.rma(d, y)
    res = 100 - 100 / (1 + rs)
    res

turnAround(float[] arr) =>
    int isTurnAround = 0
    
    now = getArrayValue(arr, 0)
    p1 = getArrayValue(arr, 1)
    p2 = getArrayValue(arr, 2)

    if p1 > now and p1 > p2
        isTurnAround := -1
    else if p1 < now and p1 < p2
        isTurnAround := 1

intergerizeSignal(i) =>
    i>0 ? 1 : i<0 ? -1 : 0

linreg(float[] y, int n, int offset=0) => 
    float slope = na
    float intercept = na

    int endcursor = offset + n - 1

    if array.size(y) > endcursor
        float sumX = 0
        float sumX2 = 0
        float sumY = 0
        float sumY2 = 0
        float sumXY = 0

        for i=offset to endcursor
            yv = array.get(y, i)
            sumY += yv
            sumY2 += math.pow(yv, 2)
            sumX += i
            sumX2 += math.pow(i, 2)
            sumXY += i*yv

        // Pearson correlation coefficient
        r = (n * sumXY - sumX * sumY) / math.sqrt((n * sumY2 - math.pow(sumY, 2)) * (n * sumX2 - math.pow(sumX, 2)))

        // Coefficient of determination
        r2 = math.pow(r, 2)

        meanX = sumX / n
        meanY = sumY / n

        slope := (n * sumXY - sumX * sumY) / (n * sumX2 - math.pow(sumX, 2))
        intercept := meanY - slope * meanX

    [slope, intercept]

isStartOfDay() => dayofweek != dayofweek[1]

// ---------------- Variables ----------------

varip float st_signal = 0
varip float macd_signal = 0
varip float macd_close_signal = 0
varip float histo_signal = 0

var int openSignal = 0
var int closeSignal = 0

// -------------------------------- Supertrend Signal (Open) --------------------------------

// ST calculation
atrPeriod = input(10, "Supertrend ATR Length")
factor = input.float(2.0, "Supertrend Factor", step = 0.01)

[_, direction] = ta.supertrend(factor, atrPeriod)

st_direction_change = ta.change(direction)
if st_direction_change < 0
    st_signal := 4
if st_direction_change > 0
    st_signal := -4

// -------------------------------- MACD Signal (Open + Close) --------------------------------

// MACD Calculation
fastLength = input(12, title="MACD Fast Length")
slowLength = input(26, title="MACD Slow Length")
signalLength = input(9, title="MACD Signal Length")
macdSlowTimeframe = input.timeframe("D", "MACD Timeframe")
macdSlopeLookbackOpen = input(7, title="MACD Slope Lookback - Open")
macdSlopeLookbackClose = input(3, title="MACD Slope Lookback - Close")

dailyClose = request.security(syminfo.tickerid, macdSlowTimeframe, close, barmerge.gaps_on)
[macdLine, signalLine, _] = ta.macd(dailyClose, fastLength, slowLength, signalLength)

// MACD Slope calculation

varip macdHistory = array.new<float>(0)
varip macdSlowSlopeArr = array.new<float>(0)
varip float macdSlowSlope = na
varip float macdCloseSlope = na

if not na(macdLine[0])
    array.push(macdHistory, macdLine[0])
    if array.size(macdHistory) > macdSlopeLookbackOpen
        array.shift(macdHistory)
    [s1, _] = linreg(macdHistory, macdSlopeLookbackOpen)
    macdSlowSlope := s1

    array.push(macdSlowSlopeArr, macdSlowSlope)
    if array.size(macdSlowSlopeArr) > macdSlopeLookbackClose
        array.shift(macdSlowSlopeArr)
    [s2, _] = linreg(macdSlowSlopeArr, macdSlopeLookbackClose)
    macdCloseSlope := s2

// MACD Signal Calculation
// > open signal
threshold_macdSlowSlope = input.float(0.75, "MACD Slope Open Threshold", step = 0.05)

macdSlowSlopeOverThreshold = math.abs(macdSlowSlope) >= threshold_macdSlowSlope
macdSlowSlopeTrend = macdSlowSlope - getArrayValue(macdSlowSlopeArr, 1)
macdSlowSlopeTrendConfirm = macdSlowSlope*macdSlowSlopeTrend >0

if (macdSlowSlopeOverThreshold and macdSlowSlopeTrendConfirm)
    macd_signal := 3*macdSlowSlope/math.abs(macdSlowSlope)
else
    macd_signal := 0

// > close signal
int macdCloseSignal = 0
macdCloseSignal := intergerizeSignal(macdCloseSlope)

// Histogram signal Calculation
histSlow = macdLine - signalLine

if (ta.crossover(histSlow, 0))
	histo_signal := 2
if (ta.crossunder(histSlow, 0))
	histo_signal := -2

// -------------------------------- RSI Signal (Close) --------------------------------
int rsiCloseSignal = 0
varip float rsiSlow = na

rsiPeriod = input(14, title="RSI Period")

varip dailyCloseRSIFilter = array.new_float()

// rewrite pine_rsi to remove NaN value from series at calculation
dailyCloseRSIFilter := filterNA(dailyCloseRSIFilter, dailyClose, rsiPeriod)

if not na(dailyClose[0])
    rsiSlow := pine_rsi(dailyCloseRSIFilter, rsiPeriod)

if rsiSlow > 80
    rsiCloseSignal := -1
else if rsiSlow < 20
    rsiCloseSignal := 1
else
    rsiCloseSignal := 0

// -------------------------------- Overall Signal --------------------------------

// Close signal
closeSignals = array.from(macdCloseSignal, rsiCloseSignal)
closeSignal := array.includes(closeSignals, 1) ? 1 : array.includes(closeSignals, -1) ? -1 : 0
closeSignal := closeSignal * 5

// Open signal
if (macd_signal * st_signal > 0) and (macd_signal * macd_close_signal >= 0)
    openSignal := intergerizeSignal(st_signal)
    openSignal := openSignal * 6
else
    openSignal := 0

// -------------------------------- Order --------------------------------
// if strategy.position_size == 0
if openSignal * closeSignal >=0
    if openSignal > 0
        strategy.entry("Long Entry", strategy.long)
    else if openSignal < 0
        strategy.entry("Short Entry", strategy.short)

if strategy.position_size != 0
    if closeSignal < 0
        strategy.close("Long Entry")
    if closeSignal > 0
        strategy.close("Short Entry")


// -------------------------------- Plot --------------------------------

plot(closeSignal, title="Close Signal", color=color.red, linewidth = 1, style=plot.style_area)
plot(openSignal, title="Open Signal", color=color.green, linewidth = 1, style=plot.style_area)
plot(st_signal, title="ST Signal", color=color.black, linewidth = 1, style=plot.style_circles)
plot(macd_signal, title="MACD Signal", color=color.blue, linewidth = 1, style=plot.style_circles)
// plot(macdSlowSlope, title="macd slow slope", color=color.purple, linewidth = 1, style=plot.style_line)
// plot(macdCloseSlope, title="macd slow slope", color=color.lime, linewidth = 1, style=plot.style_line)

hline(0, "Zero Line", color=color.gray)


Thêm nữa