Strategi Kuantitatif Supertrend MACD

Penulis:ChaoZhang, Tarikh: 2023-12-26 11:13:24
Tag:

img

Ringkasan

Strategi ini menggabungkan isyarat pembalikan trend yang berpotensi dari penunjuk Supertrend dan penunjuk MACD, bersama dengan isyarat overbought / oversold dari penunjuk RSI, untuk membentuk sistem yang agak stabil dan cekap untuk isyarat masuk dan keluar.

Logika Strategi

Logik teras strategi ini terletak pada penggunaan gabungan penunjuk Supertrend dan penunjuk MACD sebagai kriteria untuk isyarat kemasukan.

Pada bahagian Supertrend, strategi ini menggunakan perubahan arah penunjuk Supertrend sebagai isyarat pembalikan yang berpotensi. Apabila arah Supertrend berputar dari atas ke bawah, isyarat beli dihasilkan. Apabila arah berputar dari bawah ke atas, isyarat jual dihasilkan.

Pada bahagian MACD, strategi ini menggunakan kemiringan dan persilangan garis sifar penunjuk MACD pada jangka masa yang lebih rendah (tiap hari) untuk mengenal pasti peluang pembalikan yang berpotensi. Apabila nilai mutlak kemiringan MACD besar (di atas ambang) dan kemiringan mengekalkan trend menaik, isyarat dihasilkan. Jika garis MACD melintasi garis sifar, isyarat tambahan dihasilkan. Isyarat MACD biasanya lebih lancar daripada yang Supertrend.

Untuk isyarat masuk, strategi memerlukan isyarat Supertrend dan isyarat MACD berada dalam arah yang sama sebelum menghantar pesanan dagangan.

Di samping itu, untuk isyarat keluar, strategi ini juga menggunakan isyarat overbought / oversold dari penunjuk RSI. Apabila RSI melebihi 80, isyarat jual dihasilkan. Apabila RSI turun di bawah 20, isyarat beli dihasilkan. Ini membantu menentukan masa pembalikan.

Analisis Kelebihan

Kelebihan terbesar strategi ini adalah kepelbagaian isyarat penunjuk.

Isyarat pembalikan supertrend boleh menangkap trend jangka pendek yang agak kuat; kemiringan MACD dapat menilai kekuatan trend jangka menengah dan panjang untuk mengelakkan tertipu oleh pembalikan palsu; RSI boleh memberikan masa masuk dan keluar terbaik di pasaran terhad dengan menunjukkan tahap overbought / oversold. Menumpuk isyarat dari beberapa penunjuk boleh menapis beberapa perdagangan bising dan mencapai kadar kemenangan yang lebih tinggi.

Selain itu, reka bentuk jangka masa juga munasabah. Supertrend menggunakan jangka masa sejam manakala MACD menggunakan jangka masa harian. Ini memastikan kekerapan perdagangan dan kestabilan dalam penilaian trend.

Analisis Risiko

Risiko utama strategi ini adalah kebarangkalian tinggi untuk mengelirukan isyarat antara penunjuk yang berbeza. Sebagai contoh, Supertrend boleh memberikan pembalikan palsu sementara isyarat MACD tidak menyelaras. Ini boleh menyebabkan kerugian yang tidak perlu.

Di samping itu, RSI untuk menentukan masa keluar juga boleh terlalu awal atau terlalu lewat, menghalang tempoh pegangan maksimum.

Akhirnya, ambang kemiringan MACD yang terlalu besar juga mungkin terlepas peluang pembalikan yang lebih lemah.

Arahan pengoptimuman

Strategi ini boleh dioptimumkan lagi dari aspek berikut:

  1. Memperkenalkan mekanisme stop loss. Stop loss apabila kerugian melebihi peratusan tertentu.

  2. Tambah ambang dinamik untuk penghakiman kemiringan MACD. Tingkatkan ambang kemiringan apabila turun naik pasaran tinggi, dan ambang yang lebih rendah apabila pasaran stabil.

  3. Tambah syarat pulback untuk penilaian keluar RSI. Minta panggilan balik yang signifikan selepas RSI melebihi 80 sebelum mempertimbangkan kedudukan penutupan.

  4. Uji MACD dengan jumlah dan lihat sama ada ia meningkatkan kebolehpercayaan isyarat

  5. Mencuba penyesuaian parameter automatik untuk mencari tetapan optimum

Kesimpulan

Supertrend MACD Quantitative Strategy menggabungkan isyarat dari pelbagai penunjuk untuk menyediakan isyarat kemasukan dan keluar. Kelebihannya terletak pada isyarat yang stabil dan kadar kemenangan yang agak tinggi. Penambahbaikan lanjut dapat dicapai melalui pengoptimuman parameter. Risiko dan arah pengoptimuman terutamanya berpusat di sekitar isu-isu pemasangan parameter. Secara keseluruhan, strategi ini mempunyai nilai praktikal yang kuat untuk perdagangan langsung.


/*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)


Lebih lanjut