Chiến lược này là một hệ thống giao dịch Martingale dựa trên các chỉ số MACD và KDJ, kết hợp kích cỡ vị trí kim tự tháp và quản lý lợi nhuận / lỗ năng động. Chiến lược xác định thời gian vào thông qua các dấu hiệu chéo, sử dụng lý thuyết Martingale để quản lý vị trí và tăng lợi nhuận thông qua kim tự tháp trong các thị trường xu hướng. Nó có một hệ thống kiểm soát rủi ro toàn diện bao gồm kiểm soát vị trí tổng thể, cơ chế dừng lỗ năng động và cơ chế kiểm soát rút tiền.
Cơ sở logic bao gồm bốn yếu tố chính: tín hiệu nhập cảnh, cơ chế thêm vị trí, quản lý lợi nhuận / lỗ và kiểm soát rủi ro. Các tín hiệu nhập cảnh dựa trên sự hội tụ của đường MACD vượt qua đường tín hiệu và đường KDJ% K vượt qua đường % D; cơ chế thêm vị trí áp dụng lý thuyết Martingale, điều chỉnh kích thước vị trí một cách năng động thông qua một yếu tố nhân, hỗ trợ tối đa 10 vị trí bổ sung; Lợi nhuận sử dụng dừng lại để điều chỉnh mức lợi nhuận một cách năng động; dừng lỗ bao gồm cả cơ chế cố định và chậm. Chiến lược hỗ trợ điều chỉnh linh hoạt các tham số chỉ số, tham số kiểm soát vị trí và tham số kiểm soát rủi ro.
Chiến lược này xây dựng một hệ thống giao dịch định lượng hoàn chỉnh bằng cách kết hợp các chỉ số kỹ thuật cổ điển với các phương pháp quản lý vị trí tiên tiến. Những lợi thế cốt lõi của nó nằm ở độ tin cậy tín hiệu và kiểm soát rủi ro toàn diện, trong khi duy trì khả năng thích nghi mạnh mẽ thông qua các thông số. Mặc dù có rủi ro vốn có, tối ưu hóa và cải tiến liên tục cho phép chiến lược duy trì hiệu suất ổn định trong các môi trường thị trường khác nhau.
/*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)