슈퍼 트렌드 MACD 양적 전략


생성 날짜: 2023-12-26 11:13:24 마지막으로 수정됨: 2023-12-26 11:13:24
복사: 0 클릭수: 792
avatar of ChaoZhang ChaoZhang
1
집중하다
1621
수행원

슈퍼 트렌드 MACD 양적 전략

개요

이 전략은 오버 트렌드 지표와 MACD 지표의 잠재적인 트렌드 반전 신호를 활용하여 RSI 지표의 오버 구매 오버 판매 신호와 함께 안정적이고 효율적인 개시 및 매매 신호 시스템을 형성합니다. 전략은 오버 트렌드 MACD 양적 전략이라고합니다.

전략 원칙

이 전략의 핵심 논리는 포지션 개시 신호의 결정 기준으로 초 트렌드 지표와 MACD 지표를 통합적으로 사용하는 것입니다.

초상향 부분, 전략은 초상향 지표의 방향이 변하는 것을 잠재적인 반전 신호로 사용합니다. 초상향 지표의 방향이 위쪽에서 아래로 바뀌면 구매 신호를 생성합니다. 초상향 지표의 방향이 아래쪽에서 위쪽으로 바뀌면 판매 신호를 생성합니다.

MACD 부분, 전략은 MACD 지표가 낮은 시간 프레임 (일계선) 상의 기울기와 0 축의 교차를 사용하여 잠재적인 반전 기회를 판단한다. MACD 기울기가 절대값이 크면 (값보다 크면) 기울기가 동상승을 유지하면 신호를 발생시킨다. MACD 지표가 0 축을 교차하면 보조 신호를 발생시킨다. MACD 부분의 신호는 트렌드 초과 부분보다 더 평평하다.

포지션 개시 신호에서, 전략은 초 트렌드 신호와 MACD 신호가 일치하는 방향으로 유지되도록 요구합니다.

또한, 평지 부분 전략은 RSI 지표의 오버 구매 오버 판매 신호를 도입했다. RSI 지표가 80보다 크면 판매 신호를 생성하고 20보다 작은 경우 구매 신호를 생성하여 역전 시간을 판단하는 데 도움을 준다.

우위 분석

이 전략의 가장 큰 장점은 지표 신호의 다양성에 있다. 서로 다른 지표들 사이에 상호 보완이 형성되어 전체적인 신호가 더 평평하고 신뢰할 수 있다.

패러트렌드 지표의 역전 신호는 비교적 강력한 단기 트렌드를 잡을 수 있습니다. MACD 슬라이드 는 중기 장기 트렌드 강도를 판단하여 가짜 역전으로 오해받지 않도록 할 수 있습니다. RSI 는 간격의 흔들림 상황에서 패러트렌드가 과매매하는 최적의 개시 및 상위 포지션 시점을 알려줍니다. 여러 지표 신호의 중첩은 일부 잡음 거래를 필터링하여 더 높은 승률을 얻을 수 있습니다.

또한, 전략의 시간 프레임 설정도 합리적입니다. 초고속 추세는 시간대를 사용하고, MACD 지표는 일선을 사용합니다. 이것은 거래 주파수를 보장하면서도 추세 판단의 안정성을 고려합니다.

위험 분석

이 전략의 주요 위험은 지표 사이에 혼동 신호를 생성할 가능성이 높다는 것입니다. 예를 들어, 초 트렌드가 가짜 반전을 일으키고 MACD 신호는 동기화되지 않았습니다. 이것은 불필요한 손실을 초래할 수 있습니다.

또한, RSI 지표가 평소 지점을 판단하는 시기는 너무 일찍 또는 너무 늦어서 전략의 지분 시간을 극대화 할 수 없습니다.

마지막으로, MACD 지표의 기울기 임계값이 너무 커진다는 것은 약한 역전 기회를 놓치게 할 수 있다.

최적화 방향

이 전략은 다음의 몇 가지 측면에서 더 개선될 수 있습니다.

  1. 손실 제도를 도입한다. 손실이 일정 비율을 초과할 때 중단한다.

  2. MACD 기울기에 대한 판단에 동적 하락값을 추가한다. 시장의 변동성이 큰 경우 경사 하락값을 높이고, 시장의 안정성이 있는 경우 하락값을 줄인다.

  3. RSI 지표 평소 판단에 회회 조건을 추가한다. 즉, RSI가 80 이상되면 명백한 회회가 필요하며 평소 판단을 고려한다.

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

  5. Trying automated parameter tuning to find optimal settings

요약하다

트렌드를 초과하는 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)