Dynamische Risikobereinigte Handelsstrategie

Schriftsteller:ChaoZhang, Datum: 2024-01-24 11:13:39
Tags:

img

Übersicht

Diese einzigartige, systematische, regelbasierte Handelsstrategie ist in der folgenden Kategorie zu finden. Sie verwendet normalisierte Preisreihen, die von Rohtickerpreisen in Gernerate-Handelssignale umgewandelt wurden.

Strategie-Mechanik

Der normalisierte Preis ist eine an die Volatilität angepasste kumulierte Tagesrendite. Der Rückblick auf die tägliche Volatilitätsanpassung wird vom Benutzer definiert. Der gleitende Durchschnitt des normalisierten Preises wird als Haupttrendindikator verwendet. Die Rückblicksperiode der HMA wird ebenfalls vom Benutzer definiert, wobei die Standardfrist für ein reaktionsfähiges Signal ohne Überhandel 100 Tage beträgt.

Die Kerngeschäfte sind einfach, bei normalisierter Preiskreuzung HMA lang, bei Kreuzung unter HMA kurz.

Die Positionsgröße wird dynamisch anhand der jüngsten Preisvolatilität und des vom Benutzer definierten Jahresrisikoziels angepasst. Die Positionen sind risikogewichtet, größere Größe mit niedrigerer Volatilität und kleinere mit höherer Volatilität. Die jüngste Volatilität ist die Standardabweichung der Renditen in den letzten 14 Perioden, die dann als erwartete Renditen in die jährliche Volatilität extrapoliert wird. Das jährliche Risikoziel wird als Referenz für die volatilitätsbereinigte Positionsgröße verwendet. Das Standardziel beträgt 10% des Gesamtkapitals. Das Anfangskapital sollte als maximaler Verlust pro Handel festgelegt werden. Maximaler Hebel ermöglicht das Erreichen des Risikoziels, wenn die zugrunde liegende natürliche Volatilität unzureichend ist, und lindert übermäßig niedrige Volatilität.

Hard Stops basieren auf dem multiplikator für den aktuellen durchschnittlichen Preis, der vom Benutzer konfiguriert werden kann.

Vorteile

  • Normalisierte Preise verringern falsche Signale
  • Dynamische Positionsdimensionierung steuert Risiken wirksam
  • Harden Stopps verhindern Verluste
  • Einfache Tendenz nach Transparenzlogik

Risiken

  • Probleme mit dem gleitenden Durchschnitt von Hull
  • Gewinnbegrenzung bei gleichzeitiger Verringerung des Risikos durch volatilitätsbereinigte Positionsgröße
  • Zu eng, anfällig für Stacheln

Zu den Maßnahmen zur Risikokontrolle gehören alternative gleitende Durchschnittswerte und die Anpassung von Risikobegriffen.

Verbesserungen

  • Prüfwirksamkeit anderer Arten gleitender Durchschnitte
  • Optimierung der Parameter der gleitenden Durchschnitte
  • Versuchen Sie nur lange oder nur kurze Varianten
  • Feinstuning-Stopp-Verlustbereiche
  • Experimente mit anderen Stop-Loss-Mechanismen

Schlussfolgerung

Die Strategie integriert verschiedene Techniken wie Normalisierung, dynamische Positionsanpassung, Hard Stops zur Risikokontrolle. Der Handel basiert auf einfachen Regeln, die dem Trend folgen. Die Parameter können an persönliche Präferenzen und Marktregime angepasst werden. Für eine praktikable Anwendung in der realen Welt lohnt es sich, weiter zu testen und zu überprüfen.


