Estratégia de perda de parada fixa de faixa de ruptura

Autora:ChaoZhang, Data: 2023-11-03 14:31:21
Tags:

img

Resumo

A principal ideia desta estratégia é usar a faixa de ruptura para identificar a direção da tendência e combinar stop loss fixo para gerenciamento de riscos. A estratégia primeiro calcula os preços mais altos e mais baixos em um determinado período para formar uma faixa de ruptura. Quando o preço atravessa a faixa de ruptura, um sinal de negociação é gerado. Além disso, a estratégia permite que os comerciantes definam um montante de stop loss fixo.

Princípio da estratégia

A estratégia consiste em quatro partes principais: gestão de posições, identificação da faixa de ruptura, definição de stop loss e dimensionamento de posições.

Em primeiro lugar, a estratégia verifica se há alguma posição aberta, caso existam, não serão gerados novos sinais.

Em segundo lugar, a estratégia calcula os preços mais altos e mais baixos em um período para formar uma faixa de ruptura. Quando o preço sai da faixa, um sinal de negociação é gerado. Especificamente, se o preço quebra acima da faixa superior, um sinal longo é gerado. Se o preço quebra abaixo da faixa inferior, um sinal curto é gerado.

Além disso, quando um sinal longo é gerado, a estratégia define o ponto médio da faixa de ruptura como o stop loss.

Por fim, a estratégia permite definir um valor fixo de stop loss. Quando um sinal é gerado, a estratégia calcula o número de pips do stop loss ao preço atual e combina fatores como o tamanho do tick e a taxa de câmbio, para determinar a mudança de preço entre o stop loss e o preço atual em termos monetários. O tamanho da posição é então calculado com base no valor fixo de stop loss.

Os principais conceitos são identificar a direcção da tendência com bandas de ruptura e controlar o risco com stop loss fixo.

Vantagens

Esta estratégia de stop loss fixa de faixa de ruptura tem as seguintes vantagens:

  1. Concepção avançada de stop loss. A estratégia usa quantidade fixa de stop loss em vez de distância fixa de stop loss. Isso evita o problema de não ser possível fixar o risco em produtos com diferentes valores de tick.

  2. Dimensão razoável da posição: a estratégia pode calcular de forma inteligente o tamanho da posição com base no montante fixo de stop loss, de modo a controlar a perda por transação, gerindo assim razoavelmente a exposição ao risco.

  3. Identificação de breakout com bandas é simples e direta, e pode identificar efetivamente a direção da tendência.

  4. A capacidade da estratégia de ajustar a perda de parada em tempo real para a perda de parada de atraso ajuda a bloquear mais lucros.

  5. Ampla aplicabilidade. A estratégia é aplicável a qualquer produto. Desde que os parâmetros sejam definidos corretamente, o controle de risco de stop loss de quantidade fixa pode ser alcançado, tornando a estratégia altamente versátil.

  6. A estrutura do código é clara e modular, tornando-a fácil de entender e otimizar.

Riscos

Apesar das vantagens, há alguns riscos a observar para a estratégia:

  1. A estratégia não julga a qualidade do padrão de ruptura e pode gerar alguns sinais de baixa qualidade. Outros indicadores são necessários para filtrar sinais.

  2. A perda fixa pode ser muito mecânica. Os preços de mercado geralmente diferem. A perda fixa pode depender demais de regras e não ter flexibilidade no ajuste.

  3. A estratégia não limita a frequência do comércio e pode negociar com demasiada frequência.

  4. A fixação do montante do stop loss é crucial para o controlo geral do risco e deve considerar o tamanho do capital, o apetite pelo risco, etc.

  5. A direção do breakout pode dar sinais errados. Sinais errados de breakout podem ocorrer durante oscilações de preços ou retrações. Mais condições são necessárias para otimizar a estratégia.

  6. A estratégia atualmente não possui capacidade de captação de lucros para bloquear ativamente os lucros. Isso pode levar a lucros insatisfatórios.

Para enfrentar estes riscos, algumas formas de otimizar a estratégia incluem:

  1. Adição de indicadores para filtrar a qualidade do sinal, por exemplo MACD, KD, etc.

  2. Incorporar indicadores de resistência de ruptura para avaliar a qualidade, por exemplo, julgar a resistência através de alterações de volume.

  3. Adicionar limites de frequência de negociação aberta, por exemplo, uma negociação por dia.

  4. Otimizar a lógica de stop loss fixa, por exemplo, stop loss baseado em percentagem acima de um limiar.

  5. Adição de outros filtros, por exemplo, volatilidade, melhoria do stop loss, etc.

  6. Incorporar estratégias de obtenção de lucro, por exemplo, obtenção de lucro perto da resistência.

Orientações de otimização

