Супертенд MACD Количественная стратегия

Автор:Чао Чжан, Дата: 2023-12-26 11:13:24
Тэги:

img

Обзор

Эта стратегия сочетает в себе потенциальные сигналы обратного тренда от индикатора Supertrend и индикатора MACD вместе с сигналами перекупленности/перепроданности от индикатора RSI, чтобы сформировать относительно стабильную и эффективную систему сигналов входа и выхода.

Логика стратегии

Основная логика этой стратегии заключается в совместном использовании индикатора Supertrend и индикатора MACD в качестве критериев для сигналов входа.

На стороне Супертенда стратегия использует изменение направления индикатора Супертенда в качестве потенциального сигнала обратного движения. Когда направление Супертенда поворачивается сверху вниз, генерируется сигнал покупки. Когда направление поворачивается сверху вниз, генерируется сигнал продажи.

На стороне MACD стратегия использует перекресток наклона и нулевой линии индикатора MACD на более низких временных отрезках (ежедневно) для выявления потенциальных возможностей перемены. Когда абсолютное значение наклона MACD большое (выше порога) и наклон поддерживает восходящий тренд, генерируется сигнал. Если линия MACD пересекает нулевую линию, генерируется вспомогательный сигнал.

Для входных сигналов стратегия требует, чтобы сигнал Supertrend и сигнал MACD находились в одном направлении перед отправкой торговых ордеров.

Кроме того, для сигналов выхода стратегия также использует сигналы перекупа / перепродажи от индикатора RSI. Когда RSI превышает 80, генерируется сигнал продажи. Когда RSI опускается ниже 20, генерируется сигнал покупки. Они помогают определить время обратного движения.

Анализ преимуществ

Наибольшее преимущество этой стратегии заключается в разнообразии индикаторных сигналов, которые могут дополнять друг друга и сделать общий сигнал более стабильным и надежным.

Сигналы обратного движения супертенденции могут улавливать относительно сильные краткосрочные тенденции; наклон MACD может оценивать силу средне-долгосрочного тренда, чтобы не быть введенным в заблуждение ложными обратными движениями; RSI может обеспечить лучшее время входа и выхода на рынке с диапазоном, указывая на уровни перекупленности / перепроданности. Складывание сигналов из нескольких индикаторов может отфильтровать некоторые шумные сделки и достичь более высокого уровня выигрыша.

Кроме того, дизайн временных рамок также является разумным. Supertrend использует часовые временные рамки, в то время как MACD использует ежедневные временные рамки. Это обеспечивает как частоту торговли, так и стабильность в суждении о тренде.

Анализ рисков

Основным риском этой стратегии является высокая вероятность путаницы сигналов между различными индикаторами. Например, Supertrend может давать ложное изменение, в то время как сигнал MACD не синхронизируется. Это может привести к ненужным потерям.

Кроме того, RSI для определения времени выхода может быть слишком ранним или слишком поздним, что препятствует максимальному периоду хранения.

Наконец, чрезмерный порог наклона MACD также может упустить более слабые возможности для обратного движения.

Руководство по оптимизации

Эта стратегия может быть дополнительно оптимизирована из следующих аспектов:

  1. Внедрить механизм остановки потерь, когда потеря превышает определенный процент.

  2. Добавить динамический порог для оценки наклона MACD. Повысить порог наклона, когда волатильность рынка высока, и снизить порог, когда рынок стабилен.

  3. Добавить условие pullback для выхода RSI. Требуется значительный callback после того, как RSI превышает 80 перед рассмотрением закрытия позиции.

  4. Проверка MACD с объемом и посмотреть, улучшает ли он надежность сигнала

  5. Попробовать автоматическую настройку параметров для поиска оптимальных настроек

Заключение

Супертенд MACD объемная стратегия объединяет сигналы из нескольких индикаторов для обеспечения сигналов входа и выхода. Ее преимущества заключаются в стабильных сигналах и относительно высоком уровне выигрыша. Дальнейшие улучшения могут быть достигнуты за счет оптимизации параметров. Риски и направления оптимизации в основном сосредоточены вокруг проблем с перенапряжением параметров. В целом эта стратегия имеет сильное практическое значение для живой торговли.


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


Больше