Contratos de futuros contínuos para efeitos de backtesting

Autora:Bem-estar, Criado: 2019-03-18 10:48:28, Atualizado:

Resumo breve dos contratos de futuros

Os futuros são uma forma de contrato elaborada entre duas partes para a compra ou venda de uma quantidade de um ativo subjacente em uma data específica no futuro. Esta data é conhecida como a entrega ou expiração. Quando esta data é atingida, o comprador deve entregar o subjacente físico (ou equivalente em dinheiro) ao vendedor pelo preço acordado na data de formação do contrato.

Na prática, os futuros são negociados nas bolsas (em oposição à negociação Over The Counter - OTC) para quantidades e qualidades padronizadas do subjacente. Os preços são marcados para o mercado todos os dias. Os futuros são incrivelmente líquidos e são usados fortemente para fins especulativos.

Uma lista pormenorizada de todos os códigos de símbolos utilizados para contratos de futuros em várias bolsas pode ser encontrada no site CSI Data: Futures Factsheet.

A principal diferença entre um contrato de futuros e a propriedade de ações é o fato de que um contrato de futuros tem uma janela limitada de disponibilidade em virtude da data de expiração. Em qualquer momento, haverá uma variedade de contratos de futuros no mesmo subjacente, todos com datas de expiração variáveis. O contrato com a data de expiração mais próxima é conhecido como contrato próximo. O problema que enfrentamos como comerciantes quantitativos é que, em qualquer momento, temos a escolha de vários contratos com os quais negociar. Assim, estamos lidando com um conjunto de séries de tempo sobrepostas em vez de um fluxo contínuo como no caso de ações ou câmbio.

O objetivo deste artigo é delinear várias abordagens para construir um fluxo contínuo de contratos a partir deste conjunto de séries múltiplas e destacar as compensações associadas a cada técnica.

Formar um contrato de futuros contínuo

A principal dificuldade em tentar gerar um contrato contínuo a partir dos contratos subjacentes com entregas variáveis é que os contratos não costumam ser negociados aos mesmos preços. Assim, surgem situações em que eles não fornecem uma empilhadeira suave de um para o outro. Isso é devido aos efeitos de contango e backwardation.

Abordagens comuns

Infelizmente, não existe um único método padrão para unir contratos futuros no setor financeiro. Em última análise, o método escolhido dependerá muito da estratégia que emprega os contratos e do método de execução.

Ajuste para trás/para a frente (Panama)

Este método reduz a lacuna entre contratos múltiplos, mudando cada contrato de modo que as entregas individuais se unam de forma suave aos contratos adjacentes.

O principal problema com o método Panamá inclui a introdução de um viés de tendência, que introduzirá uma grande deriva nos preços. Isso pode levar a dados negativos para contratos suficientemente históricos. Além disso, há uma perda das diferenças de preço relativo devido a uma mudança absoluta nos valores. Isso significa que os retornos são complicados de calcular (ou simplesmente incorretos).

Ajuste proporcional

A abordagem de Ajuste de Proporcionalidade é semelhante à metodologia de ajuste de tratamento de divisões de estoque em ações. Em vez de tomar uma mudança absoluta nos contratos sucessivos, a relação do preço de liquidação (fechamento) mais antigo para o preço de abertura mais recente é usada para ajustar proporcionalmente os preços dos contratos históricos. Isso permite um fluxo contínuo sem uma interrupção do cálculo dos retornos percentuais.

O principal problema com o ajuste proporcional é que quaisquer estratégias de negociação que dependem de um nível de preço absoluto também terão que ser ajustadas de forma semelhante para executar o sinal correto.

Reversão/Série Perpétua

A essência desta abordagem consiste em criar um contrato contínuo de contratos sucessivos, tomando uma proporção ponderada linearmente de cada contrato ao longo de um número de dias para assegurar uma transição mais suave entre cada contrato.

Por exemplo, considere cinco dias de suavização. O preço no dia 1, P1, é igual a 80% do preço do contrato distante (F1) e 20% do preço do contrato próximo (N1). Da mesma forma, no dia 2, o preço é P2=0.6×F2+0.4×N2. No dia 5, temos P5=0.0×F5+1.0×N5=N5 e o contrato então se torna apenas uma continuação do preço próximo. Assim, após cinco dias, o contrato passa suavemente do distante para o próximo.

O problema com o método de rollover é que exige negociação em todos os cinco dias, o que pode aumentar os custos de transação.

Há outras abordagens menos comuns para o problema, mas vamos evitá-las aqui.

Formação de Roll-Return em Python e Pandas

O restante do artigo concentrar-se-á na implementação do método de série perpétua, pois este é mais adequado para backtesting.

