리소스 로딩... 로딩...

MACD-KDJ 결합된 마틴게일 피라미딩 양적 거래 전략

저자:차오장, 날짜: 2024-12-05 16:35:26
태그:MACDKDJSMA

 MACD-KDJ Combined Martingale Pyramiding Quantitative Trading Strategy

전반적인 설명

이 전략은 MACD 및 KDJ 지표에 기반을 둔 마틴게일 거래 시스템으로, 피라미딩 포지션 사이징과 동적 이익/손실 관리를 결합합니다. 이 전략은 지표 크로스오버를 통해 엔트리 타이밍을 결정하고, 포지션 관리를 위해 마틴게일 이론을 활용하고, 트렌딩 시장에서 피라미딩을 통해 수익을 향상시킵니다. 전체 포지션 제어, 동적 스톱-손실 및 드라우다운 제어 메커니즘을 포함한 포괄적 인 리스크 제어 시스템을 갖추고 있습니다.

전략 원칙

핵심 논리는 네 가지 핵심 요소로 구성되어 있습니다. 입구 신호, 포지션 추가 메커니즘, 이익/손실 관리 및 위험 통제. 입구 신호는 신호 라인을 가로질러 MACD 라인과 신호 라인을 가로질러 %D 라인을 가로질러 KDJs %K의 컨버전스에 기반합니다. 포지션 추가 메커니즘은 마르틴게일 이론을 채택하고, 인수 인수를 통해 포지션 크기를 동적으로 조정하여 최대 10 개의 추가 포지션을 지원합니다. 수익 취득은 수익 취득 수준을 동적으로 조정하기 위해 트레이링 스톱을 사용합니다. 스톱 손실은 고정 및 트레이링 메커니즘을 모두 포함합니다. 전략은 지표 매개 변수, 포지션 제어 매개 변수 및 위험 통제 매개 변수의 유연한 조정을 지원합니다.

전략적 장점

  1. 높은 신호 시스템 신뢰성: MACD 트렌드 지표와 KDJ 오시레이터를 결합하여 잘못된 신호를 효과적으로 필터합니다.
  2. 과학적 위치 관리: 마틴게일 시스템은 역동 트렌드 포지션을 추가함으로써 보유 비용을 줄일 수 있습니다.
  3. 포괄적 리스크 관리: 여러 가지 스톱 로스 메커니즘과 포지션 제한을 통해 리스크를 효과적으로 제어합니다.
  4. 최적화된 수익 구조: 피라미딩은 트렌드 시장에서 더 나은 수익을 얻을 수 있습니다.
  5. 유연한 매개 변수: 다른 시장 특성에 대한 전략 매개 변수 최적화를 지원합니다.

전략 위험

  1. 시장 위험: 다양한 시장에서의 빈번한 포지션 추가로 손실이 커질 수 있습니다.
  2. 포지션 리스크: 마틴게일 시스템은 과도한 포지션 크기를 초래할 수 있습니다.
  3. 유동성 위험: 큰 자본 투입이 불충분한 유동성 문제에 직면 할 수 있습니다.
  4. 시스템 위험: 과도한 매개 변수 최적화는 전략 과잉 조정으로 이어질 수 있습니다.

전략 최적화 방향

  1. 신호 시스템 최적화: 높은 변동성 환경에서 신호 감도를 조정하기 위해 변동성 지표를 포함합니다.
  2. 포지션 관리 최적화: 시장 조건에 기반한 적응 조정을 위한 동적 곱셈 인수를 설계
  3. 리스크 제어 최적화: 상당한 리드 아웃 도중 포지션을 줄이기 위해 마감 제어 모듈을 추가합니다.
  4. 매개 변수 최적화: 적응적 매개 변수 조절을 위한 기계 학습 방법을 도입

요약

이 전략은 고전적인 기술 지표와 고급 위치 관리 방법을 결합하여 완전한 양적 거래 시스템을 구축합니다. 그것의 핵심 장점은 신호 신뢰성과 포괄적인 위험 통제에 있으며, 파라미터화를 통해 강력한 적응력을 유지합니다. 내재된 위험이 있지만 지속적인 최적화와 개선은 전략이 다른 시장 환경에서 안정적인 성능을 유지할 수 있습니다.


