QuantBrasil

Backtest da Estratégia Saudade de Casa em Python

Helio Quintanilha Jr.
Por Helio Quintanilha Jr.
10 agosto, 2021
Compartilhar:

Como mencionado em Como Calcular as Bandas de Bollinger em Python, existem diferentes tipos de estratégias baseadas nesse indicador. No artigo de hoje, vamos realizar o backtest da estratégia conhecida como Saudade de Casa popularizada pelo Stormer.

Como funciona o setup Saudade de Casa?

A ideia por trás da estratégia é bastante simples: buscar por possíveis discrepâncias na abertura do mercado, quando o ativo se encontra fora das bandas de Bollinger (nesse caso, fora de "casa") e esperar que ele retorne para dentro da banda.

Para isso, primeiramente devemos calcular as bandas de Bollinger de 20 períodos com desvio padrão igual a 2. Para essa estratégia, que é mais utilizada no day trade, recomenda-se o timeframe de 30 minutos.

O sinal de entrada é configurado se o primeiro candle do dia abrir acima da banda superior (sinal de venda) ou abaixo da banda inferior (sinal de compra). Dado o sinal de venda, se o próximo candle do dia perder a mínima do candle sinal, a venda deverá ser efetuada. No caso da compra, se o segundo candle do dia romper a máxima do candle sinal, deveremos efetuar a compra. Caso a superação ou perda não aconteça no segundo candle do dia, o sinal está cancelado e a estratégia não é executada. Simples, certo?

Para essa estratégia, usualmente o stop é acionado na máxima (no caso da ponta da venda) ou na mínima (na ponta da compra) do candle sinal.

Para o alvo da operação, geralmente existem duas possibilidades: a banda do meio ou a banda oposta.

A figura abaixo mostra dois exemplos da estratégia para PETR4, na ponta da compra (stopada) e na ponta da venda (bem-sucedida).

Formalmente, definimos o sistema operacional com o seguinte conjunto de regras:

  • Timeframe: 30 minutos
  • Tipo de operação: compra e venda.
  • Ponto de entrada: rompimento da máxima ou mínima do candle sinal.
  • Alvo: banda central ou banda oposta.
  • Stop: máxima ou mínima do candle sinal.

Importando as bibliotecas e os dados necessários

Como já aprendemos a criar nosso próprio banco de dados e importar os dados do MetaTrader ou do ProfitChart, para esse artigo vamos usar nossos próprios dados. O arquivo que usaremos aqui estará disponível para download no nosso grupo do Telegram.

Vamos importar também as bibliotecas que usaremos para efetuar nosso backtest.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math

O ativo escolhido foi PETR4 no timeframe de 30 minutos para um intervalo de 3 anos.

df = pd.read_csv('../data/M30/PETR4.csv', index_col='datetime')[["open", "high", "low", "close"]]
df
openhighlowclose
datetime
2018-07-16 10:00:0017.9517.9517.7617.85
2018-07-16 10:30:0017.8517.9417.8117.91
2018-07-16 11:00:0017.9217.9817.7717.83
2018-07-16 11:30:0017.8417.8817.7417.77
2018-07-16 12:00:0017.7917.8317.7517.78
...............
2021-07-15 12:30:0027.4427.4927.3827.41
2021-07-15 13:00:0027.4027.4327.3127.39
2021-07-15 13:30:0027.3827.3927.3127.32
2021-07-15 14:00:0027.3227.4027.2827.29
2021-07-15 14:30:0027.3027.3027.1627.17

12087 rows × 4 columns

Calculando as Bandas de Bollinger

Podemos reutilizar a função para calcularmos as Bandas de Bollinger que já aprendemos anteriormente.

def bb(df, k=2, n=20):
  df['standard deviation'] = df['close'].rolling(n).std()
  df['middle band'] = df['close'].rolling(n).mean()
  df['upper band'] = df['middle band'] + df['standard deviation'] * k
  df['lower band'] = df['middle band'] - df['standard deviation'] * k
  
  return df

Como para essa estratégia não estamos interessados no desvio padrão, podemos eliminá-lo do nosso dataframe junto com todos os valores NaN.

df = bb(df)
df.drop(columns=["standard deviation"], inplace=True)
df.dropna(inplace=True)

