Estratégia de negociação bidirecional baseada em sinais de alta e baixa dos indicadores quantitativos

Autora:ChaoZhang, Data: 2023-12-13 17:30:13
Tags:

img

Resumo

Esta estratégia baseia-se nos sinais de alta e baixa gerados pelo indicador do canal de preços Donchain e pelo indicador quantitativo do oscilador OBV para negociação bidirecional.

Princípios de estratégia

  1. Utilize o indicador do canal de preços Donchain para determinar os canais de preços superior e inferior. O canal superior é calculado a partir do preço mais alto e o canal inferior a partir do preço mais baixo.

  2. Construir um oscilador OBV usando o indicador quantitativo OBV e o indicador EMA para determinar a força de alta e baixa. Um valor do oscilador maior que 0 indica que a força de alta excede a força de baixa e vice-versa se for menor que 0.

  3. Um sinal longo é gerado quando o preço atravessa o canal superior e o oscilador é maior que 0; Um sinal curto é gerado quando o preço atravessa o canal inferior e o oscilador é menor que 0.

  4. Fechar posições longas quando os preços recuam para o canal inferior; Fechar posições curtas quando os preços recuam para o canal superior.

Vantagens da estratégia

  1. Usar canais de preços para determinar tendências evita ser enganado por mercados flutuantes.

  2. A incorporação de indicadores quantitativos para julgar a força de alta e baixa garante que a direcção do comércio seja coerente com a força do mercado.

  3. Adotar a negociação bidirecional permite lucros, quer o mercado suba ou caia.

  4. A definição de estratégias de stop loss gerencia os riscos de forma eficaz.

Riscos da Estratégia

  1. A configuração inadequada dos parâmetros dos canais de preços pode conduzir a canais demasiado largos ou estreitos, a perder oportunidades de negociação ou a gerar sinais errados.

  2. A configuração inadequada dos parâmetros do indicador pode também conduzir a uma geração de sinal atrasada ou prematura.

  3. Os movimentos voláteis anormais súbitos resultantes de eventos podem desencadear stop losses que levam a perdas.

  4. A negociação bidireccional requer a gestão simultânea de posições longas e curtas, tornando mais difícil operar.

Orientações para a otimização da estratégia

  1. Otimizar os parâmetros do canal de preços para encontrar combinações ideais.

  2. Testar e otimizar os parâmetros do oscilador OBV para garantir julgamentos oportunos e precisos da força de alta/baixa.

  3. Considere a incorporação de outros indicadores como MACD, KD etc. para melhorar a precisão do sinal.

  4. Teste diferentes métodos de stop loss, por exemplo, tracking stops, percentage stops, etc.

  5. Teste diferentes produtos para descobrir qual é o mais adequado à estratégia.

Resumo

No geral, trata-se de uma estratégia de negociação bidirecional clara e de fácil compreensão, que incorpora a ação dos preços e indicadores quantitativos para determinar as tendências e a força do mercado.


