LPB-Mikrozyklen Adaptive Oszillationskonturverfolgungsstrategie

Schriftsteller:ChaoZhang, Datum: 2024-02-19 11:32:12
Tags:

img

Übersicht

Die Strategie verwendet den Hodrick-Prescott (HP) Filter, um den Preis zu glätten und den Preistrend zu extrahieren. Dann berechnet sie einen angepassten gewichteten Durchschnittspreis (VWAP) basierend auf dem vom Benutzer definierten Zeitrahmen.

Strategieprinzipien

  1. HP-Filter verwendet Optimierungsmethoden, um die langfristige Trendkomponente der Preise zu extrahieren und gleichzeitig kurzfristige Schwankungen auszufiltern.

  2. Berechnen Sie VWAP basierend auf dem vom Benutzer angepassten Zeitrahmen. VWAP kann die durchschnittlichen Preise über die Perioden hinweg genauer abbilden.

  3. Erfüllen Sie die Long-Bedingung, wenn der Preis über der HP-Trendlinie liegt; Erfüllen Sie die Short-Bedingung, wenn der Preis unterhalb liegt. Dies erfasst Aufbruch oder Abbruch.

  4. Die ATR-Stop-Loss-Regelung setzt ein angemessenes Risiko voraus und verhindert übermäßige Verluste.

Analyse der Vorteile

  1. Der HP-Filter extrahiert reibungslosere Kursentwicklungen als die auf MA basierenden Indikatoren und vermeidet Ablenkungen durch kurzfristige Kursschwankungen.

  2. Anpassungsfähige VWAP-Perioden passen sich besser an sich ändernde Marktzyklen an.

  3. Der Handel entlang der Trendrichtung entspricht den Konzepten des Trendhandels und hat höhere Gewinnraten.

  4. ATR-Stop Loss kontrolliert Verluste pro Handel und verhindert übergroße Verluste.

  5. Hochverstellbare Parameter bieten einen größeren Optimierungsraum für verschiedene Märkte.

Risiken und Lösungen

  1. Der Stop-Loss kann während der Konsolidierung in der Bandbreite häufig getroffen werden.

  2. Der Trend end-retracements produzieren oft falsche Ausbrüche, die die Strategie zu fangen. sollte mit anderen Indikatoren kombiniert werden, um Ende der Trends und schließen Positionen rechtzeitig zu identifizieren.

  3. Bei falschen VWAP-Perioden-Einstellungen können effektivere Handelsmöglichkeiten verpasst werden.

Optimierungsrichtlinien

  1. Der HP-Filterparameter λ passt die Glättungsintensivität an. Ein größeres λ macht die Trendlinie glänzer und erfasst langfristige Trends besser; ein kleineres λ macht sie reaktionsschneller auf Preisänderungen und eignet sich für mittlere Short-Möglichkeiten.

  2. Der ATR-Multiplikator regelt den Stop-Loss-Bereich. Kann mit dem λ-Parameter zur Optimierung koordinieren. Größeres λ garantiert breitere Stopps; kleineres λ ermöglicht engere Stopps und sperrt mehr Gewinne.

  3. Risiko: Die Gewinnquote beeinflusst die Gewinn- und Verlustquote unmittelbar.

Schlussfolgerung

Die Strategie verfolgt insgesamt einen Trendfolgungsansatz. Umfangreiche Parameter-Tuning zielt auf die Optimierung über lange, mittlere und kurze Zeitrahmen hinweg mit starken Gewinnraten und Gewinnpotenzial ab. Eine vernünftige Risikokontrolle verhindert übergroße Verluste pro Handel. Zusammenfassend lässt sich sagen, dass die Strategie durch die wissenschaftliche Extraktion von Preistrends und hochstabilisierbaren Parametern gute Anwendungsperspektiven hat.


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

Mehr