df.head(5)
openhighlowclosemiddle bandupper bandlower band
datetime
2018-07-17 11:30:0017.8918.0717.8918.0517.817518.02714917.607851
2018-07-17 12:00:0018.0518.1218.0118.0717.828518.06649817.590502
2018-07-17 12:30:0018.0718.2518.0618.2317.844518.14132417.547676
2018-07-17 13:00:0018.2318.2918.1818.2717.866518.21883217.514168
2018-07-17 13:30:0018.2518.3618.2218.2917.892518.28884517.496155

Determinando os sinais de entrada

Como na estratégia Saudade de Casa estamos interessado no primeiro candle do dia, podemos usar a mesma abordagem que aprendemos no artigo sobre Gap Trap para identificá-los. Para isso, vamos analisar para cada candle, se o anterior é de um dia diferente.

df["day"] = pd.to_datetime(df.index).strftime('%Y-%m-%d')
df["first of day"] = df["day"] != df["day"].shift(1)
df.head(5)
openhighlowclosemiddle bandupper bandlower banddayfirst of day
datetime
2018-07-17 11:30:0017.8918.0717.8918.0517.817518.02714917.6078512018-07-17True
2018-07-17 12:00:0018.0518.1218.0118.0717.828518.06649817.5905022018-07-17False
2018-07-17 12:30:0018.0718.2518.0618.2317.844518.14132417.5476762018-07-17False
2018-07-17 13:00:0018.2318.2918.1818.2717.866518.21883217.5141682018-07-17False
2018-07-17 13:30:0018.2518.3618.2218.2917.892518.28884517.4961552018-07-17False

Com o primeiro candle do dia identificado e as bandas de Bollinger calculadas, podemos criar um simples código para identificarmos a quantidade de vezes que o sinal de entrada foi acionado.

Primeiramente vamos identificar se o candle é o primeiro do dia e abriu acima ou abaixo das bandas de Bollinger. Em seguida, criaremos um coluna sinal que retornará:

  • 1 se o segundo candle do dia rompeu a máxima do candle sinal;
  • -1 se o segundo candle do dia perdeu a mínima do candle sinal;
  • 0 se não houve trade no dia.
# A bullish "missing home" opens below the lower BB 
bullish_candle = (df["first of day"] == True) & \
    (df["open"] < df['lower band']) 

# A bearish "missing home" opens above the upper BB
bearish_candle = (df["first of day"] == True) & \
    (df["open"] > df['upper band'])
    

# Signal is  1 when the next candle exceeds the high of the bullish candle
# Signal is -1 when the next candle has its low below the low of the
# bearish candle. 
# If none occurs, then the signal is 0 and no trade is placed.
df["signal"] = np.where(
    (bullish_candle == True) & (df["high"].shift(-1) > df["high"]), 
    1, 
    np.where(
        (bearish_candle == True) & (df["low"].shift(-1) < df["low"]), 
        -1, 
        0
    )
)

long_trades = df[df["signal"] == 1]
short_trades = df[df["signal"] == -1]

print(f"Total Compras: {len(long_trades)}")
print(f"Total Vendas: {len(short_trades)}")
print(f"Total Trades: {len(long_trades+short_trades)}")

Total Compras: 37
Total Vendas: 43
Total Trades: 80

No período de julho de 2018 até julho de 2021, 80 trades foram realizados pelo setup Saudade de Casa (contudo, vamos ver mais pra frente que nem todas as operações serão válidas para o nosso propósito aqui). Embora um bom balanço exista entre a ponta da compra e a ponta da venda, o número total de vendas foi um pouco superior ao da compra.

Criando o algoritmo para simular a operação

O código que vamos programar agora é baseado no backtest do estocástico lento e na estratégia 123. Contudo algumas mudanças foram feitas e por isso vamos analisá-las passo-a-passo a seguir.

Primeiramente, após inicializarmos a nossa função com o capital total, vamos criar uma lista para salvarmos os nossos lucros/prejuízos. Vamos também definir variáveis que nos auxiliarão a contar o número de ganhos e perdas das operações de compra e de venda.

# initial capital is $100,000 
total_capital = [100000]
all_profits = []
number_bullish_gain = 0
number_bearish_gain = 0
number_bullish_loss = 0
number_bearish_loss = 0

Antes de começarmos o nosso loop, como feito nos outros backtests, vamos definir uma variável (ongoing) que nos diz se estamos em um trade ou não. Em outras palavras, só poderemos começar um novo trade quando terminarmos o trade anterior. Dessa forma, só entraremos em um trade por vez.

