LPB Microcycles Stratégie de suivi du contour d'oscillation adaptative

Auteur:ChaoZhang est là., Date: le 19 février 2024 11:32:12
Les étiquettes:

img

Résumé

La stratégie utilise le filtre Hodrick-Prescott (HP) pour lisser le prix et extraire la tendance du prix. Elle calcule ensuite un prix moyen pondéré personnalisé (VWAP) en fonction de la plage de temps définie par l'utilisateur.

Principes de stratégie

  1. Utilisez le filtre HP pour extraire la tendance des prix. Le filtre HP utilise des méthodes d'optimisation pour extraire la composante tendance à long terme des prix tout en filtrant les fluctuations à court terme.

  2. Calculer le VWAP en fonction d'une plage de temps personnalisée par l'utilisateur.

  3. Remplissez la condition longue lorsque le prix est au-dessus de la ligne de tendance HP; remplissez la condition courte lorsque le prix est en dessous.

  4. L'ATR stop loss suppose un risque raisonnable et prévient les pertes excessives.

Analyse des avantages

  1. Le filtre HP extrait des tendances de prix plus fluides que les indicateurs basés sur les MA, évitant ainsi de se laisser distraire par les fluctuations de prix à court terme.

  2. Les périodes VWAP personnalisables s'adaptent mieux aux cycles changeants du marché.

  3. Le trading dans la direction de la tendance s'aligne sur les concepts de trading de tendance et présente des taux de gain plus élevés.

  4. ATR contrôle les pertes par transaction, évitant ainsi les pertes de taille excessive.

  5. Les paramètres hautement réglables offrent une plus grande marge d'optimisation pour différents marchés.

Risques et solutions

  1. Le stop loss peut être fréquemment atteint lors de consolidations à plage.

  2. Les retracements de fin de tendance produisent souvent de fausses ruptures qui piégeront la stratégie.

  3. Les paramètres de période VWAP inappropriés peuvent manquer des opportunités de négociation plus efficaces.

Directions d'optimisation

  1. Le paramètre de filtre HP λ ajuste l'intensité de lissage. Un λ plus grand rend la ligne de tendance plus lisse et capte mieux les tendances à long terme; un λ plus petit le rend plus sensible aux changements de prix et convient aux opportunités moyennes à court terme.

  2. Le multiplicateur ATR ajuste la plage d'arrêt des pertes. Il peut se coordonner avec le paramètre λ pour l'optimisation.

  3. Le risque: le ratio de rendement a une incidence directe sur le ratio de P&L. Il peut tester différents ratios pour le contrôle de l'utilisation et le potentiel de profit.

Conclusion

La stratégie adopte généralement une approche de tendance suivante. L'optimisation des paramètres à long terme, moyen et court terme, avec de forts taux de gain et un potentiel de profit. Un contrôle raisonnable des risques empêche les pertes de taille excessive par transaction. En résumé, en extraisant les tendances des prix scientifiquement et des paramètres hautement réglables, la stratégie a de bonnes perspectives d'application.


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

Plus de