Estratégia de negociação quantitativa híbrida de dois indicadores

Autora:ChaoZhang, Data: 2023-12-20 10:31:06
Tags:

img

Resumo

Esta estratégia combina dois indicadores para identificar a direção da tendência e fazer negociações. Em primeiro lugar, usa o cruzamento de duas médias móveis (rápidas e médias) para julgar a tendência de curto prazo; em segundo lugar, usa a faixa de canal e a média móvel de longo prazo para determinar a direção da tendência principal. Os sinais de negociação são gerados apenas quando os dois julgamentos são consistentes. A estratégia híbrida usando vários indicadores pode efetivamente filtrar falsos sinais e melhorar a estabilidade.

Princípio da estratégia

A estratégia usa três conjuntos de indicadores para julgamento. Primeiro, a cruz de ouro e a cruz da morte da EMA rápida (26 períodos) e da EMA média (50 períodos) para determinar a tendência de curto prazo; em segundo lugar, calcule o intervalo do canal para julgar a tendência de médio prazo; finalmente, calcule a SMA de longo prazo (200 períodos) e compare com o preço para determinar a direção da tendência principal. Os sinais de negociação são gerados apenas quando todos os três julgamentos são consistentes.

Especificamente, a lógica é:

  1. Crossover de médias móveis rápidas e médias (cruz de ouro para alta, cruz de morte para baixa) para determinar a tendência de curto prazo.

  2. Se o preço atravessa o intervalo do canal para determinar a tendência de médio prazo. O intervalo do canal é baseado no MA de longo prazo mais/menos ATR vezes um coeficiente. Quebrar o limite superior sinaliza alta, quebrar os sinais de limite inferior baixa.

  3. Comparar o preço com o MA a longo prazo para determinar a tendência principal.

Por último, os sinais de negociação só são gerados quando os três julgamentos são consistentes.

Vantagens da estratégia

Esta estratégia híbrida de dois indicadores tem várias vantagens:

  1. Filtrar efetivamente os falsos sinais e melhorar a estabilidade. Porque os sinais de negociação precisam de validação de múltiplos indicadores para evitar erros de uma única métrica.

  2. Alta flexibilidade para ajustar parâmetros para diferentes mercados.

  3. Combine a negociação de tendências e a negociação de intervalos. Os indicadores de médio e curto prazo capturam tendências, o indicador de longo prazo determina o intervalo.

  4. Eficiência de utilização de capital elevada. Coloque ordens apenas quando vários indicadores concordarem, o capital pode ser eficazmente utilizado para evitar transacções desnecessárias.

Riscos estratégicos

Há também alguns riscos:

  1. Parâmetro de definição do risco: os períodos de MA e a gama de canais precisam de uma configuração adequada, as configurações inadequadas podem não detectar tendências ou causar sinais falsos excessivos.

  2. Aumentar o custo de oportunidade dos indicadores duais Em comparação com as estratégias de indicador único, algumas oportunidades de negociação podem ser perdidas, incapazes de entrar e sair nos pontos ideais.

  3. O mecanismo de stop loss precisa de prudência. O stop loss de ruptura aqui pode causar perdas desnecessárias. A porcentagem de stop loss precisa de uma configuração cuidadosa.

  4. Esta estratégia funciona melhor em mercados com tendência aparente.

Optimização da Estratégia

A estratégia pode ser melhorada pelos seguintes aspectos:

  1. Teste diferentes combinações de parâmetros para encontrar o ideal. Mais backtests com dados históricos para localizar configurações ideais.

  2. Adicionar mecanismo de stop loss adaptativo.

  3. Ajudar com indicadores de volume em pontos críticos, avaliar o tamanho da posição com volume para melhorar a eficiência do capital.

  4. Otimizar a lógica de entrada: considerar entradas escalonadas com média de custos para reduzir o risco de entrada única.

  5. Combinar modelos de aprendizagem de máquina, introduzir redes neurais para avaliar a robustez e a aptidão do modelo.

Resumo

Esta estratégia aproveita indicadores de quadro de tempo triplo e validação dupla para suprimir sinais falsos e melhorar a estabilidade. Enquanto isso, possui os méritos de ambos os trends e range trading, com alta eficiência de uso de capital. Pode ser aprimorada através de otimização de parâmetros, sintonização de stop loss, integração com indicadores de volume, etc. Uma estratégia quantitativa híbrida recomendada.