Vamos também definir a mesma variável signal, citada anteriormente, que nos dirá qual é o sinal da operação (compra ou venda).

Por último, vamos definir a variação mínima de uma ação, min_tick.

ongoing = False
signal = 0
min_tick = 0.01

Agora já estamos prontos para iniciarmos o loop. Nele, vamos percorrer todo o DataFrame.

Dentro do loop, vamos dividir nossa operação em duas partes. Se ongoing == False, ou seja, se ainda não estamos em nenhuma operação, vamos buscar pelo sinal de entrada para um trade de compra ou venda:

for i in range(0,len(df)):

# bullish:
    if (df["signal"][i] == 1):
        signal = 1
        entry = df["high"][i] + min_tick
        stop = df["low"][i] - min_tick
        risk = entry - stop
        ongoing = True 

# bearish:
    elif (df["signal"][i] == -1):
        signal = -1
        entry = df["low"][i] - min_tick
        stop = df["high"][i] + min_tick
        risk = entry - stop 
        ongoing = True

Lembrando que no final de cada condição, devemos setar ongoing = True sinalizando que iniciamos um trade.

Agora o algoritmo fica mais interessante e vamos definir as operações que faremos quando o sinal for dado e estivermos em um trade.

Primeiramente devemos definir o nosso alvo. Como as Bandas de Bollinger variam à medida que novos dados são inseridos, o nosso alvo é variável com o tempo. Por isso, temos que defini-lo dentro do loop. Como estamos interessados em dois alvos diferentes, a banda do meio e a banda oposta, vamos criar a variável target_band e defini-la como um dado de entrada da função. Repare que precisamos saber o sinal da operação para identificar a banda oposta, mas não precisamos para a banda do meio, que é igual em ambos os casos.

target_band = 'middle'

for i in range(0,len(df)):

    if (signal == 1 and target_band == 'opposite'):
        target = df["upper band"][i]

    elif (signal == -1 and target_band == 'opposite'):
        target = df["lower band"][i]

    elif (target_band == 'middle'):
        target = df["middle band"][i]

    else:
        print('Unknown target')

Lembra que eu comentei anteriormente que nem todas as 80 operações seriam válidas para esse trade? O que acontece é que existem operações em que não sabemos (olhando o timeframe de 30 minutos) se o stop aconteceu antes da entrada. Por simplicidade, vamos desconsiderar essas operações.

for i in range(0,len(df)):
    
    # Ignore signals where you might have been stopped in the same candle once
    # we are unable to say what happened first 
    if (signal == 1 and df["high"][i] >= df["high"][i-1] and df["low"][i] <= stop): 
        ongoing = False
    elif (signal == -1 and df["low"][i] <= df["low"][i-1] and df["high"][i] >= stop):
        ongoing = False

Pronto, agora podemos definir se a nossa entrada atingiu o nosso alvo. Novamente vamos separar as operações da ponta da compra e da ponta da venda, calcular o resultado e adicionar à lista de resultads. Vamos também atualizar o capital e usar as variáveis de contagem para sabermos quantas operações foram bem-sucedidas.

# Example with fixed shares
shares = 100

for i in range(0,len(df)):

# bullish:
    if (signal == 1 and df["high"][i] >= target):      
        profit = shares * (target - entry)
        all_profits += [profit]
        current_capital = total_capital[-1]
        total_capital += [current_capital + profit]
        number_bullish_gain += 1
        ongoing = False

# bearish:
    elif (signal == -1 and df["low"][i] <= target):
        profit = shares * (target - entry)
        all_profits += [profit]
        current_capital = total_capital[-1]
        total_capital += [current_capital + profit]
        number_bearish_gain += 1
        ongoing = False

Na última parte do loop, vamos definir o stop. Lembre-se que o stop é acionado na perda da mínima do candle sinal (ponta da compra) ou no rompimento da máxima do candle sinal (ponta da venda). Nesse caso, também calcularemos o resultado e o adicionaremos à lista.

# Example with fixed shares
shares = 100

