Strategi ini adalah sistem perdagangan Martingale berdasarkan indikator MACD dan KDJ, menggabungkan ukuran posisi piramida dan manajemen laba / kerugian dinamis. Strategi ini menentukan waktu masuk melalui crossover indikator, memanfaatkan teori Martingale untuk manajemen posisi, dan meningkatkan pengembalian melalui piramida di pasar tren.
Logika inti terdiri dari empat elemen utama: sinyal masuk, mekanisme penambahan posisi, manajemen laba/rugi, dan pengendalian risiko. Sinyal masuk didasarkan pada konvergensi garis MACD yang melintasi garis sinyal dan KDJs %K yang melintasi garis %D; mekanisme penambahan posisi mengadopsi teori Martingale, secara dinamis menyesuaikan ukuran posisi melalui faktor perkalian, mendukung hingga 10 posisi tambahan; mengambil keuntungan menggunakan trailing stop untuk secara dinamis menyesuaikan tingkat mengambil keuntungan; stop-loss mencakup mekanisme tetap dan trailing. Strategi ini mendukung penyesuaian yang fleksibel dari parameter indikator, parameter kontrol posisi, dan parameter kontrol risiko.
Strategi ini membangun sistem perdagangan kuantitatif yang lengkap dengan menggabungkan indikator teknis klasik dengan metode manajemen posisi canggih. Keuntungannya utama terletak pada keandalan sinyal dan kontrol risiko yang komprehensif, sambil mempertahankan kemampuan beradaptasi yang kuat melalui parameterisasi. Meskipun risiko yang melekat ada, pengoptimalan dan peningkatan terus menerus memungkinkan strategi untuk mempertahankan kinerja yang stabil di berbagai lingkungan pasar.
/*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)