Vamos juntar o contrato de futuros de petróleo bruto WTI near e far (símbolo CL) para gerar uma série de preços contínua.

Para realizar o download de dados de futuros, usei o plugin Quandl. Certifique-se de configurar o ambiente virtual Python correto em seu sistema e instale o pacote Quandl digitando o seguinte no terminal:

import datetime
import numpy as np
import pandas as pd
import Quandl

O trabalho principal é realizado na função futures_rollover_weights. Requer uma data de início (a primeira data do contrato próximo), um dicionário de datas de liquidação do contrato (datas de expiração), os símbolos dos contratos e o número de dias para reverter o contrato (por padrão para cinco).

def futures_rollover_weights(start_date, expiry_dates, contracts, rollover_days=5):
    """This constructs a pandas DataFrame that contains weights (between 0.0 and 1.0)
    of contract positions to hold in order to carry out a rollover of rollover_days
    prior to the expiration of the earliest contract. The matrix can then be
    'multiplied' with another DataFrame containing the settle prices of each
    contract in order to produce a continuous time series futures contract."""

    # Construct a sequence of dates beginning from the earliest contract start
    # date to the end date of the final contract
    dates = pd.date_range(start_date, expiry_dates[-1], freq='B')

    # Create the 'roll weights' DataFrame that will store the multipliers for
    # each contract (between 0.0 and 1.0)
    roll_weights = pd.DataFrame(np.zeros((len(dates), len(contracts))),
                                index=dates, columns=contracts)
    prev_date = roll_weights.index[0]

    # Loop through each contract and create the specific weightings for
    # each contract depending upon the settlement date and rollover_days
    for i, (item, ex_date) in enumerate(expiry_dates.iteritems()):
        if i < len(expiry_dates) - 1:
            roll_weights.ix[prev_date:ex_date - pd.offsets.BDay(), item] = 1
            roll_rng = pd.date_range(end=ex_date - pd.offsets.BDay(),
                                     periods=rollover_days + 1, freq='B')

            # Create a sequence of roll weights (i.e. [0.0,0.2,...,0.8,1.0]
            # and use these to adjust the weightings of each future
            decay_weights = np.linspace(0, 1, rollover_days + 1)
            roll_weights.ix[roll_rng, item] = 1 - decay_weights
            roll_weights.ix[roll_rng, expiry_dates.index[i+1]] = decay_weights
        else:
            roll_weights.ix[prev_date:, item] = 1
        prev_date = ex_date
    return roll_weights

Agora que a matriz de ponderação foi produzida, é possível aplicá-la às séries temporais individuais. A função principal descarrega os contratos próximos e distantes, cria um único DataFrame para ambos, constrói a matriz de ponderação de rollover e, finalmente, produz uma série contínua de ambos os preços, ponderados adequadamente:

if __name__ == "__main__":
    # Download the current Front and Back (near and far) futures contracts
    # for WTI Crude, traded on NYMEX, from Quandl.com. You will need to 
    # adjust the contracts to reflect your current near/far contracts 
    # depending upon the point at which you read this!
    wti_near = Quandl.get("OFDP/FUTURE_CLF2014")
    wti_far = Quandl.get("OFDP/FUTURE_CLG2014")
    wti = pd.DataFrame({'CLF2014': wti_near['Settle'],
                        'CLG2014': wti_far['Settle']}, index=wti_far.index)

    # Create the dictionary of expiry dates for each contract
    expiry_dates = pd.Series({'CLF2014': datetime.datetime(2013, 12, 19),
                              'CLG2014': datetime.datetime(2014, 2, 21)}).order()

    # Obtain the rollover weighting matrix/DataFrame
    weights = futures_rollover_weights(wti_near.index[0], expiry_dates, wti.columns)

    # Construct the continuous future of the WTI CL contracts
    wti_cts = (wti * weights).sum(1).dropna()

    # Output the merged series of contract settle prices
    wti_cts.tail(60)

A saída é a seguinte:

2013-10-14 102.230 2013-10-15 101.240 2013-10-16 102.330 2013-10-17 100.620 2013-10-18 100.990 2013-10-21 99,760 2013-10-22 98.470 2013-10-23 97.000 2013-10-24 97.240 2013-10-25 97.950 - Não. - Não. 2013-12-24 99,220 2013-12-26 99,550 2013-12-27 100.320 2013-12-30 99,290 2013-12-31 98.420 2014-01-02 95.440 2014-01-03 93.960 2014-01-06 93.430 2014-01-07 93.670 2014-01-08 92.330 Comprimento: 60, dtipo: flutuador64

Pode-se ver que a série é agora contínua em ambos os contratos. O próximo passo é realizar isso para várias entregas em uma variedade de anos, dependendo de suas necessidades de backtesting.


Mais.