La idea principal de esta estrategia es combinar el filtro de Kalman y el seguimiento de stop loss para construir un tren de stop loss ajustado dinámicamente. El filtro de Kalman se utiliza para rastrear los precios y dar valores previstos. El tren de stop loss se construye en función de las predicciones en un cierto porcentaje para lograr un seguimiento dinámico de los precios. Esto permite obtener el máximo beneficio durante la fase de tendencia mientras se detiene la pérdida oportuna durante la inversión.
Toda la estrategia puede lograr buenos resultados en mercados de tendencia.
La estrategia consta de las siguientes partes principales:
Filtro de Kalman
Reloj de pérdida de parada
Piramidizando y obteniendo beneficios
Los principales flujos operativos de toda la estrategia son:
Las principales ventajas de esta estrategia:
Los principales riesgos de esta estrategia:
Los riesgos pueden reducirse mediante:
La estrategia se puede optimizar aún más mediante:
En resumen, esta estrategia de tren de pérdida de parada adaptativa combina de manera única la predicción de Kalman y la pérdida de parada dinámica. Con el ajuste adecuado de parámetros, puede lograr buenos resultados.
/*backtest start: 2023-06-01 00:00:00 end: 2024-01-01 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © BigCoinHunter // ____ _ _____ _ _ _ _ // | _ \(_) / ____| (_) | | | | | | // | |_) |_ __ _| | ___ _ _ __ | |__| |_ _ _ __ | |_ ___ _ __ // | _ <| |/ _` | | / _ \| | '_ \| __ | | | | '_ \| __/ _ \ '__| // | |_) | | (_| | |___| (_) | | | | | | | | |_| | | | | || __/ | // |____/|_|\__, |\_____\___/|_|_| |_|_| |_|\__,_|_| |_|\__\___|_| // __/ | // |___/ //@version=5 strategy(title='Loft Strategy V4', overlay=true, pyramiding=0, default_qty_type=strategy.cash, default_qty_value=100, initial_capital=10000, currency=currency.USD, commission_value=0.05, commission_type=strategy.commission.percent, process_orders_on_close=true) //-------------- fetch user inputs ------------------ gain = input.float(title="Kalman Gain:", defval=100.0, minval=1, maxval=10000.0, step=1) src = input(defval=close, title='Source:') stopPercentBase = input.float(title='Beginning Approach(%)', defval=5.0, minval=0.1, maxval=30.0, step=0.1) stopPercentMin = input.float(title='Final Approach(%)', defval=1.0, minval=0.1, maxval=30.0, step=0.1) downStep = input.float(title='Approach Decrease Step', defval=0.001, minval=0.0, maxval = 5, step=0.001) //stopPercentDeviation = input.float(title="Approach Deviation", defval=1.0, minval=0.1, maxval = 5.0, step=0.1) baseOrderQty = input.float(title="Base Order Quantity", defval=100.0, minval=0.001) maxOrderCount = input.int(title="Max Safe Order Attemp", defval=4, minval=1) priceDeviation = input.float(title="Safe Order Deviation", defval=3, minval=1.0, step=0.1) profitDeviation = input.float(title="Profit Deviation", defval=1.0, minval=1.0, maxval=10, step=0.1) maxTakeProfit = input.float(title="Max Take Profit(%)", defval=25.0, maxval=100, step=0.1) maxOrderQty = input.float(title="Max Order Quantity", defval=1.0, minval=0.01) baseTP1 = input.float(title="TP1(%)", defval=1.0, minval=0.0, maxval=100.0, step=0.1, inline="0") qt1 = input.int(title="QT1(%):", defval=40, minval=1, maxval=100, step=5, inline="0") baseTP2 = input.float(title="TP2(%)", defval=3.0, minval=0.0, maxval=100.0, step=0.1, inline="1") qt2 = input.int(title="QT2(%):", defval=30, minval=1, maxval=100, step=5, inline="1") baseTP3 = input.float(title="TP3(%)", defval=5.0, minval=0.0, maxval=100.0, step=0.1, inline="2") qt3 = input.int(title="QT3(%):", defval=30, minval=1, maxval=100, step=5, inline="2") initialStopLoss = input.float(title="Stop Loss(%)", defval=0.0, minval=0.0, maxval=100.0, step=0.1) longEntry = input.bool(defval=true, title= 'Long Entry', inline="3") shortEntry = input.bool(defval=true, title='Short Entry', inline="3") useSafeStop2 = input.bool(defval = true, title="Safe Stop After TP2", inline="6") useSafeStop1 = input.bool(defval = false, title="Safe Stop After TP1", inline="6") //---------- backtest range setup ------------ fromDay = input.int(defval = 1, title = "From Date:", minval = 1, maxval = 31, inline="4") fromMonth = input.int(defval = 1, title = "/", minval = 1, maxval = 12, inline="4") fromYear = input.int(defval = 2021, title = "/", minval = 2010, inline="4") toDay = input.int(defval = 30, title = "To__ Date:", minval = 1, maxval = 31, inline="5") toMonth = input.int(defval = 12, title = "/", minval = 1, maxval = 12, inline="5") toYear = input.int(defval = 2022, title = "/", minval = 2010, inline="5") //------------ time interval setup ----------- start = timestamp(fromYear, fromMonth, fromDay, 00, 00) // backtest start window finish = timestamp(toYear, toMonth, toDay, 23, 59) // backtest finish window window() => true // create function "within window of time" //------- define the order comments ------ enterLongComment = "" exitLongComment = "" enterShortComment = "" exitShortComment = "" longTPSL = "" longTP = "" longSL = "" shortTPSL = "" shortTP = "" shortSL = "" //--------- Define global variables ----------- var bool long = true var bool stoppedOutLong = false var bool stoppedOutShort = false var float kf = 0.0 var float velo = 0.0 var float orderQty = baseOrderQty var float stopLoss = initialStopLoss var bool isProfit = false var int barindex = 1 var int winCounter = 0 var int winCounterBuffer = 0 var int failCounter = 0 var float tp1 = baseTP1 var float tp2 = baseTP2 var float tp3 = baseTP3 var bool isTakeTP1 = false var bool isTakeTP2 = false var bool isTakeTP3 = false var bool isLastProfit = true var float stopPercentMax = stopPercentBase var float stopPercent = stopPercentBase var float stopLine = 0.0 var labelColor = color.blue //------ kalman filter calculation -------- dk = src - nz(kf[1], src) smooth = nz(kf[1], src) + dk * math.sqrt(gain / 10000 * 2) velo := nz(velo[1], 0) + gain / 10000 * dk kf := smooth + velo //--------- calculate the loft stopLoss line --------- //stopPercentMax := isLastProfit ? stopPercentBase : (stopPercentBase * stopPercentDeviation) if long == true stopLine := kf - (kf * (stopPercent / 100)) if long[1] == true and stopLine <= stopLine[1] stopLine := stopLine[1] else if (long[1] == true) stopPercent := stopPercent - downStep if(stopPercent < stopPercentMin) stopPercent := stopPercentMin if(kf < stopLine) long := false stopPercent := stopPercentMax stopLine := kf + (kf * (stopPercent / 100)) else stopLine := kf + (kf * (stopPercent / 100)) if long[1] == false and stopLine >= stopLine[1] stopLine := stopLine[1] else if(long[1] == false) stopPercent := stopPercent - downStep if(stopPercent < stopPercentMin) stopPercent := stopPercentMin if(kf > stopLine) long := true stopPercent := stopPercentMax stopLine := kf - (kf * (stopPercent / 100)) //------------------- determine buy and sell points --------------------- buySignall = window() and long and (not stoppedOutLong) sellSignall = window() and (not long) and (not stoppedOutShort) if longEntry and shortEntry if buySignall and baseTP1 <= 0.0 if strategy.position_size < 0 if close < strategy.position_avg_price isLastProfit := true else if strategy.position_size == 0 if strategy.wintrades > winCounter //strategy.wintrades[ barindex ] isLastProfit := true else isLastProfit := false else if sellSignall and baseTP1 <= 0.0 if strategy.position_size > 0 if close > strategy.position_avg_price isLastProfit := true else if strategy.position_size == 0 if strategy.wintrades > winCounter //strategy.wintrades[ barindex ] isLastProfit := true else isLastProfit := false else if isTakeTP2 == true isLastProfit := true else isLastProfit := false else if longEntry if sellSignall winCounterBuffer := winCounter if buySignall if winCounter > winCounterBuffer isLastProfit := true else isLastProfit := false else if shortEntry if buySignall winCounterBuffer := winCounter if sellSignall if winCounter > winCounterBuffer isLastProfit := true else isLastProfit := false //------------- set the deviations ------------ var float maxOrderSize = (baseOrderQty * math.pow(priceDeviation, maxOrderCount - 1)) if buySignall or sellSignall if isLastProfit == false orderQty := orderQty * priceDeviation tp1 := tp1 * profitDeviation tp2 := tp2 * profitDeviation tp3 := tp3 * profitDeviation tp1 := math.min(tp1, maxTakeProfit) tp2 := math.min(tp2, maxTakeProfit) tp3 := math.min(tp3, maxTakeProfit) if orderQty > maxOrderSize failCounter := failCounter + 1 orderQty := baseOrderQty tp1 := baseTP1 tp2 := baseTP2 tp3 := baseTP3 else orderQty := baseOrderQty tp1 := baseTP1 tp2 := baseTP2 tp3 := baseTP3 // ----------------- put debug labels ------------------- if orderQty == maxOrderSize labelColor := color.red else labelColor := isLastProfit ? color.lime : color.yellow if longEntry and shortEntry if buySignall or sellSignall label.new( x=bar_index, y=high, text="Qty:"+str.tostring(math.min(orderQty, maxOrderQty))+" | Worst Case:"+str.tostring(failCounter) ,color = labelColor ) else if longEntry if buySignall label.new( x=bar_index, y=high, text="Qty:"+str.tostring(math.min(orderQty, maxOrderQty))+" | Worst Case:"+str.tostring(failCounter) ,color = labelColor ) else if shortEntry if sellSignall label.new( x=bar_index, y=high, text="Qty:"+str.tostring(math.min(orderQty, maxOrderQty))+" | Worst Case:"+str.tostring(failCounter) ,color = labelColor ) //---------- execute the strategy ----------------- nz(orderQty, baseOrderQty) if longEntry and shortEntry if long strategy.close_all( when = buySignall, comment = exitShortComment) strategy.entry("LONG", strategy.long, when = buySignall, qty=math.min(orderQty, maxOrderQty), comment = enterLongComment) stoppedOutLong := true stoppedOutShort := false else strategy.close_all(when=sellSignall, comment = exitLongComment) strategy.entry("SHORT", strategy.short, when = sellSignall, qty=math.min(orderQty, maxOrderQty), comment = enterShortComment) stoppedOutLong := false stoppedOutShort := true else if(longEntry) strategy.entry("LONG", strategy.long, when = buySignall, qty=math.min(orderQty, maxOrderQty), comment = enterLongComment) strategy.close("LONG", when = sellSignall, comment = exitLongComment) if long stoppedOutLong := true stoppedOutShort := false else stoppedOutLong := false stoppedOutShort := true else if(shortEntry) strategy.entry("SHORT", strategy.short, when = sellSignall, qty=math.min(orderQty, maxOrderQty), comment = enterShortComment) strategy.close("SHORT", when = buySignall, comment = exitShortComment) if not long stoppedOutShort := true stoppedOutLong := false else stoppedOutShort := false stoppedOutLong := true //--------- calculate the TP/SL entries ----------- longProfitPrice1 = strategy.position_avg_price * (1 + tp1 * 0.01) longProfitPrice2 = strategy.position_avg_price * (1 + tp2 * 0.01) longProfitPrice3 = strategy.position_avg_price * (1 + tp3 * 0.01) shortProfitPrice1 = strategy.position_avg_price * (1 - tp1 * 0.01) shortProfitPrice2 = strategy.position_avg_price * (1 - tp2 * 0.01) shortProfitPrice3 = strategy.position_avg_price * (1 - tp3 * 0.01) longStopPrice = strategy.position_avg_price * (1 - stopLoss * 0.01) shortStopPrice = strategy.position_avg_price * (1 + stopLoss * 0.01) shortSafeStopPrice2 = strategy.position_avg_price * (1 - 0.2 * 0.01) longSafeStopPrice2 = strategy.position_avg_price * (1 + 0.2 * 0.01) longSafeStopPrice1 = stopLine shortSafeStopPrice1 = stopLine //----------- calculate TP quantity values ----------- takeQty1 = math.min(orderQty, maxOrderQty) * qt1 / 100 takeQty2 = math.min(orderQty, maxOrderQty) * qt2 / 100 takeQty3 = math.min(orderQty, maxOrderQty) * qt3 / 100 //----------------- take profit and stop loss processes ----------------- if strategy.position_size > 0 if close > longProfitPrice1 and tp1 > 0 and isTakeTP1 == false strategy.close(id="LONG", qty=takeQty1, comment = "longTP 1") isTakeTP1 := true if close > longProfitPrice2 and tp2 > 0 and isTakeTP2 == false strategy.close(id="LONG", qty=takeQty2, comment = "longTP 2") isTakeTP2 := true if close > longProfitPrice3 and tp3 > 0 and isTakeTP3 == false strategy.close(id="LONG", qty=takeQty3, comment = "longTP 3") isTakeTP3 := true if isTakeTP2 == true and useSafeStop2 strategy.exit(id="LONG", stop=longSafeStopPrice2, comment = "Long Safe Stop2") if isTakeTP1 == true and useSafeStop1 strategy.exit(id="LONG", stop=longSafeStopPrice1, comment = "Long Safe Stop1") if strategy.position_size < 0 if close < shortProfitPrice1 and tp1 > 0 and isTakeTP1 == false strategy.close(id="SHORT", qty=takeQty1, comment = "Short TP 1") isTakeTP1 := true if close < shortProfitPrice2 and tp2 > 0 and isTakeTP2 == false strategy.close(id="SHORT", qty=takeQty2, comment = "Short TP 2") isTakeTP2 := true if close < shortProfitPrice3 and tp3 > 0 and isTakeTP3 == false strategy.close(id="SHORT", qty=takeQty3, comment = "Short TP 3") isTakeTP3 := true if isTakeTP2 == true and useSafeStop2 strategy.exit(id="SHORT", stop=shortSafeStopPrice2, comment = "Short Safe Stop2") if isTakeTP1 == true and useSafeStop1 strategy.exit(id="SHORT", stop=shortSafeStopPrice1, comment = "Short Safe Stop1") if(initialStopLoss>0.0) if ( strategy.position_size > 0 ) strategy.exit(id="LONG", stop=longStopPrice, comment = "Long Stop Loss") else if ( strategy.position_size < 0 ) strategy.exit(id="SHORT", stop=shortStopPrice, comment = "Short Stop Loss") if buySignall or sellSignall isTakeTP1 := false isTakeTP2 := false isTakeTP3 := false // winCounter := strategy.wintrades //------------- plot charts --------------------- lineColor1 = long ? color.green : color.red lineColor2 = long ? color.aqua : color.fuchsia kalmanPlot = plot(kf, color=lineColor1, linewidth=3, title = "Kalman Filter") stopPlot = plot(stopLine, color=lineColor2, linewidth=2, title = "Stop Loss Line")