/*backtest
start: 2023-01-17 00:00:00
end: 2024-01-23 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/
// © Crunchster1

//@version=5
strategy(title="Crunchster's Normalised Trend Strategy", shorttitle="Normalised Trend Strategy", overlay=false )

// Inputs and Parameters
src = input(close, 'Source', group='Strategy Settings')
length = input.int(title="Lookback period for price normalisation filter", defval=14, minval=2, group='Strategy Settings', tooltip='This sets the lookback period for the volatility adjustment of returns, which is used to transform the price series into the "real price"')
hlength = input.int(title="Lookback period for Hull Moving Average", defval=100, minval=2, group='Strategy Settings')
offset = input.int(title="HMA Offset", defval=0, minval=0, group='Strategy Settings')
long = input(true, 'Long', inline='08', group='Strategy Settings')
short = input(true, 'Short', inline='08', group='Strategy Settings', tooltip='Toggle long/short strategy on/off')

stopMultiple = input.float(1, 'Stop multiple', step=0.25, group='Risk Management Settings', tooltip='Multiple for ATR, setting hard stop loss from entry price')
lev = input.float(1, 'Max Leverage', step=0.5, group='Risk Management Settings', tooltip='Max leverage sets maximum allowable leverage of total capital (initial capital + any net profit), capping maximum volatility adjusted position size')
riskT = input.float(10, maxval=75, title='Annualised Volatility Target %', group='Risk Management Settings', tooltip='Specify annual risk target, used to determine volatility adjusted position size. Annualised daily volatility is referenced to this value and position size adjusted accordingly')
comp = input(false, 'Compounding', inline='09', group='Risk Management Settings')
Comppct = input.float(50, '%', step=5, inline='09', group='Risk Management Settings', tooltip='Toggle compounding of profit, and set % of profit to compound')

// Backtesting period
FromDay = input.int(defval=1, title='From Day', minval=1, maxval=31, inline='04', group='Backtest range')
FromMonth = input.int(defval=1, title='From Mon', minval=1, maxval=12, inline='04', group='Backtest range')
FromYear = input.int(defval=2018, title='From Yr', minval=1900, inline='04', group='Backtest range', tooltip='Set start of backtesting period')
ToDay = input.int(defval=1, title='To Day', minval=1, maxval=31, inline='05', group='Backtest range')
ToMonth = input.int(defval=1, title='To Mon', minval=1, maxval=12, inline='05', group='Backtest range')
ToYear = input.int(defval=9999, title='To Yr', minval=1900, inline='05', group='Backtest range', tooltip='Set end of backtesting period')

start = timestamp(FromYear, FromMonth, FromDay, 00, 00)
finish = timestamp(ToYear, ToMonth, ToDay, 23, 59)
window = true

// Normalised returns calculation
nRet = (src - src[1]) / ta.stdev((src - src[1]), length)

nPrice = ta.cum(nRet)

//Hull Moving Average - using normalised price series
fHMA = ta.wma(2 * ta.wma(nPrice[offset], hlength / 2) - ta.wma(nPrice[offset], hlength), math.round(math.sqrt(hlength)))

//Risk Management formulae
strategy.initial_capital = 50000
tr = math.max(high - low, math.abs(high - close), math.abs(low - close)) //True range
stopL = ta.sma(tr, 14) //Average true range
stdev = ta.stdev(close-close[1], 14) //volatility of recent returns
maxcapital = strategy.initial_capital+strategy.netprofit //Maximum capital available to invest - initial capital net of profit
annvol = 100*math.sqrt(365)*stdev/close //converts recent volatility of returns into annualised volatility of returns - assumes daily timeframe

risk = 1.1
if comp
    risk := (strategy.initial_capital+(Comppct*strategy.netprofit/100))//adjust investment capital to include compounding
else
    risk := strategy.initial_capital

shares = (risk * (riskT/annvol)) / close //calculates volatility adjusted position size, dependent on user specified annualised risk target
if ((shares*close) > lev*maxcapital) //ensures position size does not exceed available capital multiplied by user specified maximum leverage
    shares := lev*maxcapital/close

//To set the price at the entry point of trade
Posopen() =>
    math.abs(strategy.position_size[1]) <= 0 and math.abs(strategy.position_size) > 0

var float openN = na
if Posopen()
    openN := stopL

// Strategy Rules
if long
    longCondition = ta.crossover(nPrice, fHMA) and window
    exitlong = ta.crossunder(nPrice, fHMA)
    if (longCondition)
        strategy.entry('Go Long!', strategy.long, qty=shares)
    if strategy.position_size > 0    
        strategy.exit('Stop Long', from_entry = 'Go Long!', stop=(strategy.opentrades.entry_price(0) - (openN * stopMultiple)))
    if (exitlong)
        strategy.close('Go Long!', immediately = true)

if short
    shortCondition = ta.crossunder(nPrice, fHMA) and window
    exitshort = ta.crossover(nPrice, fHMA)
    if (shortCondition)
        strategy.entry('Go Short!', strategy.short, qty=shares)
    if strategy.position_size < 0   
        strategy.exit('Stop Short', from_entry = 'Go Short!', stop=(strategy.opentrades.entry_price(0) + (openN * stopMultiple)))
    if (exitshort)
        strategy.close('Go Short!', immediately = true)

// Visuals of trend and direction
plot(nPrice, title='Real Price', color=color.black)

MAColor = fHMA > fHMA[3] ? #00ff00 : #ff0000
MA1 = plot(fHMA, title='Hull MA', color=MAColor)
MA2 = plot(fHMA[3], title='Hull MA Offset', color=MAColor)
fill(MA1, MA2, title='Band Filler', color=MAColor)

Mehr