for i in range(0,len(df)):

    # bullish:
    if (signal == 1 and df["low"][i] <= stop):
        profit = shares * (stop - entry)
        all_profits += [profit]
        current_capital = total_capital[-1]
        total_capital += [current_capital + profit]
        number_bullish_loss += 1
        ongoing = False

    # bearsih:

    elif (signal == -1 and df["high"][i] >= stop):
        profit = shares * (stop - entry)
        all_profits += [profit]
        current_capital = total_capital[-1]
        total_capital += [current_capital + profit]
        number_bearish_loss += 1
        ongoing = False

Finalmente, vamos calcular o número total de operações de compra (total_number_bullish) e venda (total_number_bearish) e calcular a porcentagem de ganhos em cada um deles (pct_bullish_gain e pct_bearish_gain). É essa a informação que estamos mais interessados para sabermos se existe maiores chances de se acertar comprado ou vendido nesse trade. Nossa função vai retornar essa porcentagem, a soma dos nossos lucros e também o nosso capital final ao fim da operação.

A versão final do código, juntando todas as partes, ficará assim:

# Create a function to round any number to the smalles multiple of 100
def round_down(x):
    return int(math.floor(x / 100.0)) * 100

def missing_home_algorithm(
    df,    
    capital_exposure,
    initial_capital,
    target_band='middle'): # we define the middle band as standard if nothing is provided

    # List with the total capital after every operation
    total_capital = [initial_capital]

    # List with all profits and a couting splitting bullish and bearish operations
    all_profits = [] 
    number_bullish_gain = 0
    number_bearish_gain = 0
    number_bullish_loss = 0
    number_bearish_loss = 0
  
    ongoing = False # at the start no trade is ongoing
    signal = 0      # initialising signal
    min_tick = 0.01 # That's the min variation for this asset

    for i in range(0,len(df)):
        
        # start of the trade
        if ongoing == False:

            # bullish signal
            if (df["signal"][i] == 1):
                signal = 1
                entry = df["high"][i] + min_tick
                stop = df["low"][i] - min_tick
                risk = entry - stop
                shares = round_down(capital_exposure / risk)

                ongoing = True

            # bearish signal
            elif (df["signal"][i] == -1):            
                signal = -1
                entry = df["low"][i] - min_tick
                stop = df["high"][i] + min_tick
                risk = entry - stop                
                shares = round_down(capital_exposure / risk)

                ongoing = True

        else:
            # if I am in a trade, my target is variable and updated every candle    
            if (signal == 1 and target_band == 'opposite'):
                target = df["upper band"][i]
            elif (signal == -1 and target_band == 'opposite'):
                target = df["lower band"][i]
            elif (target_band == 'middle'):
                target = df["middle band"][i]
            else:
                print('No target defined/recognised')
                break                

            # operation where we don't know if the stop happened first is NOT considered  
            if (signal == 1 and df["high"][i] >= df["high"][i-1] and df["low"][i] <= stop): 
            
                #buy operation cancelled
                ongoing = False

            elif (signal == -1 and df["low"][i] <= df["low"][i-1] and df["high"][i] >= stop):
          
                #sell operation cancelled
                ongoing = False

            # bullish target
            elif (signal == 1 and df["high"][i] >= target):
                # target was reached
                profit = shares * (target - entry)

                # Append profit to list and create a new entry with the capital
                # after the operation is complete
                all_profits += [profit]
                current_capital = total_capital[-1] # current capital is the last entry in the list
                total_capital += [current_capital + profit]
                number_bullish_gain += 1

                #buy operation target
                ongoing = False

            # bearish target
            elif (signal == -1 and df["low"][i] <= target):
                # target was reached
                profit = shares * (target - entry)

                # Append profit to list and create a new entry with the capital
                # after the operation is complete
                all_profits += [profit]
                current_capital = total_capital[-1] # current capital is the last entry in the list
                total_capital += [current_capital + profit]                
                number_bearish_gain += 1

                #sell operation target
                ongoing = False  

            # stop loss
            elif (signal == 1 and df["low"][i] <= stop):
                # stop was reached: end of operation
                profit = shares * (stop - entry)

                # Append profit to list and create a new entry with the capital
                # after the operation is complete
                all_profits += [profit]
                current_capital = total_capital[-1] # current capital is the last entry in the list
                total_capital += [current_capital + profit]
                number_bullish_loss += 1

                #stop in bullish
                ongoing = False

            elif (signal == -1 and df["high"][i] >= stop):
                # stop was reached: end of operation
                profit = shares * (stop - entry)

                # Append profit to list and create a new entry with the capital
                # after the operation is complete
                all_profits += [profit]
                current_capital = total_capital[-1] # current capital is the last entry in the list
                total_capital += [current_capital + profit]
                number_bearish_loss += 1

                #stop in bearlish
                ongoing = False            

    total_number_bullish = number_bullish_gain + number_bullish_loss
    total_number_bearish = number_bearish_gain + number_bearish_loss
       
    pct_bullish_gain = (number_bullish_gain / total_number_bullish) * 100
    pct_bearish_gain = (number_bearish_gain / total_number_bearish) * 100
    
    return all_profits, pct_bullish_gain, pct_bearish_gain, total_capital