/*backtest
start: 2024-11-04 00:00:00
end: 2024-12-04 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © aaronxu567
//@version=5
strategy("MACD and KDJ Opening Conditions with Pyramiding and Exit", overlay=true) // pyramiding

// Setting
initialOrder = input.float(50000.0, title="Initial Order") 
initialOrderSize = initialOrder/close
//initialOrderSize = input.float(1.0, title="Initial Order Size") // Initial Order Size
macdFastLength = input.int(9, title="MACD Fast Length") // MACD Setting
macdSlowLength = input.int(26, title="MACD Slow Length")
macdSignalSmoothing = input.int(9, title="MACD Signal Smoothing")
kdjLength = input.int(14, title="KDJ Length")
kdjSmoothK = input.int(3, title="KDJ Smooth K")
kdjSmoothD = input.int(3, title="KDJ Smooth D")
enableLong = input.bool(true, title="Enable Long Trades")
enableShort = input.bool(true, title="Enable Short Trades")

// Additions Setting
maxAdditions = input.int(5, title="Max Additions", minval=1, maxval=10) // Max Additions
addPositionPercent = input.float(1.0, title="Add Position Percent", minval=0.1, maxval=10) // Add Conditions
reboundPercent = input.float(0.5, title="Rebound Percent (%)", minval=0.1, maxval=10) // Rebound 
addMultiplier = input.float(1.0, title="Add Multiplier", minval=0.1, maxval=10) // 

// Stop Setting
takeProfitTrigger = input.float(2.0, title="Take Profit Trigger (%)", minval=0.1, maxval=10) // 
trailingStopPercent = input.float(0.3, title="Trailing Stop (%)", minval=0.1, maxval=10) // 
stopLossPercent = input.float(6.0, title="Stop Loss Percent", minval=0.1, maxval=10) // 

// MACD Calculation
[macdLine, signalLine, _] = ta.macd(close, macdFastLength, macdSlowLength, macdSignalSmoothing)

// KDJ Calculation
k = ta.sma(ta.stoch(close, high, low, kdjLength), kdjSmoothK)
d = ta.sma(k, kdjSmoothD)
j = 3 * k - 2 * d

// Long Conditions
enterLongCondition = enableLong and ta.crossover(macdLine, signalLine) and ta.crossover(k, d)

// Short Conditions
enterShortCondition = enableShort and ta.crossunder(macdLine, signalLine) and ta.crossunder(k, d)

// Records
var float entryPriceLong = na
var int additionsLong = 0 // 记录多仓加仓次数
var float nextAddPriceLong = na // 多仓下次加仓触发价格
var float lowestPriceLong = na // 多头的最低价格
var bool longPending = false // 多头加仓待定标记

var float entryPriceShort = na
var int additionsShort = 0 // 记录空仓加仓次数
var float nextAddPriceShort = na // 空仓下次加仓触发价格
var float highestPriceShort = na // 空头的最高价格
var bool shortPending = false // 空头加仓待定标记

var bool plotEntryLong = false
var bool plotAddLong = false
var bool plotEntryShort = false
var bool plotAddShort = false

// Open Long
if (enterLongCondition and strategy.opentrades == 0)
    strategy.entry("long", strategy.long, qty=initialOrderSize,comment = 'Long')
    entryPriceLong := close
    nextAddPriceLong := close * (1 - addPositionPercent / 100)
    additionsLong := 0
    lowestPriceLong := na
    longPending := false
    plotEntryLong := true

// Add Long
if (strategy.position_size > 0 and additionsLong < maxAdditions)
    // Conditions Checking
    if (close < nextAddPriceLong) and not longPending
        lowestPriceLong := close
        longPending := true

    if (longPending)
        // Rebound Checking
        if (close > lowestPriceLong * (1 + reboundPercent / 100))
            // Record Price
            float addQty = initialOrderSize*math.pow(addMultiplier,additionsLong+1)
            strategy.entry("long", strategy.long, qty=addQty,comment = 'Add Long')
            additionsLong += 1
            longPending := false
            nextAddPriceLong := math.min(nextAddPriceLong, close) * (1 - addPositionPercent / 100) // Price Updates
            plotAddLong := true
        else
            lowestPriceLong := math.min(lowestPriceLong, close)

// Open Short
if (enterShortCondition and strategy.opentrades == 0)
    strategy.entry("short", strategy.short, qty=initialOrderSize,comment = 'Short')
    entryPriceShort := close
    nextAddPriceShort := close * (1 + addPositionPercent / 100)
    additionsShort := 0
    highestPriceShort := na
    shortPending := false
    plotEntryShort := true

// add Short
if (strategy.position_size < 0 and additionsShort < maxAdditions)
    // Conditions Checking
    if (close > nextAddPriceShort) and not shortPending
        highestPriceShort := close
        shortPending := true

    if (shortPending)
        // rebound Checking
        if (close < highestPriceShort * (1 - reboundPercent / 100))
            // Record Price
            float addQty = initialOrderSize*math.pow(addMultiplier,additionsShort+1)
            strategy.entry("short", strategy.short, qty=addQty,comment = "Add Short")
            additionsShort += 1
            shortPending := false
            nextAddPriceShort := math.max(nextAddPriceShort, close) * (1 + addPositionPercent / 100) // Price Updates
            plotAddShort := true
        else
            highestPriceShort := math.max(highestPriceShort, close)

// Take Profit or Stop Loss
if (strategy.position_size != 0)
    float stopLossLevel = strategy.position_avg_price * (strategy.position_size > 0 ? (1 - stopLossPercent / 100) : (1 + stopLossPercent / 100))
    float trailOffset = strategy.position_avg_price * (trailingStopPercent / 100) / syminfo.mintick

    if (strategy.position_size > 0)
        strategy.exit("Take Profit/Stop Loss", from_entry="long", stop=stopLossLevel, trail_price=strategy.position_avg_price * (1 + takeProfitTrigger / 100), trail_offset=trailOffset)
    else
        strategy.exit("Take Profit/Stop Loss", from_entry="short", stop=stopLossLevel, trail_price=strategy.position_avg_price * (1 - takeProfitTrigger / 100), trail_offset=trailOffset)

// Plot
plotshape(series=plotEntryLong, location=location.belowbar, color=color.blue, style=shape.triangleup, size=size.small, title="Long Signal")
plotshape(series=plotAddLong, location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small, title="Add Long Signal")
plotshape(series=plotEntryShort, location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small, title="Short Signal")
plotshape(series=plotAddShort, location=location.abovebar, color=color.orange, style=shape.triangledown, size=size.small, title="Add Short Signal")

// Plot Clear
plotEntryLong := false
plotAddLong := false
plotEntryShort := false
plotAddShort := false



// // table
// var infoTable = table.new(position=position.top_right,columns = 2,rows = 6,bgcolor=color.yellow,frame_color = color.white,frame_width = 1,border_width = 1,border_color = color.black)
// if barstate.isfirst
//     t1="Open Price"
//     t2="Avg Price"
//     t3="Additions"
//     t4='Next Add Price'
//     t5="Take Profit"
//     t6="Stop Loss"
//     table.cell(infoTable, column = 0, row = 0,text=t1       ,text_size=size.auto)
//     table.cell(infoTable, column = 0, row = 1,text=t2       ,text_size=size.auto)
//     table.cell(infoTable, column = 0, row = 2,text=t3       ,text_size=size.auto)
//     table.cell(infoTable, column = 0, row = 3,text=t4       ,text_size=size.auto)
//     table.cell(infoTable, column = 0, row = 4,text=t5       ,text_size=size.auto)
//     table.cell(infoTable, column = 0, row = 5,text=t6       ,text_size=size.auto)
// if barstate.isconfirmed and strategy.position_size!=0
//     ps=strategy.position_size
//     pos_avg=strategy.position_avg_price
//     opt=strategy.opentrades
//     t1=str.tostring(strategy.opentrades.entry_price(0),format.mintick)
//     t2=str.tostring(pos_avg,format.mintick)
//     t3=str.tostring(opt>1?(opt-1):0)
//     t4=str.tostring(ps>0?nextAddPriceLong:nextAddPriceShort,format.mintick)
//     t5=str.tostring(pos_avg*(1+(ps>0?1:-1)*takeProfitTrigger*0.01),format.mintick)
//     t6=str.tostring(pos_avg*(1+(ps>0?-1:1)*stopLossPercent*0.01),format.mintick)
//     table.cell(infoTable, column = 1, row = 0,text=t1  ,text_size=size.auto)
//     table.cell(infoTable, column = 1, row = 1,text=t2  ,text_size=size.auto)
//     table.cell(infoTable, column = 1, row = 2,text=t3  ,text_size=size.auto)
//     table.cell(infoTable, column = 1, row = 3,text=t4  ,text_size=size.auto)
//     table.cell(infoTable, column = 1, row = 4,text=t5  ,text_size=size.auto)
//     table.cell(infoTable, column = 1, row = 5,text=t6  ,text_size=size.auto)
    

관련

더 많은