Com base na análise, a estratégia pode ser otimizada nos seguintes aspectos:

  1. Adicionar filtros para melhorar a qualidade do sinal usando múltiplos indicadores técnicos e avaliar a qualidade da tendência.

  2. Optimizar stop loss para maior flexibilidade. Pode mudar para stop de trailing baseado em porcentagem após um certo retracement. Também pode otimizar dinamicamente com base na volatilidade.

  3. Controlar a frequência de negociação para evitar a troca excessiva adicionando filtros em períodos de tempo ou frequência.

  4. Incorporar indicadores de tendência para melhorar o calendário, por exemplo, aguardar a confirmação da tendência.

  5. Otimizar as estratégias de captação de lucro para melhorar a rentabilidade através de meta de lucro, parada de lucro, parada de volatilidade, etc.

  6. Optimização dos parâmetros de risco com base em backtests, tais como quantidade fixa de stop, período de ruptura, etc.

  7. Refatoração do código para uma melhor extensibilidade através da desconexão adicional dos módulos de sinal, filtro, risco e lucro.

  8. Testar mais produtos para oportunidades de arbitragem.

Através dessas dimensões de otimização, a estratégia de stop loss pode se tornar mais robusta e lucrativa.

Conclusão

Em geral, a estratégia é razoável em usar bandas de ruptura para identificar tendências e paradas de quantidade fixa para controle de risco. Os conceitos são progressivos para gerenciamento de risco. A lógica de dimensionamento de posição também é boa para controlar a perda por comércio. Mas a estratégia pode ser aprimorada por meio de várias otimizações para melhorar a qualidade do sinal, flexibilidade no stop loss, lucratividade, etc. Ao incorporar filtros de tendência, melhorar a tomada de lucro e controlar estritamente a frequência do comércio, uma melhoria significativa pode ser alcançada. Em conclusão, a estratégia fornece uma estrutura para aprender técnicas de gerenciamento de risco e dimensionamento de posição, estabelecendo as bases para mais pesquisas em sistemas de arbitragem e multi-estratégia mais complexos.


