Strategi Kuantitatif Supertrend MACD

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

img

Gambaran umum

Strategi ini menggabungkan sinyal pembalikan tren potensial dari indikator Supertrend dan indikator MACD, bersama dengan sinyal overbought/oversold dari indikator RSI, untuk membentuk sistem yang relatif stabil dan efisien untuk sinyal masuk dan keluar.

Logika Strategi

Logika inti dari strategi ini terletak pada penggunaan gabungan indikator Supertrend dan indikator MACD sebagai kriteria untuk sinyal masuk.

Pada bagian Supertrend, strategi mengadopsi perubahan arah indikator Supertrend sebagai sinyal pembalikan potensial. Ketika arah Supertrend berputar dari atas ke bawah, sinyal beli dihasilkan. Ketika arah berputar dari bawah ke atas, sinyal jual dihasilkan.

Pada bagian MACD, strategi menggunakan kemiringan dan penyeberangan garis nol dari indikator MACD pada kerangka waktu yang lebih rendah (tiap hari) untuk mengidentifikasi peluang pembalikan potensial. Ketika nilai mutlak kemiringan MACD besar (di atas ambang batas) dan kemiringan mempertahankan tren naik, sinyal dihasilkan. Jika garis MACD melintasi garis nol, sinyal bantu dihasilkan. Sinyal MACD biasanya lebih halus daripada yang Supertrend.

Untuk sinyal masuk, strategi mengharuskan sinyal Supertrend dan sinyal MACD berada di arah yang sama sebelum mengirim pesanan perdagangan.

Selain itu, untuk sinyal keluar, strategi ini juga mengadopsi sinyal overbought/oversold dari indikator RSI. Ketika RSI naik di atas 80, sinyal jual dihasilkan. Ketika RSI turun di bawah 20, sinyal beli dihasilkan. Ini membantu menentukan waktu pembalikan.

Analisis Keuntungan

Keuntungan terbesar dari strategi ini adalah keragaman sinyal indikator. indikator yang berbeda dapat melengkapi satu sama lain dan membuat sinyal keseluruhan lebih stabil dan dapat diandalkan.

Sinyal pembalikan supertrend dapat menangkap tren jangka pendek yang relatif kuat; kemiringan MACD dapat menilai kekuatan tren jangka menengah-panjang untuk menghindari tertipu oleh pembalikan palsu; RSI dapat memberikan waktu masuk dan keluar terbaik di pasar yang terikat rentang dengan mengindikasikan tingkat overbought / oversold. Menumpuk sinyal dari beberapa indikator dapat menyaring beberapa perdagangan yang bising dan mencapai tingkat kemenangan yang lebih tinggi.

Selain itu, desain timeframe juga masuk akal. Supertrend menggunakan timeframe per jam sedangkan MACD menggunakan timeframe harian. Ini memastikan frekuensi perdagangan dan stabilitas dalam penilaian tren.

Analisis Risiko

Risiko utama dari strategi ini adalah kemungkinan tinggi sinyal membingungkan antara indikator yang berbeda. Misalnya, Supertrend dapat memberikan pembalikan palsu sementara sinyal MACD tidak sinkronisasi. Hal ini dapat menyebabkan kerugian yang tidak perlu.

Selain itu, RSI untuk menentukan waktu keluar juga bisa terlalu dini atau terlalu terlambat, mencegah periode penyimpanan maksimum.

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

Arahan Optimasi

Strategi ini dapat dioptimalkan lebih lanjut dari aspek berikut:

  1. Memperkenalkan mekanisme stop loss. Stop loss ketika kerugian melebihi persentase tertentu.

  2. Tambahkan ambang dinamis untuk penilaian kemiringan MACD Tingkatkan ambang kemiringan ketika volatilitas pasar tinggi, dan menurunkan ambang ketika pasar stabil.

  3. Tambahkan kondisi pullback untuk penilaian keluar RSI. Minta callback yang signifikan setelah RSI melebihi 80 sebelum mempertimbangkan posisi penutupan.

  4. Mencoba MACD dengan volume dan melihat apakah itu meningkatkan keandalan sinyal

  5. Mencoba penyesuaian parameter otomatis untuk menemukan pengaturan optimal

Kesimpulan

Supertrend MACD Quantitative Strategy menggabungkan sinyal dari beberapa indikator untuk memberikan sinyal masuk dan keluar. Keuntungannya terletak pada sinyal yang stabil dan tingkat kemenangan yang relatif tinggi. Peningkatan lebih lanjut dapat dicapai melalui optimasi parameter. Risiko dan arah optimasi terutama berpusat di sekitar masalah overfit parameter. Secara keseluruhan, strategi ini memiliki nilai praktis 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 banyak