スーパートレンドMACD定量戦略


作成日: 2023-12-26 11:13:24 最終変更日: 2023-12-26 11:13:24
コピー: 0 クリック数: 792
1
フォロー
1621
フォロワー

スーパートレンドMACD定量戦略

概要

この戦略は,超トレンド指数とMACD指数の潜在的トレンド反転シグナルを利用して,RSI指数の超買超売りシグナルと連携して,より安定で効率的な開場および平仓シグナルシステムを形成します.この戦略は,超トレンドMACD定量化戦略と呼ばれる.

戦略原則

この戦略の核心的な論理は,超トレンド指標とMACD指標を総合的にポジション開設シグナルとして判断基準として使用することにある.

超トレンド部分では,戦略は超トレンド指標の方向の変化を潜在的反転信号として使用する.超トレンド指標の方向が上から下へと変化すると買入信号が生じ,超トレンド指標の方向が下から上へと変化すると売り信号が生じます.

MACD部分では,戦略は,MACD指標が低い時間枠 ((日線) 上の斜率とゼロ軸の交差を用い,潜在的反転の機会を判断する. MACDの斜率の絶対値が大きい ( (値より大きい) と斜率が同上昇を維持するときにシグナルを生成する. MACD指標がゼロ軸の交差をすると,補助信号を生成する. 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)