Estrategia adaptativa de trenes sin pérdidas

El autor:¿ Qué pasa?, Fecha: 2024-01-02 11:10:54
Las etiquetas:

img

Resumen general

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.

Principio de la estrategia

La estrategia consta de las siguientes partes principales:

  1. Filtro de Kalman

    • Predecir precios utilizando algoritmos recursivos
    • Precios suaves y valores previstos
  2. Reloj de pérdida de parada

    • Construido sobre la base de los valores previstos en la proporción establecida
    • La relación disminuirá gradualmente acercándose a las predicciones a medida que las barras progresen
    • Detener pérdidas cuando el precio rompe la barandilla
  3. Piramidizando y obteniendo beneficios

    • Utilice el método de martingale para agregar posiciones sobre pérdidas
    • Configurar puntos de ganancia múltiples

Los principales flujos operativos de toda la estrategia son:

  1. El filtro Kalman predice los precios
  2. Establecer un sistema de frenado de pérdidas basado en el precio y la relación previstos
  3. A medida que el precio se mueve hacia una dirección favorable, el tren stop loss se acerca progresivamente para maximizar las ganancias
  4. Si el precio rompe la barandilla, el stop loss entra en juego.
  5. Aumentar el tamaño de las posiciones a la pirámide de pérdidas
  6. Configurar múltiples puntos de toma de ganancias para asegurar el beneficio

Análisis de ventajas

Las principales ventajas de esta estrategia:

  1. Utilice el filtro Kalman para predecir los precios, más suave y preciso que otros indicadores
  2. El tren de stop loss adaptable se puede ajustar en función de la situación real para maximizar el beneficio
  3. Mecanismo de pirámide y toma múltiple de ganancias para obtener más ganancias en movimientos de tendencia
  4. Parámetros altamente configurables para ajustes flexibles

Análisis de riesgos

Los principales riesgos de esta estrategia:

  1. StartStop puede activarse con frecuencia en movimientos variados, aumentando la frecuencia de negociación y las tarifas
  2. Aunque el mecanismo de pirámide puede amplificar las ganancias en las tendencias, también aumenta los riesgos y el DD
  3. Aunque las ganancias múltiples aseguran ganancias, también reducen el potencial de ganancias

Los riesgos pueden reducirse mediante:

  1. Suspensión de las operaciones en el mercado de variantes
  2. Ajustar la pirámide y tomar los parámetros de ganancia para reducir el riesgo

Dirección de optimización

La estrategia se puede optimizar aún más mediante:

  1. Añadir filtros para identificar tendencias y rangos
  2. Incorporar más indicadores para filtrar señales falsas
  3. Considere la posibilidad de liquidar todas las posiciones si las pérdidas superan cierto umbral
  4. Añadir módulo de dimensionamiento de posición
  5. Los diferentes conjuntos de parámetros se pueden probar y optimizar para diferentes mercados

Resumen de las actividades

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")












Más.