Estratégia de negociação dinâmica ajustada para o risco e para o momento

Autora:ChaoZhang, Data: 2024-01-24 11:13:39
Tags:

img

Resumo

Esta estratégia única de negociação baseada em regras sistemáticas está na seguinte categoria de tendência. Ele usa séries de preços normalizadas transformadas de preço de ticker bruto para sinais de negociação de gerenciamento de taxas.

Mecânica da estratégia

O preço normalizado é uma série de retornos diários acumulados ajustados à volatilidade. O lookback do ajuste de volatilidade diário é definido pelo usuário. A média móvel do preço normalizado é usada como o principal indicador de tendência. O período de lookback do HMA também é definido pelo usuário, com um período padrão de 100 dias para um sinal responsivo sem induzir excesso de negociação.

Os principais trades são simples, longos quando o preço é normalizado no cruzamento HMA, curtos quando o preço é cruzado no cruzamento HMA.

O tamanho da posição é ajustado dinamicamente com base na volatilidade recente dos preços e no alvo de risco anual definido pelo usuário. As posições são ponderadas pelo risco, de tamanho maior com menor volatilidade e menor com maior volatilidade. A volatilidade recente é o desvio padrão dos retornos nos últimos 14 períodos, depois extrapolado para a volatilidade anual como retornos esperados. O alvo de risco anual é usado como referência para o dimensionamento de posição ajustado à volatilidade. O alvo padrão é 10% do capital total. O capital inicial deve ser definido como perda máxima por negociação. A alavancagem máxima permite alcançar o alvo de risco se a volatilidade natural subjacente for insuficiente e alivia a volatilidade excessivamente baixa.

As paradas duras são baseadas no multiplicador de faixa real do preço médio recente, configurável pelo utilizador.

Vantagens

  • Os preços normalizados reduzem os falsos sinais
  • Controles dinâmicos de dimensionamento de posição de risco eficaz
  • Paradas duras evitam perdas desproporcionadas
  • Tendência simples seguindo a lógica da transparência

Riscos

  • Problemas de atraso com a média móvel de Hull
  • Limitar os lucros ao mesmo tempo que reduz o risco através do dimensionamento das posições ajustado à volatilidade
  • Fecha muito apertado vulnerável a espinhos

As medidas de controlo do risco incluem selecções alternativas de médias móveis e ajustamento dos objetivos de risco.

Melhorias

  • Eficácia dos ensaios de outros tipos de médias móveis
  • Otimizar os parâmetros das médias móveis
  • Tente apenas variantes longas ou curtas
  • Intervalos de perda de parada de sintonização fina
  • Experimentação com outros mecanismos de stop loss

Conclusão

A estratégia integra várias técnicas como normalização, ajuste dinâmico da posição, paradas duras para controlar riscos. A negociação é baseada em regras simples de tendência. Os parâmetros podem ser ajustados para preferências pessoais e regimes de mercado. Vale a pena testar e verificar mais para aplicação viável no mundo real.


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

Mais.