적응식 스톱 손실 철도 전략

저자:차오장, 날짜: 2024-01-02 11:10:54
태그:

img

전반적인 설명

이 전략의 주요 아이디어는 칼만 필터와 추적 스톱 로스를 결합하여 동적으로 조정된 스톱 로스 레일을 구축하는 것입니다. 칼만 필터는 가격을 추적하고 예측 값을 제공하기 위해 사용됩니다. 스톱 로스 레일은 가격의 동적 추적을 달성하기 위해 특정 비율의 예측을 기반으로 구성됩니다. 이는 트렌드 단계에서 최대 이익을 얻을 수 있으며 역전 과정에서 신속한 스톱 로스를 허용합니다.

전체 전략은 트렌딩 시장에서 좋은 결과를 얻을 수 있습니다.

전략 원칙

이 전략은 다음과 같은 주요 부분으로 구성됩니다.

  1. 칼만 필터

    • 재귀 알고리즘을 사용하여 가격을 예측
    • 평탄한 가격과 예측 값
  2. 스톱 패스 레일

    • 설정된 비율에서 예측된 값에 기초하여 구성
    • 비율은 바가 진행됨에 따라 예측에 점차적으로 접근 하 고 감소 합니다.
    • 가격이 레일을 깨면 손실을 멈추십시오.
  3. 피라미드 짓고 이익을 취하는 것

    • 손실에 대한 포지션을 추가하기 위해 마틴게일 방법을 사용합니다.
    • 여러 개의 수익점 설정

전체 전략의 주요 운영 흐름은 다음과 같습니다.

  1. 칼만 필터는 가격을 예측합니다.
  2. 예측된 가격과 비율에 기초한 스톱 손실 레일을 설정
  3. 가격이 유리한 방향으로 움직일 때, 손해를 막는 레일은 이익을 극대화하기 위해 점차적으로 접근합니다.
  4. 만약 가격이 레일을 깨면, 스톱 손실이 시작됩니다.
  5. 지점 크기를 손실 피라미드로 늘리십시오.
  6. 수익을 확보하기 위해 여러 가지 수익점을 설정합니다.

이점 분석

이 전략의 주요 장점:

  1. 칼만 필터를 사용하여 다른 지표보다 부드럽고 정확하게 가격을 예측합니다.
  2. 적응 스톱 손실 레일은 수익을 극대화하기 위해 실제 상황에 따라 조정할 수 있습니다.
  3. 피라미딩 및 다중 취득 메커니즘은 트렌딩 움직임에서 더 많은 수익을 창출합니다.
  4. 유연한 조절을 위한 매우 구성 가능한 매개 변수

위험 분석

이 전략의 주요 위험은:

  1. StartStop는 다양한 움직임에서 자주 발생하여 거래 빈도와 수수료를 증가시킬 수 있습니다.
  2. 피라미드 메커니즘은 트렌드 이득을 증폭시킬 수 있지만 또한 위험과 DD를 증가시킵니다.
  3. 복수 취득이 수익을 보장하지만 수익 잠재력도 감소합니다.

위험은 다음을 통해 줄일 수 있습니다.

  1. 시장에서 거래를 중지
  2. 피라미딩을 조정하고 수익 매개 변수를 낮추고 위험을 줄이세요

최적화 방향

이 전략은 다음을 통해 더 이상 최적화 될 수 있습니다.

  1. 트렌드와 범위를 식별하는 필터를 추가합니다.
  2. 잘못된 신호를 필터링하기 위해 더 많은 지표를 포함
  3. 손실이 특정 임계치를 초과하면 모든 포지션을 클리어하는 것을 고려하십시오.
  4. 위치 크기를 조정하는 모듈 추가
  5. 다른 매개 변수 집합은 다른 시장에 대해 역 테스트 및 최적화 될 수 있습니다.

요약

요약하자면,이 적응 스톱 손실 레일 전략은 칼만 예측과 동적 스톱 손실을 독특하게 결합합니다. 적절한 매개 변수 조정으로 좋은 결과를 얻을 수 있습니다. 추가 모듈화 및 최적화는 더 많은 시장에서 응용을 위해이 전략을 더 완전하게 만들 수 있습니다.


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












더 많은