Chiến lược đường sắt dừng mất mát thích nghi

Tác giả:ChaoZhang, Ngày: 2024-01-02 11:10:54
Tags:

img

Tổng quan

Ý tưởng chính của chiến lược này là kết hợp bộ lọc Kalman và theo dõi stop loss để xây dựng một đường ray stop loss điều chỉnh năng động. Bộ lọc Kalman được sử dụng để theo dõi giá và đưa ra các giá trị dự đoán. Đường ray stop loss được xây dựng dựa trên các dự đoán ở một tỷ lệ phần trăm nhất định để đạt được theo dõi năng động của giá. Điều này cho phép lợi nhuận tối đa trong giai đoạn xu hướng trong khi dừng lỗ kịp thời trong quá trình đảo ngược.

Toàn bộ chiến lược có thể đạt được kết quả tốt trong thị trường xu hướng.

Nguyên tắc chiến lược

Chiến lược bao gồm các phần chính sau:

  1. Bộ lọc Kalman

    • Dự đoán giá bằng cách sử dụng thuật toán tái diễn
    • Đơn giản hóa giá cả và đưa ra các giá trị dự đoán
  2. Đường sắt dừng mất mát

    • Xây dựng dựa trên các giá trị dự đoán ở tỷ lệ đặt
    • Tỷ lệ sẽ giảm dần dần đến dự đoán như thanh tiến bộ
    • Dừng lỗ khi giá phá vỡ đường ray
  3. Bức piramide và lợi nhuận

    • Sử dụng phương pháp martingale để thêm vị trí trên lỗ
    • Thiết lập nhiều điểm thu lợi nhuận

Dòng chảy hoạt động chính của toàn bộ chiến lược là:

  1. Bộ lọc Kalman dự đoán giá cả
  2. Thiết lập đường sắt dừng mất mát dựa trên giá và tỷ lệ dự đoán
  3. Khi giá di chuyển theo hướng thuận lợi, đường ray dừng lỗ tiếp cận dần để tối đa hóa lợi nhuận
  4. Nếu giá phá vỡ đường ray, dừng lỗ đá vào
  5. Tăng kích thước vị trí lên kim tự tháp về lỗ
  6. Thiết lập nhiều điểm lấy lợi nhuận để đảm bảo lợi nhuận

Phân tích lợi thế

Những lợi thế chính của chiến lược này:

  1. Sử dụng bộ lọc Kalman để dự đoán giá cả, mượt mà và chính xác hơn các chỉ số khác
  2. Đường sắt dừng mất mát thích nghi có thể điều chỉnh dựa trên tình huống thực tế để tối đa hóa lợi nhuận
  3. Pyramiding và cơ chế lợi nhuận đa để mang lại lợi nhuận nhiều hơn trong các động thái xu hướng
  4. Các tham số có thể cấu hình cao cho các điều chỉnh linh hoạt

Phân tích rủi ro

Những rủi ro chính của chiến lược này:

  1. StartStop có thể được kích hoạt thường xuyên trong các chuyển động khác nhau, tăng tần suất giao dịch và phí
  2. Mặc dù cơ chế kim tự tháp có thể khuếch đại lợi nhuận trong xu hướng, nó cũng làm tăng rủi ro và DD
  3. Mặc dù nhiều lần lấy lợi nhuận đảm bảo lợi nhuận, nó cũng làm giảm tiềm năng lợi nhuận

Các rủi ro có thể được giảm bằng cách:

  1. Dừng giao dịch trên thị trường dao động
  2. Điều chỉnh kim tự tháp và lấy các tham số lợi nhuận để giảm rủi ro

Hướng tối ưu hóa

Chiến lược có thể được tối ưu hóa hơn nữa thông qua:

  1. Thêm bộ lọc để xác định xu hướng và phạm vi
  2. Tích hợp nhiều chỉ số hơn để lọc tín hiệu sai
  3. Xem xét thanh toán tất cả các vị trí nếu lỗ vượt quá ngưỡng nhất định
  4. Thêm mô-đun định kích thước vị trí
  5. Các bộ tham số khác nhau có thể được kiểm tra và tối ưu hóa cho các thị trường khác nhau

Tóm lại

Tóm lại, chiến lược đường ray dừng mất mát thích nghi này kết hợp độc đáo dự đoán Kalman và mất mát dừng động. Với điều chỉnh tham số thích hợp, nó có thể đạt được kết quả tốt.


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












Thêm nữa