/*backtest
start: 2023-11-19 00:00:00
end: 2023-12-19 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5
// Indicator to combines:
//           Trend Channel[Gu5] (SMA 200) +
//           EMA's cross  (26, 50 ) +
//           Golden Cross (50, 200)
// Author: @gu5tavo71 08/2019
// v2.3.6, 2022.02.18
// Trend Channel [Gu5] // Author: @gu5tavo71 08/2019
//
// This source code is subject to these terms:
// Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
// https://www.safecreative.org/work/2202190517452-mix1-ema-cross-trend-channel-gu5-
// You are free to:
// Share, copy and redistribute this script
// Adapt, transform and build on this script
// Under the following terms:
// Non-commercial: You cannot sell my indicator. You can't sell my work.
// Attribution: If you post part of my code, you must give me proper credit
//
// I am using part of this code published by @PineCoders and Public Library
// Disclaimer: I am not a financial advisor.
//             For purpose educate only. Use at your own risk.
strategy(title = 'Mix1 : Ema Cross + Trend Channel [Gu5] - Backtest', shorttitle = 'Mix01', overlay = true,
  initial_capital = 100,
  default_qty_value = 100,
  default_qty_type = strategy.percent_of_equity,
  commission_value = 0.075,
  commission_type = strategy.commission.percent,
  format = format.price,
  precision = 2,
  process_orders_on_close = true)


// ---------   Inputs                       "=============================="           |
i_maSrc      = input.source     (close,     'MA Source'                     , group    = 'EMAs')
i_maFast1    = input.int        (26,        'EMA Fast'                      , group    = 'EMAs')
i_maFast2    = input.int        (50,        'EMA Medium'                    , group    = 'EMAs')
i_maLen      = input.int        (200,       'MA Trend'                      , group    = 'Trend Channel')
o_maLen1     =                              'EMA'
o_maLen2     =                              'SMA'
i_maLenSel   = input.string     (o_maLen2,  'MA Type'                       , group    = 'Trend Channel',
               options = [o_maLen1, o_maLen2],
               tooltip = "EMA or SMA")
i_htf        = input.timeframe  ('',        'Select Higher Timeframe'       , tooltip  = 'Only for MA Trend'  , group    = 'Trend Channel')
i_rangeLen   = input.float      (0.618,     'Channel Range Length'          , tooltip  = 'ATR of the MA Trend', group    = 'Trend Channel')
i_slOn       = input.bool       (false,     '■ Stop Loss On/Off'            , group    = 'Stop Loss')
i_sl         = input.float      (2.618,     'SL %'                          , step     = 0.1, group    = 'Stop Loss')
i_periodSw   = input.bool       (true,      '■ Period On/Off'               , group    = 'Period')
o_start      = timestamp        (           '2020-01-01 00:00 GMT-3'        )
o_end        = timestamp        (           '2099-12-31 00:00 GMT-3'        )
i_periodStar = input       (o_start,   'Start Time'                    , group    = 'Period')
i_periodEnd  = input       (o_end,     'End Time'                      , group    = 'Period')
o_posSel1    =                              'Only Long'
o_posSel2    =                              'Only Short'
o_posSel3    =                              'Both'
i_posSel     = input.string     (o_posSel3, 'Position Type'                 , group   = 'Strategy',
               options = [o_posSel1, o_posSel2, o_posSel3],
               tooltip = "Only Long, Only short or Both")
o_typeS1     =                              'Strategy 1'
o_typeS2     =                              'Strategy 2'
i_typeS      = input.string     (o_typeS2,  'Strategy Type'                 , group   = 'Strategy',
               options = [o_typeS1, o_typeS2],
               tooltip = "Strategy 1:\nLong, when the price (close) crosses the ema.\nStrategy 2:\nLong, only when ema goes up")
i_barColOn   = input.bool       (true,      '■ Bar Color On/Off'            , group   = 'Display')
i_alertOn    = input.bool       (false,     '■ Alert On/Off'                , group   = 'Display')
i_channelOn  = input.bool       (false,     '■ Channel Range On/Off'        , tooltip = 'If the price (close) is over than the channel, the trend is bullish. If the price is under, bearish. And if the price is in the channel, it is in range', group   = 'Display')
i_goldenOn   = input.bool       (false,     '■ Golden Cross On/Off'         )
o_alert      =                              '{{strategy.order.comment}}'
i_alert      = input.string     (o_alert,   'Setting alert'                 , tooltip = 'For Alerts, just copy {{strategy.order.comment}} and paste in alert window.', group   = 'Display')

// ---------   Calculations
maFast1      = ta.ema(i_maSrc, i_maFast1)
maFast2      = ta.ema(i_maSrc, i_maFast2)
maDir        = maFast1 > maFast2 ? 1 : -1
maTrend      = request.security(syminfo.tickerid, i_htf,
               i_maLenSel == "SMA" ? ta.sma(close, i_maLen)[1] : ta.ema(close, i_maLen)[1],
               lookahead = barmerge.lookahead_on)  //No repaint
maTrendDir   = i_maSrc >= maTrend ? 1 : -1
rangeAtr     = ta.atr(i_maLen) * i_rangeLen
rangeTop     = maTrend + rangeAtr
rangeBot     = maTrend - rangeAtr
rangeCh      = (open <= rangeTop or close <= rangeTop) and
               (open >= rangeBot or close >= rangeBot)
trendDir     = i_typeS  ==  'Strategy 1'                            ?
               rangeCh                                                ?  0 :
               maTrendDir ==  1 and maDir ==  1 and maTrend > maFast2 ?  0 :
               maTrendDir == -1 and maDir == -1 and maTrend < maFast2 ?  0 :
               maTrendDir ==  1 and maDir ==  1                       ?  1 :
               maTrendDir == -1 and maDir == -1                       ? -1 : 0 :
               rangeCh                                                ?  0 :
               maTrendDir ==  1 and maDir ==  1                       ?  1 :
               maTrendDir == -1 and maDir == -1                       ? -1 : 0
GCross       = i_goldenOn ? ta.crossover (maFast2, maTrend) : na
DCross       = i_goldenOn ? ta.crossunder(maFast2, maTrend) : na

period       = true
// Set initial values
condition    = 0.0
entryLong    = trendDir ==  1 and
               i_posSel != 'Only Short' and
               (i_periodSw ? period : true)
entryShort   = trendDir == -1 and
               i_posSel != 'Only Long' and
               (i_periodSw ? period : true)
exitLong     = (trendDir !=  1 or maDir == -1) and
               condition[1] == 1 and 
               i_posSel != 'Only Short' and
               (i_periodSw ? period : true)
exitShort    = (trendDir != -1 or maDir ==  1) and
               condition[1] == -1 and
               i_posSel != 'Only Long' and
               (i_periodSw ? period : true)
closeCond    = exitLong or exitShort
// Stop Loss (sl)
slEntry      = close * i_sl / 100
slTop        = close + slEntry
slBot        = close - slEntry
slTopBuff    = ta.valuewhen(condition[1] !=  1 and entryLong,  slBot, 0)
slBotBuff    = ta.valuewhen(condition[1] != -1 and entryShort, slTop, 0)
slLine       = condition[1] == -1 and entryLong  ? slTopBuff :
               condition[1] ==  1 and entryShort ? slBotBuff :
               condition[1] ==  1  or entryLong  ? slTopBuff :
               condition[1] == -1  or entryShort ? slBotBuff : na
slTopCross   = condition[1] ==  1 and ta.crossunder(close, slLine) or high > slLine and low < slLine
slBotCross   = condition[1] == -1 and ta.crossover (close, slLine) or high > slLine and low < slLine
slExit       = i_slOn ? slTopCross or slBotCross : na
// Conditions
condition   := condition[1] !=  1 and entryLong  ?  1 :
               condition[1] != -1 and entryShort ? -1 :
               condition[1] !=  0 and slExit     ?  0 :
               condition[1] !=  0 and exitLong   ?  0 :
               condition[1] !=  0 and exitShort  ?  0 : nz(condition[1])
long         = condition[1] !=  1 and condition ==  1
short        = condition[1] != -1 and condition == -1
xl           = condition[1] ==  1 and exitLong and not slExit
xs           = condition[1] == -1 and exitShort and not slExit
sl           = condition[1] !=  0 and slExit

// ---------   Colors
c_green      = #006400  //Green
c_greenLight = #388e3c  //Green Light
c_red        = #8B0000  //Red
c_redLight   = #b71c1c  //Red Light
c_emas       = xl                             ? color.new(color.orange, 99) :
               xs                             ? color.new(color.orange, 99) :
               trendDir ==  1 and maDir ==  1 ? color.new(c_green,      99) :
               trendDir == -1 and maDir == -1 ? color.new(c_red,        99) :
               color.new(color.orange, 99)
c_maFill     = xl                             ? color.new(color.orange, 70) :
               xs                             ? color.new(color.orange, 70) :
               trendDir ==  1 and maDir ==  1 ? color.new(c_green,      70) :
               trendDir == -1 and maDir == -1 ? color.new(c_red,        70) :
               color.new(color.orange, 70)
c_maTrend    = trendDir ==  0                           ? color.new(color.orange,  0) :
               trendDir ==  1 and maTrend[1]  < maTrend ? color.new(c_green,       0) :
               trendDir ==  1 and maTrend[1] >= maTrend ? color.new(c_greenLight,  0) :
               trendDir == -1 and maTrend[1]  < maTrend ? color.new(c_redLight,    0) :
               trendDir == -1 and maTrend[1] >= maTrend ? color.new(c_red,         0) : na
c_ch         = trendDir ==  0                           ? color.new(color.orange, 50) :
               trendDir ==  1                           ? color.new(c_green,      50) :
               trendDir == -1                           ? color.new(c_red,        50) : na
c_slLineUp   = ta.rising (slLine, 1)
c_slLineDn   = ta.falling(slLine, 1)
c_slLine     = c_slLineUp ? na :
               c_slLineDn ? na : color.red
c_barCol     = trendDir ==  0                   ? color.new(color.orange,  0) :
               trendDir ==  1 and open <= close ? color.new(c_green,       0) :
               trendDir ==  1 and open  > close ? color.new(c_greenLight,  0) :
               trendDir == -1 and open >= close ? color.new(c_red,         0) :
               trendDir == -1 and open  < close ? color.new(c_redLight,    0) :
               color.new(color.orange, 0)

// ---------   Plots
p_maFast1    = plot(
  maFast1,
  title      = 'EMA Fast 1',
  color      = c_emas,
  linewidth  = 1)
p_maFast2    = plot(
  maFast2,
  title      = 'EMA Fast 2',
  color      = c_emas,
  linewidth  = 2)
fill(
  p_maFast1, p_maFast2,
  title      = 'EMAs Fill',
  color      = c_maFill)
plot(
  maTrend,
  title      = 'SMA Trend',
  color      = c_maTrend,
  linewidth  = 3)
p_chTop      = plot(
  i_channelOn   ? rangeTop : na,
  title      = 'Top Channel',
  color      = c_maTrend,
  linewidth  = 1)
p_chBot      = plot(
  i_channelOn   ? rangeBot : na,
  title      = 'Bottom Channel',
  color      = c_maTrend,
  linewidth  = 1)
fill(
  p_chTop, p_chBot,
  title      = 'Channel',
  color      = c_ch)
plot(
  i_slOn and condition != 0 ? slLine : na,
  title      = 'Stop Loss Line',
  color      = c_slLine,
  linewidth  = 1,
  style      = plot.style_linebr)

// ---------   Alerts
barcolor(i_barColOn ? c_barCol : na)

plotshape(
  i_alertOn and long ? high : na,
  title      = 'Long Label',
  text       = 'Long',
  textcolor  = color.white,
  color      = color.new(c_green, 0),
  style      = shape.labelup,
  size       = size.normal,
  location   = location.belowbar)
plotshape(
  i_alertOn and short ? low : na,
  title      = 'Short Label',
  text       = 'Short',
  textcolor  = color.white,
  color      = color.new(c_red, 0),
  style      = shape.labeldown,
  size       = size.normal,
  location   = location.abovebar)
plotshape(
  i_alertOn and (xl or xs) ? close : na,
  title      = 'Close Label',
  text       = 'Close',
  textcolor  = color.orange,
  color      = color.new(color.orange, 0),
  style      = shape.xcross,
  size       = size.small,
  location   = location.absolute)
plotshape(
  i_alertOn and sl ? slLine : na,
  title      = 'Stop Loss',
  text       = 'Stop\nLoss',
  textcolor  = color.orange,
  color      = color.new(color.orange, 0),
  style      = shape.xcross,
  size       = size.small,
  location   = location.absolute)
plotshape(
  i_alertOn and i_goldenOn and GCross ? maTrend : na,
  title      = 'Golden Cross Label',
  text       = 'Golden\nCross',
  textcolor  = color.white,
  color      = color.new(color.orange, 0),
  style      = shape.labelup,
  size       = size.normal,
  location   = location.absolute)
plotshape(
  i_alertOn and i_goldenOn and DCross ? maTrend : na,
  title      = 'Death Cross Label',
  text       = 'Death\nCross',
  textcolor  = color.white,
  color      = color.new(color.orange, 0),
  style      = shape.labeldown,
  size       = size.normal,
  location   = location.absolute)

bgcolor(
  i_periodSw and not period ? color.new(color.gray, 90) : na,
  title      = 'Session')

// ---------   Backtest
if long  and strategy.position_size == 0 and barstate.isconfirmed
    strategy.entry('Long',  strategy.long,  comment = 'long')
if short and strategy.position_size == 0 and barstate.isconfirmed
    strategy.entry('Short', strategy.short, comment = 'short')
strategy.exit(
  id         = 'XL',
  from_entry = 'Long',
  stop       = i_slOn ? slLine : na)
strategy.exit(
  id         = 'XS',
  from_entry = 'Short',
  stop       = i_slOn ? slLine : na)
strategy.close(
  'Long',
  comment    = 'Close',
  when       = xl)
strategy.close(
  'Short',
  comment    = 'Close',
  when = xs)

Mais.