Эта стратегия представляет собой торговую систему Мартингейла, основанную на индикаторах MACD и KDJ, сочетающую в себе размещение позиций в виде пирамиды и динамическое управление прибылью / убытками. Стратегия определяет сроки входа через перекрестки индикаторов, использует теорию Мартингейла для управления позициями и повышает доходность посредством пирамиды на трендовых рынках.
Основная логика состоит из четырех ключевых элементов: сигналов входа, механизма добавления позиций, управления прибылью/убытками и контроля риска. Сигналы входа основаны на сближении линии MACD, пересекающей линию сигнала, и %K KDJs, пересекающей линию %D; механизм добавления позиций использует теорию Мартингейла, динамически регулируя размер позиции с помощью коэффициента множителя, поддерживая до 10 дополнительных позиций; прием прибыли использует остановки для динамической корректировки уровней получения прибыли; стоп-лосс включает как фиксированные, так и остановки механизмов. Стратегия поддерживает гибкую корректировку параметров индикатора, параметров контроля позиции и параметров контроля риска.
Стратегия создает полную количественную торговую систему путем сочетания классических технических индикаторов с передовыми методами управления позициями. Ее основные преимущества заключаются в надежности сигнала и всеобъемлющем контроле рисков, сохраняя при этом сильную адаптивность посредством параметризации.
/*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)