Calculando a curva de capital e as estatísticas

Para plotarmos a curva de capital e calcularmos as estatísticas da estratégia, vamos nos basear nas funções get_drawdownstrategy_test e capital_plot ja desenvolvidas em artigos anteriores. Apenas algumas poucas mudanças foram feitas, para incluirmos a média de ganhos e perdas e também o cálculo do valor esperado (EV).

def get_drawdown(data, column = "close"):
    data["Max"] = data[column].cummax()
    data["Delta"] = data['Max'] - data[column]
    data["Drawdown"] = 100 * (data["Delta"] / data["Max"])
    max_drawdown = data["Drawdown"].max()
    return max_drawdown

def strategy_test(all_profits, pct_bullish_gain, pct_bearish_gain, total_capital):
    number_gains = [x for x in all_profits if x >= 0] 
    number_losses = [x for x in all_profits if x < 0] 
    gains = len(number_gains)
    losses = len(number_losses)
    sum_gains = sum(number_gains)
    sum_losses = sum(number_losses)
    avg_gains = sum_gains / gains
    avg_losses = sum_losses / losses
    num_operations = gains + losses
    pct_gains = 100 * (gains / num_operations)
    pct_losses = 100 - pct_gains
    total_profit = sum(all_profits)
    pct_profit = (total_profit / total_capital[0]) * 100
    EV = (pct_gains * avg_gains + pct_losses * avg_losses) / 100
    
    # Compute drawdown
    total_capital = pd.DataFrame(data=total_capital, columns=["total_capital"])
    drawdown = get_drawdown(data=total_capital, column="total_capital")

    return {
        "num_operations": num_operations,
        "gains": gains,
        "pct_gains": pct_gains,
        "avg_gains": avg_gains.round(),
        "pct_bullish_gains": pct_bullish_gain,
        "pct_bearish_gains": pct_bearish_gain,
        "losses": losses,
        "pct_losses": pct_losses, 
        "avg_loss": avg_losses.round(),
        "total_profit": total_profit,
        "pct_profit": pct_profit,
        "drawdown": drawdown,
        'EV': EV
    }

def capital_plot(total_capital, all_profits):
  all_profits = [0] + all_profits # make sure both lists are the same size
  cap_evolution = pd.DataFrame({'Capital': total_capital, 'Profit': all_profits})
  plt.title("Curva de Capital")
  plt.xlabel("Total Operações")
  cap_evolution['Capital'].plot()

Rodando o backtest da estratégia saudade de casa

Agora que temos todas as funções necessarias programadas e entendidas, podemos finalmente rodar o nosso backtest!

Vamos seguir o critério usados em outros backtests e entrar com um capital fixo de R$100.000 e um risco controlado de R$1.000 (1% do capital).

Alvo 1: banda central

Como nosso idéia é testar o setup para dois alvos diferentes, vamos começar analisando o alvo como sendo a banda de Bollinger do meio. Vamos também transformar o dicionário statistics em um dataframe para melhor visualização.

all_profits, pct_bullish_gain, pct_bearish_gain, total_capital = missing_home_algorithm(
  df, 
  capital_exposure = 1000, 
  initial_capital = 100000, 
  target_band='middle'
)

capital_plot(total_capital, all_profits)

statistics = strategy_test(all_profits, pct_bullish_gain, pct_bearish_gain, total_capital)
statistics = pd.DataFrame.from_dict(statistics, orient='index')
statistics 
0
num_operations71.000000
gains43.000000
pct_gains60.563380
avg_gains804.000000
pct_bullish_gains65.625000
pct_bearish_gains74.358974
losses28.000000
pct_losses39.436620
avg_loss-788.000000
total_profit12522.600000
pct_profit12.522600
drawdown4.195121
EV176.374648

