Esta estrategia es un sistema de negociación Martingale basado en los indicadores MACD y KDJ, que combina el tamaño de posición piramidal y la gestión dinámica de ganancias/pérdidas.
La lógica básica consiste en cuatro elementos clave: señales de entrada, mecanismo de adición de posición, gestión de ganancias/pérdidas y control de riesgos. Las señales de entrada se basan en la convergencia de la línea MACD que cruza la línea de señal y la línea %D de KDJ
La estrategia construye un sistema de negociación cuantitativo completo mediante la combinación de indicadores técnicos clásicos con métodos avanzados de gestión de posiciones. Sus principales ventajas se encuentran en la fiabilidad de la señal y el control integral del riesgo, al tiempo que mantiene una fuerte adaptabilidad a través de la parametrización.
/*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)