/*backtest
start: 2022-12-06 00:00:00
end: 2023-12-12 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/
// © ahancock

//@version=4
strategy(
     title = "Hancock - Filtered Volume OBV OSC [Strategy]",
     initial_capital = 1000,
     overlay = false,
     commission_type = strategy.commission.percent,
     commission_value= 0.075)

// Inputs
source = input(close, title = "Source", type = input.source)

use_volume_filter     = input(true, title = "Use Volume Filter", type = input.bool)
vol_filter_length     = input(20, title = "Volume Filter - Length", type = input.integer, minval = 1)
vol_filter_multiplier = input(1.2, title = "Volume Filter - Multiplier", type = input.float, minval = 0.1, step = 0.1)

use_osc    = input(true, title = "Use Oscillator", type = input.bool)
osc_length = input(40, title = "Oscillator - Signal Length", type = input.integer, minval = 1)

channel_length = input(65, title = "Channel - Slow Length", minval = 5, maxval = 200, step = 5)
channel_percent = input(70, title = "Channel - Fast Length Percent", minval = 5, maxval = 100, step = 5)

trade_both = "Both", trade_long = "Long", trade_short = "Short"
trade_direction       = input("Both", title = "Trade - Direction", options = [trade_both, trade_long, trade_short])
trade_leverage        = input(2, title = "Trade - Leverage", type = input.integer, minval = 1, maxval = 100)
trade_stop            = input(7.5, title = "Trade - Stop Loss %", type = input.float, minval = 0.5, step = 0.5, maxval = 100)
trade_trail_threshold = input(5, title = "Trade - Trail Stop Threshold %", type = input.float, minval = 0.5, step = 0.5, maxval = 100)
trade_trail           = input(5, title = "Trade - Trail Stop Minimum %", type = input.float, minval = 0.5, step = 0.5, maxval = 100)
trade_risk            = input(100, title = "Trade - Risk %", type = input.integer, step = 1, minval = 1, maxval = 100)

test_year   = input(2019, "Test - Year", type = input.integer, minval = 1970, maxval = 2222) 
test_month  = input(01, "Test - Month", type = input.integer, minval = 1, maxval = 12)
test_day    = input(01, "Test - Day", type = input.integer,  minval = 1, maxval = 31)

// Functions
get_round(value, precision) => round(value * (pow(10, precision))) / pow(10, precision)

get_obv(values, filter_length, filter_multiplier, use_filter, osc_length, use_osc) => 
    threshold = abs(avg(volume, filter_length) - (stdev(volume, filter_length) * filter_multiplier))

    obv = 0.0
    if (use_filter and volume < threshold)
        obv := nz(obv[1])
    else
        obv :=  nz(obv[1]) + sign(change(values)) * volume
        
    use_osc ? (obv - ema(obv, osc_length)) : obv

get_dc(high_values, low_values, length) =>

    top = highest(high_values, length)
    bot = lowest(low_values, length)
    mid = bot + ((top - bot) / 2)
    
    [top, mid, bot]

get_dcs(high_values, low_values, length, length_percent) => 
    
    slow_length = length
    fast_length = slow_length * length_percent / 100

    [slow_top, slow_mid, slow_bot] = 
         get_dc(high_values, low_values, slow_length)
         
    [fast_top, fast_mid, fast_bot] = 
         get_dc(high_values, low_values, fast_length)
    
    [slow_top, slow_mid, slow_bot, fast_top, fast_mid, fast_bot]

// Strategy
obv = get_obv(
         source, 
         vol_filter_length, 
         vol_filter_multiplier, 
         use_volume_filter,
         osc_length,
         use_osc)

[slow_top_price, _, slow_bot_price, fast_top_price, _, fast_bot_price] = 
     get_dcs(high, low, channel_length, channel_percent)

[slow_top_obv, _, slow_bot_obv, fast_top_obv, _, fast_bot_obv] = 
     get_dcs(obv, obv, channel_length, channel_percent)

enter_long_price  = high > slow_top_price[1]
exit_long_price   = low  < fast_bot_price[1]
enter_short_price = low  < slow_bot_price[1]
exit_short_price  = high > fast_top_price[1]

enter_long_obv  = obv > slow_top_obv[1] and (use_osc ? obv > 0 : true)
enter_short_obv = obv < fast_bot_obv[1] and (use_osc ? obv < 0 : true)
exit_long_obv   = obv < slow_bot_obv[1]
exit_short_obv  = obv > fast_top_obv[1]

// Trade Conditions
can_trade = true

enter_long_condition = enter_long_obv and enter_long_price
exit_long_condition  = exit_long_obv  and exit_long_price

enter_short_condition = enter_short_obv and enter_short_price 
exit_short_condition  = exit_short_obv  and exit_short_price

position_signal = 0
position_signal := 
     enter_long_condition ? 1 :
     enter_short_condition ? -1 :
     exit_long_condition or exit_short_condition ? 0 :
     position_signal[1]

// Positions
test_time   = timestamp(test_year, test_month, test_day, 0, 0)

if (time >= test_time and strategy.opentrades == 0)
    contracts = get_round((strategy.equity * trade_leverage / close) * (trade_risk / 100), 4)
    
    if (trade_direction == trade_both or trade_direction == trade_long)
        strategy.entry(
             "LONG", 
             strategy.long, 
             qty = contracts,
             when = enter_long_condition)
             
    if (trade_direction == trade_both or trade_direction == trade_short)
        strategy.entry(
             "SHORT", 
             strategy.short, 
             qty = contracts,
             when = enter_short_condition)

in_long  = strategy.position_size > 0
in_short  = strategy.position_size < 0

float long_high = na 
float short_low = na

long_high := in_long ? high >= nz(long_high[1], low) ? high : long_high[1] : na
short_low := in_short ? low <= nz(short_low[1], high) ? low : short_low[1] : na

long_change  = abs(((long_high - strategy.position_avg_price) / strategy.position_avg_price) * 100)
short_change = abs(((short_low - strategy.position_avg_price) / strategy.position_avg_price) * 100)

threshold_difference = (strategy.position_avg_price / trade_leverage) * (trade_trail_threshold / 100)

long_trail_threshold  = in_long ? strategy.position_avg_price + threshold_difference : na
short_trail_threshold = in_short ? strategy.position_avg_price - threshold_difference : na

long_trail = in_long and long_high > long_trail_threshold ? 
     long_high - (long_high / trade_leverage) * (trade_trail / 100) : na
short_trail = in_short and short_low < short_trail_threshold ? 
     short_low + (short_low / trade_leverage) * (trade_trail / 100) : na

stop_difference = (strategy.position_avg_price / trade_leverage) * (trade_stop / 100)

long_stop  = in_long ? long_high > long_trail_threshold ? long_trail : strategy.position_avg_price - stop_difference : na
short_stop = in_short ? short_low < short_trail_threshold ? short_trail : strategy.position_avg_price + stop_difference : na

strategy.exit("S/L", "LONG",
     stop = long_stop,
     qty = abs(get_round(strategy.position_size, 4)))
         
strategy.exit("S/L", "SHORT", 
     stop = short_stop, 
     qty = abs(get_round(strategy.position_size, 4)))

strategy.close_all(when = abs(change(position_signal)) > 0)

// Plots
plotshape(enter_long_condition, "Enter Long", shape.diamond, location.top, color.green)
plotshape(exit_long_condition, "Exit Long", shape.diamond, location.top, color.red)

plotshape(enter_short_condition, "Enter Short", shape.diamond, location.bottom, color.green)
plotshape(exit_short_condition, "Exit Short", shape.diamond, location.bottom, color.red)

color_green = #63b987
color_red   = #eb3d5c

hline(use_osc ? 0 : na)
plot(use_osc ? obv : na, color = color.silver, style = plot.style_area, transp = 90)
plot(obv, color = color.white, style = plot.style_line, linewidth = 2, transp = 0)

plot_slow_top = plot(slow_top_obv, color = color_green, linewidth = 2, transp = 60)
plot_slow_bot = plot(slow_bot_obv, color = color_green, linewidth = 2, transp = 60)
fill(plot_slow_top, plot_slow_bot, color = color_green, transp = 90)

plot_fast_top = plot(fast_top_obv, color = color_red, linewidth = 2, transp = 60)
plot_fast_bot = plot(fast_bot_obv, color = color_red, linewidth = 2, transp = 60)
fill(plot_fast_top, plot_fast_bot, color = color_red, transp = 90)





Mais.