Contrats à terme continus à des fins de backtesting

Auteur:La bonté, Créé: 2019-03-18 10:48:28, mis à jour:

Résumé des contrats à terme

Les contrats à terme sont une forme de contrat établie entre deux parties pour l'achat ou la vente d'une quantité d'un actif sous-jacent à une date spécifiée dans le futur. Cette date est connue sous le nom de livraison ou d'expiration. Lorsque cette date est atteinte, l'acheteur doit livrer le sous-jacent physique (ou l'équivalent en espèces) au vendeur au prix convenu à la date de formation du contrat.

En pratique, les contrats à terme sont négociés sur les bourses (contrairement à la négociation en bourse) pour des quantités et des qualités standardisées du sous-jacent. Les prix sont marqués au marché tous les jours. Les contrats à terme sont incroyablement liquides et sont largement utilisés à des fins spéculatives.

Une liste détaillée de tous les codes de symboles utilisés pour les contrats à terme sur diverses bourses est disponible sur le site CSI Data: Futures Factsheet.

La principale différence entre un contrat à terme et la propriété d'actions est le fait qu'un contrat à terme a une fenêtre limitée de disponibilité en raison de la date d'expiration. À tout moment, il y aura une variété de contrats à terme sur le même sous-jacent, tous avec des dates d'expiration variables. Le contrat avec la date d'expiration la plus proche est connu sous le nom de contrat proche. Le problème auquel nous sommes confrontés en tant que traders quantitatifs est que, à tout moment, nous avons le choix de plusieurs contrats avec lesquels trader. Ainsi, nous avons affaire à un ensemble de séries chronologiques qui se chevauchent plutôt qu'à un flux continu comme dans le cas des actions ou des devises.

L'objectif de cet article est de décrire diverses approches pour construire un flux continu de contrats à partir de cet ensemble de séries multiples et de mettre en évidence les compromis associés à chaque technique.

Formation d'un contrat à terme continu

La principale difficulté à essayer de générer un contrat continu à partir des contrats sous-jacents avec des livraisons variables est que les contrats ne sont pas souvent négociés aux mêmes prix. Ainsi, des situations surviennent où ils ne fournissent pas un épaississement en douceur de l'un à l'autre. Cela est dû aux effets de contango et de backwardation. Il existe diverses approches pour résoudre ce problème, dont nous allons maintenant discuter.

Approches communes

Malheureusement, il n'existe pas de méthode standard unique pour joindre les contrats à terme dans le secteur financier. En fin de compte, la méthode choisie dépendra fortement de la stratégie employant les contrats et de la méthode d'exécution.

Retour en arrière/avant (Panama)

Cette méthode réduit l'écart entre les contrats multiples en déplaçant chaque contrat de manière à ce que les livraisons individuelles se joignent de manière lisse aux contrats adjacents.

Le principal problème de la méthode de Panama est l'introduction d'un biais de tendance, qui introduira une grande dérive des prix. Cela peut entraîner des données négatives pour les contrats suffisamment historiques. En outre, il y a une perte des différences de prix relatives en raison d'un changement absolu des valeurs. Cela signifie que les rendements sont compliqués à calculer (ou tout simplement incorrects).

Ajustement proportionnel

L'approche de l'ajustement de proportionnalité est similaire à la méthodologie d'ajustement du traitement des scissions d'actions. Plutôt que de prendre un changement absolu dans les contrats successifs, le rapport du prix de règlement (close) plus ancien au prix d'ouverture plus récent est utilisé pour ajuster proportionnellement les prix des contrats historiques. Cela permet un flux continu sans interruption du calcul des rendements en pourcentage.

Le principal problème avec l'ajustement proportionnel est que toutes les stratégies de trading basées sur un niveau de prix absolu devront également être ajustées de la même manière afin d'exécuter le bon signal.

Retour de série/série perpétuelle

L'essence de cette approche est de créer un contrat continu de contrats successifs en prenant une proportion pondérée linéairement de chaque contrat sur un certain nombre de jours afin d'assurer une transition plus fluide entre chacun.

Par exemple, considérons cinq jours de lissage. Le prix au jour 1, P1, est égal à 80% du prix du contrat loin (F1) et 20% du prix du contrat près (N1). De même, le jour 2, le prix est P2=0.6×F2+0.4×N2. Au jour 5, nous avons P5=0.0×F5+1.0×N5=N5 et le contrat devient alors une continuation du prix près. Ainsi, après cinq jours, le contrat passe en douceur du loin au proche.

Le problème avec la méthode de roulement est qu'elle nécessite une négociation tous les cinq jours, ce qui peut augmenter les coûts de transaction.

Il existe d'autres approches moins courantes du problème, mais nous les éviterons ici.

Formation de roulement-retour dans Python et Pandas

Le reste de l'article se concentrera sur la mise en œuvre de la méthode des séries perpétuelles car elle est la plus appropriée pour le backtesting.

Nous allons assembler les contrats à terme du pétrole brut WTI near et far (symbole CL) afin de générer une série de prix continue. Au moment de la rédaction (janvier 2014), le contrat proche est CLF2014 (janvier) et le contrat lointain est CLG2014 (février).

Pour effectuer le téléchargement des données futures, j'ai utilisé le plugin Quandl. Assurez-vous de configurer l'environnement virtuel Python correct sur votre système et installez le package Quandl en tapant ce qui suit dans le terminal:

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

Le travail principal est effectué dans la fonction futures_rollover_weights. Elle nécessite une date de début (la première date du contrat proche), un dictionnaire des dates de règlement du contrat (date d'expiration), les symboles des contrats et le nombre de jours pour renouveler le contrat (par défaut à cinq).

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

Maintenant que la matrice de pondération a été produite, il est possible de l'appliquer aux séries chronologiques individuelles.

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)

La sortie est la suivante:

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 - Je ne sais pas. - Je ne sais pas. 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 Longueur: 60, type d: flotteur64

On peut voir que la série est maintenant continue sur les deux contrats.


Plus de