슈퍼트렌드 MACD 양적 전략

저자:차오장, 날짜: 2023-12-26 11:13:24
태그:

img

전반적인 설명

이 전략은 슈퍼트렌드 지표와 MACD 지표의 잠재적 인 트렌드 역전 신호와 RSI 지표의 과잉 구매 / 과잉 판매 신호를 결합하여 상대적으로 안정적이고 효율적인 입출 신호 시스템을 형성합니다. 전략 이름은 슈퍼트렌드 MACD 양적 전략입니다.

전략 논리

이 전략의 핵심 논리는 슈퍼트렌드 지표와 MACD 지표가 엔트리 신호의 기준으로 결합되어 사용된다는 것입니다.

슈퍼트렌드 부분에서 전략은 슈퍼트렌드 지표의 방향 변경을 잠재적 인 반전 신호로 채택합니다. 슈퍼트렌드 방향이 위에서 아래로 전환되면 구매 신호가 생성됩니다. 방향이 아래에서 위로 전환되면 판매 신호가 생성됩니다.

MACD 부분에서 전략은 잠재적인 반전 기회를 식별하기 위해 MACD 지표의 기울기와 제로 라인 크로스오버를 낮은 시간 프레임 (일일) 에 사용합니다. MACD 기울기 절대 값이 크면 (약수 이상) 기울기가 상승 추세를 유지하면 신호가 생성됩니다. MACD 라인이 제로 라인을 넘으면 보조 신호가 생성됩니다. MACD 신호는 일반적으로 슈퍼 트렌드보다 부드럽습니다.

엔트리 신호의 경우, 전략은 슈퍼트렌드 신호와 MACD 신호가 거래 명령을 발송하기 전에 같은 방향으로 있어야 합니다.

또한, 출구 신호에 대한 전략은 또한 RSI 지표에서 과잉 구매 / 과잉 판매 신호를 채택합니다. RSI가 80을 넘으면 판매 신호가 생성됩니다. RSI가 20 이하로 떨어지면 구매 신호가 생성됩니다. 이것들은 반전 시기를 결정하는 데 도움이됩니다.

이점 분석

이 전략의 가장 큰 장점은 지표 신호의 다양성입니다. 다른 지표가 서로를 보완하여 전체 신호를 더 안정적이고 신뢰할 수 있습니다.

슈퍼 트렌드 역전 신호는 비교적 강한 단기 트렌드를 포착 할 수 있습니다. MACD 기울기는 거짓 반전으로 잘못 인도되지 않도록 중장기 트렌드 강도를 판단 할 수 있습니다. RSI는 과잉 구매 / 과잉 판매 수준을 표시함으로써 범위 제한 시장에서 가장 좋은 입출 시기를 제공 할 수 있습니다. 여러 지표에서 신호를 쌓는 것은 소란한 거래를 필터링하고 더 높은 승률을 달성 할 수 있습니다.

또한, 시간 프레임 디자인은 또한 합리적입니다. 슈퍼 트렌드는 시간 프레임을 사용하고 MACD는 일일 시간 프레임을 사용합니다. 이것은 거래 빈도와 트렌드 판단의 안정성을 모두 보장합니다.

위험 분석

이 전략의 주요 위험은 다른 지표들 사이의 신호를 혼동할 가능성이 높기 때문이다. 예를 들어, 슈퍼트렌드는 MACD 신호가 동기화되지 않는 동안 잘못된 반전을 줄 수 있다. 이것은 불필요한 손실로 이어질 수 있다.

또한, 출출 시기를 결정하는 RSI는 너무 일찍 또는 너무 늦게 발생할 수 있으며 최대 보유 기간을 막을 수 있습니다.

마지막으로, MACD 기울기 문턱이 너무 크면 약해진 반전 기회를 놓칠 수도 있습니다.

최적화 방향

이 전략은 다음 측면에서 더 이상 최적화 될 수 있습니다.

  1. 스톱 로스 메커니즘을 도입합니다.

  2. MACD 기울기 판단에 동적 임계치를 추가합니다. 시장 변동성이 높을 때 기울기 임계치를 높이고 시장이 안정되면 임계치를 낮추십시오.

  3. RSI 출구 판단을 위한 pullback 조건을 추가합니다. 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)


더 많은