다중 시간 규모 적응 진동 프로파일 추적 전략


생성 날짜: 2024-02-19 11:32:12 마지막으로 수정됨: 2024-02-19 11:32:12
복사: 2 클릭수: 564
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

다중 시간 규모 적응 진동 프로파일 추적 전략

개요

이 전략은 호드릭-프레스콧 (Hodrick-Prescott, HP) 필터를 사용하여 가격을 평형화하고 가격 트렌드 라인을 추출합니다. 그리고 사용자 정의 된 시간 범위를 기반으로 사용자 정의 된 중화 평균 가격을 계산합니다. 가격이 트렌드 라인보다 높을 때 더 많이하고, 낮은 경우 더 많이하지 않습니다.

전략 원칙

  1. HP 필터를 사용하여 가격 트렌드 라인을 추출한다. HP 필터는 최적화 방법을 통해 가격의 장기 트렌드 성분을 추출하고, 단기 변동의 방해를 제거한다.

  2. 사용자 지정된 시간 범위를 기반으로 VWAP를 계산한다. VWAP는 다른 주기에서의 평균 가격을 더 정확하게 나타낸다.

  3. 가격이 HP 트렌드 라인보다 높을 때 다중 조건이 충족되고, 가격이 HP 트렌드 라인보다 낮을 때 공백 조건이 충족된다. 이렇게 하면 가격이 아래에서 위로 또는 위에서 아래로 돌파구를 잡을 수 있다.

  4. ATR 상쇄는 합리적인 위험을 감수하고 과도한 손실을 방지합니다.

우위 분석

  1. HP 필터를 사용하여 가격 동향을 추출하고, MA와 같은 지표에 비해 더 부드럽고, 단기 가격 변동에 착각하지 않도록 한다.

  2. 사용자 정의 VWAP 주기, 시장 주기 변화에 더 유연하게 적응한다.

  3. 트렌드 방향에 따라 거래하는 것은 트렌드 트레이딩 철학에 부합하며, 승률이 높다.

  4. ATR는 단편 손실을 통제하여 과대 손실을 방지합니다.

  5. 다양한 매개 변수들을 조정할 수 있으며, 다양한 시장에 맞게 최적화할 수 있다.

위험과 대책

  1. 진동 디스크 정리에서 스탠다드 손실이 발생할 수 있다. 스탠다드 손실 범위를 적절히 완화할 수 있다.

  2. 트렌드 말기 ClientRawResponse는 종종 회귀 시동 탐색적 돌파구가 발생하여 전략이 좌우된다. 다른 지표와 결합하여 트렌드 말기, 적시에 평정해야 한다.

  3. VWAP 주기 설정이 부적절하면 더 효과적인 거래 기회를 놓칠 수 있다. VWAP 주기 조정은 트렌드 지표의 동적으로 이루어져야 한다.

최적화 방향

1.HP 필터 변수 λ은 평준화 강도를 조정할 수 있다. △λ 값은 큰 시간에 트렌드 라인이 더 부드럽고, 긴 선의 트렌드를 잡는 데 더 유리하다. △λ 값은 시간의 가격 변화에 더 민감하며, 중간에 짧은 선의 기회를 잡는 데 더 적합하다.

  1. ATR 배수는 손해의 범위를 조정할 수 있다.λ 변수 최적화와 연동할 수 있으며,λ 값이 커지면 손해의 범위를 적절히 확장할 수 있다.λ 값이 작으면 손해의 범위를 축소하여 더 많은 이익을 잠금할 수 있다.

  2. 리스크 수익률 (R:R) 은 수익/손실 비율에 직접적으로 영향을 미칩니다. 회수 제어와 수익성을 테스트할 수 있는 다른 배수 조건이 있습니다.

요약하다

