A ideia principal desta estratégia é combinar o filtro de Kalman e o rastreamento de stop loss para construir um trilho de stop loss ajustado dinamicamente. O filtro de Kalman é usado para rastrear preços e dar valores previstos. O trilho de stop loss é construído com base em previsões em uma certa porcentagem para alcançar o rastreamento dinâmico de preços. Isso permite o máximo de lucro durante a fase de tendência, enquanto o stop loss é oportuno durante a reversão.
Toda a estratégia pode alcançar bons resultados nos mercados em tendência.
A estratégia consiste nas seguintes partes principais:
Filtro Kalman
Trilha de perda de paragem
Pirâmide e lucro
O principal fluxo operacional de toda a estratégia é:
As principais vantagens desta estratégia:
Os principais riscos desta estratégia:
Os riscos podem ser reduzidos através de:
A estratégia pode ser melhorada através de:
Em resumo, esta estratégia adaptativa de stop loss rail combina de forma exclusiva a previsão de Kalman e a perda de stop dinâmica.
/*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")