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


Ngày tạo: 2023-12-26 11:13:24 sửa đổi lần cuối: 2023-12-26 11:13:24
sao chép: 0 Số nhấp chuột: 792
1
tập trung vào
1621
Người theo dõi

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

Tổng quan

Chiến lược này sử dụng các tín hiệu đảo ngược xu hướng tiềm năng của chỉ số xu hướng và MACD, kết hợp với tín hiệu mua và bán của chỉ số RSI, tạo thành một hệ thống tín hiệu mở và đóng vị trí ổn định và hiệu quả hơn. Chiến lược này được gọi là Chiến lược định lượng MACD.

Nguyên tắc chiến lược

Lập luận cốt lõi của chiến lược này là sử dụng tổng hợp các chỉ số siêu xu hướng và MACD như các tiêu chuẩn để xác định tín hiệu mở vị trí.

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

Phần MACD, chiến lược sử dụng độ lệch MACD trên khung thời gian thấp hơn (đường mặt trời) và giao điểm 0 để đánh giá cơ hội đảo ngược tiềm năng. Khi độ lệch MACD lớn hơn giá trị tuyệt đối (chủ yếu là lớn hơn giá trị thềm) và độ lệch duy trì cùng với tăng lên, tín hiệu được tạo ra; Nếu MACD giao điểm 0 cũng sẽ tạo ra tín hiệu phụ.

Trong tín hiệu mở vị trí, chiến lược yêu cầu tín hiệu siêu xu hướng và tín hiệu MACD ở cùng hướng trước khi ra lệnh mở vị trí.

Ngoài ra, chiến lược bán lẻ cũng đưa ra tín hiệu bán tháo của chỉ số RSI. Khi chỉ số RSI lớn hơn 80, nó tạo ra tín hiệu bán và mua khi nó nhỏ hơn 20, để hỗ trợ 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 chỉ số khác nhau có thể được tạo ra để làm cho tín hiệu tổng thể ổn định và đáng tin cậy hơn.

Tín hiệu đảo ngược của chỉ số siêu xu hướng có thể nắm bắt xu hướng ngắn hạn mạnh mẽ hơn; độ lệch MACD có thể xác định cường độ xu hướng trung hạn và tránh bị sai lệch bởi sự đảo ngược giả; và RSI có thể cho biết thời gian mở và hòa bình tốt nhất để mua quá mức trong tình trạng biến động trong khu vực. Việc chồng lên nhiều tín hiệu chỉ số có thể lọc ra một số giao dịch ồn ào và đạt được tỷ lệ chiến thắng cao hơn.

Ngoài ra, khung thời gian của chiến lược cũng hợp lý hơn. Xu hướng siêu sử dụng khung thời gian theo giờ, chỉ số MACD sử dụng đường mặt trời, do đó đảm bảo tần suất giao dịch và tính đến sự ổn định của 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à có nhiều khả năng tạo ra tín hiệu lẫn lộn giữa các chỉ số. Ví dụ, một xu hướng siêu có một sự đảo ngược giả, trong khi tín hiệu MACD không được tạo ra đồ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 có thể được sử dụng để xác định thời gian để giữ vị trí quá sớm hoặc quá muộn, làm cho thời gian giữ vị trí của chiến lược không thể được tối đa hóa.

Cuối cùng, thiết lập ngưỡng độ lệch của MACD quá lớn cũng có thể dẫn đến việc bỏ lỡ cơ hội đảo ngược yếu hơn.

Hướng tối ưu hóa

Chiến lược này có thể được tối ưu hóa hơn nữa ở những khía cạnh sau:

  1. Đưa ra cơ chế dừng lỗ. Khi lỗ vượt quá một tỷ lệ nhất định.

  2. Thêm đè giá động vào phán quyết về độ lệch MACD. Tăng đè giá khi thị trường biến động lớn và giảm đè giá khi thị trường ổn định.

  3. Điều kiện điều chỉnh lại được thêm vào để đánh giá mức cân bằng của chỉ số RSI. Đó là yêu cầu một lần điều chỉnh lại rõ ràng sau khi RSI vượt quá 80 và xem xét mức cân bằng.

  4. Testing MACD with volume and see if it improves signal reliability

  5. Trying automated parameter tuning to find optimal settings

Tóm tắt

Chiến lược định lượng MACD vượt quá xu hướng kết hợp nhiều chỉ số để cung cấp tín hiệu mở vị trí và vị trí. Ưu điểm của nó là tín hiệu ổn định, tỷ lệ thắng cao, có thể được nâng cao hơn nữa thông qua tối ưu hóa tham số.

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