이 전략은 전체적으로 트렌드 추적 아이디어 디자인을 채택한다. 여러 가지 매개 변수 설정을 통해 중·단기 다른 시간 주기에 대해 최적화 할 수 있으며, 승률과 수익성이 강하다. 위험 제어 측면에서도 어느 정도 고려가 이루어져 단편 손실이 너무 크지 않도록 효과적으로 보장한다. 전반적으로 이 전략은 보다 과학적인 방법을 사용하여 가격 트렌드 특성을 추출하고, 매개 변수 최적화 공간이 큰 특성과 결합하여 적용 전망이 좋다.

전략 소스 코드
/*backtest
start: 2024-02-17 00:00:00
end: 2024-02-18 00:00:00
period: 1h
basePeriod: 15m
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/
// © tathal animouse hajixde

//@version=4
strategy("LPB MicroCycles Strategy", "HPVWAP", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, max_bars_back=5000)
startDate = input(title="Start Date", type=input.integer,
     defval=1, minval=1, maxval=31)
startMonth = input(title="Start Month", type=input.integer,
     defval=1, minval=1, maxval=12)
startYear = input(title="Start Year", type=input.integer,
     defval=2010, minval=1800, maxval=2100)

endDate = input(title="End Date", type=input.integer,
     defval=31, minval=1, maxval=31)
endMonth = input(title="End Month", type=input.integer,
     defval=12, minval=1, maxval=12)
endYear = input(title="End Year", type=input.integer,
     defval=2021, minval=1800, maxval=2100)
     
// STEP 2:
// Look if the close time of the current bar
// falls inside the date range
inDateRange = true

///

// Strategy Settings
var g_strategy      = "Strategy Settings"
stopMultiplier      = input(title="Stop Loss ATR", type=input.float, defval=1.0, group=g_strategy, tooltip="Stop loss multiplier (x ATR)")
rr                  = input(title="R:R", type=input.float, defval=1.0, group=g_strategy, tooltip="Risk:Reward profile")

/// Backtester Settings
var g_tester        = "Backtester Settings"
startBalance        = input(title="Starting Balance", type=input.float, defval=10000.0, group=g_tester, tooltip="Your starting balance for the custom inbuilt tester system")
riskPerTrade        = input(title="Risk Per Trade", type=input.float, defval=1.0, group=g_tester, tooltip="Your desired % risk per trade (as a whole number)")
drawTester          = input(title="Draw Backtester", type=input.bool, defval=true, group=g_tester, tooltip="Turn on/off inbuilt backtester display")

////////////////INPUTS///////////////////
lambda = input(defval = 1000, type = input.float, title = "Smoothing Factor (Lambda)", minval = 1)
leng = input(defval = 100, type = input.integer, title = "Filter Length", minval = 1)
src = ohlc4
atr = atr(14)

///////////Construct Arrays///////////////
a = array.new_float(leng, 0.0) 
b = array.new_float(leng, 0.0)
c = array.new_float(leng, 0.0)
d = array.new_float(leng, 0.0)
e = array.new_float(leng, 0.0)
f = array.new_float(leng, 0.0)

/////////Initialize the Values///////////

ll1 = leng-1
ll2 = leng-2

for i = 0 to ll1
    array.set(a,i, lambda*(-4))
    array.set(b,i, src[i])
    array.set(c,i, lambda*(-4))
    array.set(d,i, lambda*6 + 1)
    array.set(e,i, lambda)
    array.set(f,i, lambda)

array.set(d, 0,  lambda + 1.0)
array.set(d, ll1, lambda + 1.0)
array.set(d, 1,  lambda * 5.0 + 1.0)
array.set(d, ll2, lambda * 5.0 + 1.0)

array.set(c, 0 , lambda * (-2.0))
array.set(c, ll2, lambda * (-2.0))

array.set(a, 0 , lambda * (-2.0))
array.set(a, ll2, lambda * (-2.0))

//////////////Solve the optimization issue/////////////////////
float r = array.get(a, 0)
float s = array.get(a, 1)
float t = array.get(e, 0)
float xmult = 0.0

for i = 1 to ll2
    xmult := r / array.get(d, i-1) 
    array.set(d, i, array.get(d, i) - xmult * array.get(c, i-1))
    array.set(c, i, array.get(c, i) - xmult * array.get(f, i-1))
    array.set(b, i, array.get(b, i) - xmult * array.get(b, i-1))

    xmult := t / array.get(d, i-1)
    r     := s - xmult*array.get(c, i-1)
    array.set(d, i+1, array.get(d, i+1) - xmult * array.get(f, i-1))
    array.set(b, i+1, array.get(b, i+1) - xmult * array.get(b, i-1))
    
    s     := array.get(a, i+1)
    t     := array.get(e, i)

xmult := r / array.get(d, ll2)
array.set(d, ll1, array.get(d, ll1) - xmult * array.get(c, ll2))

x = array.new_float(leng, 0) 
array.set(x, ll1, (array.get(b, ll1) - xmult * array.get(b, ll2)) / array.get(d, ll1))
array.set(x, ll2, (array.get(b, ll2) - array.get(c, ll2) * array.get(x, ll1)) / array.get(d, ll2))

for j = 0 to leng-3
    i = leng-3 - j
    array.set(x, i, (array.get(b,i) - array.get(f,i)*array.get(x,i+2) - array.get(c,i)*array.get(x,i+1)) / array.get(d, i))



//////////////Construct the output///////////////////
HP = array.get(x,0)

///////////////Custom VWAP////////////////////////
TimeFrame = input('1', type=input.resolution)
start = security(syminfo.tickerid, TimeFrame, time)

//------------------------------------------------
newSession = iff(change(start), 1, 0)
//------------------------------------------------
vwapsum = 0.0
vwapsum := iff(newSession, HP*volume, vwapsum[1]+HP*volume)
volumesum = 0.0
volumesum := iff(newSession, volume, volumesum[1]+volume)
v2sum = 0.0
v2sum := iff(newSession, volume*HP*HP, v2sum[1]+volume*HP*HP)
myvwap = vwapsum/volumesum
dev = sqrt(max(v2sum/volumesum - myvwap*myvwap, 0))
Coloring=close>myvwap?color.new(#81c784, 62):color.new(#c2185b, 38)
av=myvwap
showBcol = input(true, type=input.bool, title="Show barcolors")


///////////////Entry & Exit///////////////////

// Custom function to convert pips into whole numbers
toWhole(number) =>
    return = atr < 1.0 ? (number / syminfo.mintick) / (10 / syminfo.pointvalue) : number
    return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return * 100 : return
    
// Custom function to convert whole numbers back into pips
toPips(number) =>
    return = atr >= 1.0 ? number : (number * syminfo.mintick) * (10 / syminfo.pointvalue)
    return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return / 100 : return
    
// Custom function to truncate (cut) excess decimal places
truncate(_number, _decimalPlaces) =>
    _factor = pow(10, _decimalPlaces)
    int(_number * _factor) / _factor


///////////////Conditional Strategy Logic//////////////
Long = crossover(av, ohlc4)
Sell = crossunder(av, ohlc4)

// Check if we have confirmation for our setup
validLong = Long and strategy.position_size == 0 and inDateRange and barstate.isconfirmed
validShort = Sell and strategy.position_size == 0 and inDateRange and barstate.isconfirmed


// Calculate our stop distance & size for the current bar
stopSize = atr * stopMultiplier
longStopPrice = low < low[1] ? low - stopSize : low[1] - stopSize
longStopDistance = close - longStopPrice
longTargetPrice = close + (longStopDistance * rr)


// Save trade stop & target & position size if a valid setup is detected
var t_entry = 0.0
var t_stop = 0.0
var t_target = 0.0
var t_direction = 0

// Detect valid long setups & trigger alert
if validLong
    t_entry := close
    t_stop := longStopPrice
    t_target := longTargetPrice
    t_direction := 1
    strategy.entry(id="Long", long=strategy.long, when=validLong, comment="(SL=" + tostring(truncate(toWhole(longStopDistance),2)) + " pips)")
    // Fire alerts
    alert(message="Long Detected", freq=alert.freq_once_per_bar_close)
    
// Check if price has hit long stop loss or target
if t_direction == 1 and (low <= t_stop or high >= t_target)
    t_direction := 0

// Check if price has hit short stop loss or target
if t_direction == -1 and (high >= t_stop or low <= t_target)
    t_direction := 0


// Exit trades whenever our stop or target is hit
strategy.exit(id="Long Exit", from_entry="Long", limit=t_target, stop=t_stop, when=strategy.position_size > 0)

// Draw trade data
plot(strategy.position_size != 0 or validLong? t_stop : na, title="Trade Stop Price", color=color.red, style=plot.style_linebr)
plot(strategy.position_size != 0 or validLong? t_target : na, title="Trade Target Price", color=color.green, style=plot.style_linebr)

/////////////////////Plotting//////////////////////////

A=plot(av, color=Coloring, title="HP VWAP")

barcolor(showBcol?Coloring:na)

fill(A, plot(ohlc4), Coloring)

// Draw price action setup arrows
plotshape(validLong ? 1 : na, style=shape.triangleup, location=location.belowbar, color=color.green, title="Bullish Setup")

// // --- BEGIN TESTER CODE --- //
// // Declare performance tracking variables
// var balance = startBalance
// var drawdown = 0.0
// var maxDrawdown = 0.0
// var maxBalance = 0.0
// var totalPips = 0.0
// var totalWins = 0
// var totalLoss = 0

// // Detect winning trades
// if strategy.wintrades != strategy.wintrades[1]
//     balance := balance + ((riskPerTrade / 100) * balance) * rr
//     totalPips := totalPips + abs(t_entry - t_target)
//     totalWins := totalWins + 1
//     if balance > maxBalance
//         maxBalance := balance
        
// // Detect losing trades
// if strategy.losstrades != strategy.losstrades[1]
//     balance := balance - ((riskPerTrade / 100) * balance)
//     totalPips := totalPips - abs(t_entry - t_stop)
//     totalLoss := totalLoss + 1
//     // Update drawdown
//     drawdown := (balance / maxBalance) - 1
//     if drawdown < maxDrawdown
//         maxDrawdown := drawdown
        
// // Prepare stats table
// var table testTable = table.new(position.top_right, 5, 2, border_width=1)
// f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
//     _cellText = _title + "\n" + _value
//     table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor)
    
// // Draw stats table
// var bgcolor = color.new(color.black,0)
// if drawTester
//     if barstate.islastconfirmedhistory
//         // Update table
//         dollarReturn = balance - startBalance
//         f_fillCell(testTable, 0, 0, "Total Trades:", tostring(strategy.closedtrades), bgcolor, color.white)
//         f_fillCell(testTable, 0, 1, "Win Rate:", tostring(truncate((strategy.wintrades/strategy.closedtrades)*100,2)) + "%", bgcolor, color.white)
//         f_fillCell(testTable, 1, 0, "Starting:", "$" + tostring(startBalance), bgcolor, color.white)
//         f_fillCell(testTable, 1, 1, "Ending:", "$" + tostring(truncate(balance,2)), bgcolor, color.white)
//         f_fillCell(testTable, 2, 0, "Return:", "$" + tostring(truncate(dollarReturn,2)), dollarReturn > 0 ? color.green : color.red, color.white)
//         f_fillCell(testTable, 2, 1, "Pips:", (totalPips > 0 ? "+" : "") + tostring(truncate(toWhole(totalPips),2)), bgcolor, color.white)
//         f_fillCell(testTable, 3, 0, "Return:", (dollarReturn > 0 ? "+" : "") + tostring(truncate((dollarReturn / startBalance)*100,2)) + "%", dollarReturn > 0 ? color.green : color.red, color.white)
//         f_fillCell(testTable, 3, 1, "Max DD:", tostring(truncate(maxDrawdown*100,2)) + "%", color.red, color.white)
// // --- END TESTER CODE --- //