Muitas informações interessantes podem ser tiradas dos resultados acima. Note que como algumas operações foram canceladas, o número total de operações diminuiu de 80 para 71.

Vemos também que obtivemos nessa estratégia com o alvo na banda do meio, um ganho de 60.5%. Além do mais, podemos observar que separando esses ganhos entre compra e venda, a porcentagem de acerto na venda (74.3%) é maior que a porcentagem de acertos na compra (65.6%). O drawdown da operação ficou em 4.2%, o que pode ser considerado bom.

Contudo, o nosso EV foi relativamente baixo. Se olharmos quando a operação da lucro, a média de ganhos esta em R$804 e quando a operação da prejuízo, a média de perdas é de R$788. Nesse caso, a relação de ganho e perda da estratégia é praticamente 1:1.

E como seria agora se mudarmos o nosso alvo para a banda oposta?

Alvo 2: banda oposta

Vamos rodar novamente o nosso código, dessa vez utilizando target_band='opposite' para definirmos o alvo como sendo a banda superior no caso da ponta da compra, e a banda inferior no caso da ponta da venda.

all_profits, pct_bullish_gain, pct_bearish_gain, total_capital = missing_home_algorithm(
  df,
  capital_exposure = 1000,
  initial_capital = 100000,
  target_band='opposite'
)

capital_plot(total_capital, all_profits)

statistics = strategy_test(all_profits, pct_bullish_gain, pct_bearish_gain, total_capital)
statistics = pd.DataFrame.from_dict(statistics, orient='index')
statistics 
0
num_operations67.000000
gains36.000000
pct_gains53.731343
avg_gains1793.000000
pct_bullish_gains45.161290
pct_bearish_gains61.111111
losses31.000000
pct_losses46.268657
avg_loss-994.000000
total_profit33723.425586
pct_profit33.723426
drawdown5.940304
EV503.334710

Note primeiramente que o número de operações diminuiu; foi de 71 para 67. Se o número de sinais é o mesmo e apenas mudamos o nosso alvo, como podemos ter um número de operações diferente?

Acontece que como não estamos definindo um limite no tempo para carregar as operações, as bandas opostas podem demorar mais tempo para serem alcançadas. E como definimos que só podemos realizar uma operação por vez, podemos deixar de entrar em alguma operação se outra já estiver em andamento.

Outra informação importante é que a porcentagem de ganhos diminuiu para 53.7% em comparação aos 60.5% da banda central. Mas assim como no caso anterior, a porcentagem de acerto na ponta da venda foi maior do que na ponta da compra.

O nosso drawdown aumentou levemente para 5.9%. Apenas olhando essas informações poderiamos dizer que o alvo sendo a banda oposta é pior, certo? Mas vamos antes de tirar conclusões olhar as médias de ganhos e perdas assim como o nosso EV.

Nessa nova abordagem, a média de ganhos está em R$1793 enquanto a média de perdas esta em R$994. Isso acabou por geral um EV de R$503 em comparação com o de R$176 obtido anteriormente. Ou seja, embora temos diminuido a nossa taxa de acerto quando mudamos o nosso alvo para a banda oposta ao invés da banda do meio, o nosso lucro é muito maior quando acertamos. Isso faz com que a relação de ganhos e perdas seja de aproximadamente 2:1, o que torna essa estratégia muito interessante.

Conclusão

Nesse backtest da estratégia Saudade de Casa, vimos que realmente existe uma boa possiblidade do ativo voltar para dentro das Bandas de Bollinger quando o mesmo abre fora delas.

Vimos também que quando o alvo é a banda do meio, embora a operação tenha uma boa taxa de acertos, a relação de ganhos e perdas não é tão interessante. Contudo, quando utilizamos as bandas opostas, conseguimos aumentar os nossos ganhos e consequentemente aumentar essa relação.

No artigo de hoje, porém, não limitamos a operação como day trade, mas abrimos a possibilidade de ser um swing trade, ao passo que a operação fica aberta até o preço atingir o alvo ou sermos stopados. Em uma próxima análise, vamos comparar esses dois tipos de estratégias para entendermos qual delas nos dará um maior retorno usando esse setup.

Para acompanhar os próximos artigos e muitos outros backtests de diferentes estratégias, participe do canal QuantBrasil no Telegram e se inscreva na nossa newsletter!