/*backtest
start: 2023-10-26 00:00:00
end: 2023-10-28 03:00:00
period: 10m
basePeriod: 1m
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/
//@version=4
//@author=Takazudo

strategy("Fixed price SL",
  overlay=true,
  default_qty_type=strategy.fixed,
  initial_capital=0,
  currency=currency.USD)

var COLOR_TRANSPARENT = color.new(#000000, 100)
var COLOR_ENTRY_BAND = color.new(#43A6F5, 30)

//============================================================================
// config
//============================================================================

// Money management
_g1 = 'Money management'
var config_riskPrice = input(100, minval=1, title="Risk price for each entry", group=_g1)
var config_depositCurrency = input(title="Deposit currency", type=input.string, defval="USD", options=["USD"], group=_g1)

// Entry strategy
_g2 = 'Entry strategy'
var config_entryBandBars = input(defval = 100, title = "Entry band bar count",  minval=1, group=_g2)

// Backtesting range
_g3 = 'Backtesting range'
fromYear  = input(defval = 2018, title = "From Year",  minval = 1970, group=_g3)
fromMonth = input(defval = 1,    title = "From Month", minval = 1, maxval = 12, group=_g3)
fromDay   = input(defval = 1,    title = "From Day",   minval = 1, maxval = 31, group=_g3)
toYear  = input(defval = 2020, title = "To Year",  minval = 1970, group=_g3)
toMonth = input(defval = 12,    title = "To Month", minval = 1, maxval = 12, group=_g3)
toDay   = input(defval = 31,    title = "To Day",   minval = 1, maxval = 31, group=_g3)

//============================================================================
// exchange caliculations
//============================================================================

// mico pip size caliculation
// ex1: AUDCAD -> 0.0001
// ex2: USDJPY -> 0.01
f_calcMicroPipSize() =>
    _base = syminfo.basecurrency
    _quote = syminfo.currency
    _result = 0.0001
    if _quote == 'JPY'
        _result := _result * 100
    if _base == 'BTC'
        _result := _result * 100
    _result

// convert price to pips
f_convertPriceToPips(_price) =>
    _microPipSize = f_calcMicroPipSize()
    _price / _microPipSize

// caliculate exchange rate between deposit and quote currency
f_calcDepositExchangeSymbolId() =>
    _result = ''
    _deposit = config_depositCurrency
    _quote = syminfo.currency
    if (_deposit == 'USD') and (_quote == 'USD')
        _result := na
    if (_deposit == 'USD') and (_quote == 'AUD')
        _result := 'OANDA:AUDUSD'
    if (_deposit == 'EUR') and (_quote == 'USD')
        _result := 'OANDA:EURUSD'
    if (_deposit == 'USD') and (_quote == 'GBP')
        _result := 'OANDA:GBPUSD'
    if (_deposit == 'USD') and (_quote == 'NZD')
        _result := 'OANDA:NZDUSD'
    if (_deposit == 'USD') and (_quote == 'CAD')
        _result := 'OANDA:USDCAD'
    if (_deposit == 'USD') and (_quote == 'CHF')
        _result := 'OANDA:USDCHF'
    if (_deposit == 'USD') and (_quote == 'JPY')
        _result := 'OANDA:USDJPY'
    _result

// Let's say we need CAD to USD exchange
// However there's only "OANDA:USDCAD" symbol.
// Then we need to invert the exhchange rate.
// this function tells us whether we should invert the rate or not
f_calcShouldInvert() =>
    _result = false
    _deposit = config_depositCurrency
    _quote = syminfo.currency
    if (_deposit == 'USD') and (_quote == 'CAD')
        _result := true
    if (_deposit == 'USD') and (_quote == 'CHF')
        _result := true
    if (_deposit == 'USD') and (_quote == 'JPY')
        _result := true
    _result

// caliculate how much quantity should I buy or sell
f_calcQuantitiesForEntry(_depositExchangeRate, _slPips) =>
    _microPipSize = f_calcMicroPipSize()
    _priceForEachPipAsDeposit = _microPipSize * _depositExchangeRate
    _losePriceOnSl = _priceForEachPipAsDeposit * _slPips
    floor(config_riskPrice / _losePriceOnSl)

//============================================================================
// Quantity caliculation
//============================================================================

depositExchangeSymbolId = f_calcDepositExchangeSymbolId()

// caliculate deposit exchange rate
rate = security(depositExchangeSymbolId, timeframe.period, hl2)
shouldInvert = f_calcShouldInvert()
depositExchangeRate = if config_depositCurrency == syminfo.currency
    // if USDUSD, no exchange of course
    1
else
    // else, USDCAD to CADUSD invert if we need
    shouldInvert ? (1 / rate) : rate

//============================================================================
// Range Edge caliculation
//============================================================================

f_calcEntryBand_high() =>
    _highest = max(open[3], close[3])
    for i = 4 to (config_entryBandBars - 1)
        _highest := max(_highest, open[i], close[i])
    _highest

f_calcEntryBand_low() =>
    _lowest = min(open[3], close[3])
    for i = 4 to (config_entryBandBars - 1)
        _lowest := min(_lowest, open[i], close[i])
    _lowest

entryBand_high = f_calcEntryBand_high()
entryBand_low = f_calcEntryBand_low()
entryBand_height = entryBand_high - entryBand_low

plot(entryBand_high, color=COLOR_ENTRY_BAND, linewidth=1)
plot(entryBand_low, color=COLOR_ENTRY_BAND, linewidth=1)

rangeBreakDetected_long = entryBand_high < close
rangeBreakDetected_short = entryBand_low > close

shouldMakeEntryLong = (strategy.position_size == 0) and rangeBreakDetected_long
shouldMakeEntryShort = (strategy.position_size == 0) and rangeBreakDetected_short

//============================================================================
// SL & Quantity
//============================================================================

var sl_long = hl2
var sl_short = hl2

entryQty = 0
slPips = 0.0

// just show info bubble
f_showEntryInfo(_isLong) =>
    _str =
      'SL pips: ' + tostring(slPips) + '\n' +
      'Qty: ' + tostring(entryQty)
    _bandHeight = entryBand_high - entryBand_low
    _y = _isLong ? (entryBand_low + _bandHeight * 1/4) : (entryBand_high - _bandHeight * 1/4)
    _style = _isLong ? label.style_label_up : label.style_label_down
    label.new(bar_index, _y, _str, size=size.large, style=_style)

if shouldMakeEntryLong
    sl_long := (entryBand_high + entryBand_low) / 2
    slPips := f_convertPriceToPips(close - sl_long)
    entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips)
if shouldMakeEntryShort
    sl_short := (entryBand_high + entryBand_low) / 2
    slPips := f_convertPriceToPips(sl_short - close)
    entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips)

// trailing SL
if strategy.position_size > 0
    sl_long := max(sl_long, entryBand_low)
if strategy.position_size < 0
    sl_short := min(sl_short, entryBand_high)

//============================================================================
// backtest duration
//============================================================================

// Calculate start/end date and time condition
startDate  = timestamp(fromYear, fromMonth, fromDay, 00, 00)
finishDate = timestamp(toYear,   toMonth,   toDay,   00, 00)

//============================================================================
// make entries
//============================================================================

if (true)
    if shouldMakeEntryLong
        strategy.entry(id="Long", long=true, stop=close, qty=entryQty)
        f_showEntryInfo(true)
    if shouldMakeEntryShort
        strategy.entry(id="Short", long=false, stop=close, qty=entryQty)
        f_showEntryInfo(false)

strategy.exit('Long-SL/TP', 'Long', stop=sl_long)
strategy.exit('Short-SL/TP', 'Short', stop=sl_short)

//============================================================================
// plot misc
//============================================================================

sl = strategy.position_size > 0 ? sl_long :
  strategy.position_size < 0 ? sl_short : na

plot(sl, color=color.red, style=plot.style_cross, linewidth=2, title="SL")

value_bgcolor = rangeBreakDetected_long ? color.green :
  rangeBreakDetected_short ? color.red : COLOR_TRANSPARENT

bgcolor(value_bgcolor, transp=95)


Mais.