Des transactions en paire basées sur des technologies basées sur les données

Auteur:La bonté, Créé: 2019-08-21 13:50:23, Mis à jour: 2023-10-19 21:01:31

img

L'appariement des transactions est un bon exemple de stratégie de négociation basée sur l'analyse mathématique. Dans cet article, nous allons démontrer comment utiliser les données pour créer et automatiser des stratégies de négociation d'appariement.

Les principes de base

假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.

Lorsque des différences de prix temporaires existent, les transactions vont vendre les investisseurs performants (les investisseurs qui augmentent) et acheter les investisseurs qui diminuent (les investisseurs qui diminuent). Vous pouvez être sûr que la différence de rentabilité entre les deux investisseurs finira par se traduire par une baisse des investisseurs performants ou une reprise des investisseurs qui diminuent ou les deux.

Par conséquent, l'appariement est une stratégie de négociation neutre sur le marché qui permet aux traders de profiter de presque toutes les conditions du marché: tendance haussière, tendance baissière ou réglage horizontal.

Expliquer le concept: deux hypothèses d'investissement

  • Nous avons construit notre environnement de recherche sur la plateforme de quantification des inventeurs.

Tout d'abord, pour que le travail se déroule bien, nous devons construire notre environnement de recherche, et dans cet article, nous utilisons une plate-forme de quantification des inventeurs.FMZ.COMLe projet a été conçu pour créer un environnement de recherche, principalement pour une interface d'API facile et rapide et un système Docker complet.

Dans le nom officiel de la plate-forme de quantification des inventeurs, ce système Docker est appelé système d'hébergement.

Pour savoir comment déployer des hôtes et des robots, veuillez vous référer à mon précédent article:https://www.fmz.com/bbs-topic/4140

Les lecteurs qui souhaitent acheter leur propre hôte de déploiement de serveur en nuage peuvent consulter cet article:https://www.fmz.com/bbs-topic/2848

Après avoir déployé avec succès de bons services de cloud computing et un système d'administrateur, nous allons installer le plus grand temple de Python à ce jour: Anaconda.

Pour mettre en œuvre tous les environnements de programmation nécessaires à cet article (la bibliothèque de dépendances, la gestion des versions, etc.), le moyen le plus simple est d'utiliser Anaconda. Il s'agit d'un écosystème de data science Python et d'un gestionnaire de bibliothèque de dépendances.

Pour savoir comment installer Anaconda, consultez le guide officiel d'Anaconda:https://www.anaconda.com/distribution/

本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.

Ces bases peuvent également être consultées dans mon article précédent sur la configuration de l'environnement Anaconda et les bibliothèques numpy et pandas:https://www.fmz.com/digest-topic/4169

La prochaine chose que nous allons faire, c'est mettre en place un code pour les deux hypothèses de l'investissement.

import numpy as np
import pandas as pd

import statsmodels
from statsmodels.tsa.stattools import coint
# just set the seed for the random number generator
np.random.seed(107)

import matplotlib.pyplot as plt

Oui, nous allons aussi utiliser la bibliothèque de graphiques très connue de Python, matplotlib.

Supposons que nous générions X d'un indicateur hypothétique d'investissement et que nous simulions son rendement quotidien en utilisant une distribution normale.

# Generate daily returns
Xreturns = np.random.normal(0, 1, 100) 
# sum them and shift all the prices up
X = pd.Series(np.cumsum(
    Xreturns), name='X') 
    + 50
X.plot(figsize=(15,7))
plt.show()

img

X de l'indicateur d'investissement, simulant sa rentabilité quotidienne par une distribution normale

Maintenant, nous avons généré Y et X qui sont fortement liés entre eux, donc le prix de Y devrait être très similaire à la variation de X. Nous avons modélisé cela en prenant X, en le déplaçant vers le haut et en ajoutant un peu de bruit aléatoire extrait de la distribution normale.

noise = np.random.normal(0, 1, 100)
Y = X + 5 + noise
Y.name = 'Y'
pd.concat([X, Y], axis=1).plot(figsize=(15,7))
plt.show()

img

Les X et Y des indices d'investissement co-intégrés

La cohésion

协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:

Y = X + e

L'e est le bruit et l'e est la fréquence.

Pour les paires de transactions entre deux séquences de temps, le rapport doit nécessairement converger avec le temps vers des valeurs égales, c'est-à-dire qu'elles doivent être coïncidentes. La séquence de temps que nous avons construite ci-dessus est coïncidente. Nous allons maintenant tracer le rapport entre les deux afin que nous puissions voir à quoi elle ressemble.

(Y/X).plot(figsize=(15,7)) 
plt.axhline((Y/X).mean(), color='red', linestyle='--') 
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()

img

Le ratio et la moyenne entre les prix des deux indices d'investissement coordonné

Tests de co-intégration

Il y a une méthode de test pratique qui est d'utiliser statsmodels.tsa.stattools. Nous devrions voir une très faible p-value parce que nous avons artificiellement créé deux séries de données qui coïncident le plus possible.

# compute the p-value of the cointegration test
# will inform us as to whether the ratio between the 2 timeseries is stationary
# around its mean
score, pvalue, _ = coint(X,Y)
print pvalue

Le résultat est le suivant: 1.81864477307e-17

Remarque: la pertinence et la cohérence

Relativité et cohérence, bien que similaires en théorie, ne sont pas la même chose. Voyons des exemples de séries de données liées mais non cohérentes, et vice versa.

X.corr(Y)

Le résultat est: 0.951.

Comme on pouvait s'y attendre, c'est très élevé. Mais qu'en est-il de deux séries liées mais non cohérentes? Un exemple simple est deux séries de données déviantes.

ret1 = np.random.normal(1, 1, 100)
ret2 = np.random.normal(2, 1, 100)

s1 = pd.Series( np.cumsum(ret1), name='X')
s2 = pd.Series( np.cumsum(ret2), name='Y')

pd.concat([s1, s2], axis=1 ).plot(figsize=(15,7))
plt.show()
print 'Correlation: ' + str(X_diverging.corr(Y_diverging))
score, pvalue, _ = coint(X_diverging,Y_diverging)
print 'Cointegration test p-value: ' + str(pvalue)

img

Deux séries connexes (non intégrées)

Coefficient de réponse: 0.998 P-value de l'examen de co-intégration: 0,258

Les exemples simples de co-intégration sans corrélation sont les séquences de distribution normale et les ondes carrées.

Y2 = pd.Series(np.random.normal(0, 1, 800), name='Y2') + 20
Y3 = Y2.copy()
Y3[0:100] = 30
Y3[100:200] = 10
Y3[200:300] = 30
Y3[300:400] = 10
Y3[400:500] = 30
Y3[500:600] = 10
Y3[600:700] = 30
Y3[700:800] = 10
Y2.plot(figsize=(15,7))
Y3.plot()
plt.ylim([0, 40])
plt.show()
# correlation is nearly zero
print 'Correlation: ' + str(Y2.corr(Y3))
score, pvalue, _ = coint(Y2,Y3)
print 'Cointegration test p-value: ' + str(pvalue)

img

Je suis un peu dégoûté. P-value de l'examen de co-intégration: 0.0

La corrélation est très faible, mais les p-values montrent une parfaite synergie!

Comment faire les transactions de couplage?

Parce que deux séquences de temps coordonnées (par exemple, X et Y ci-dessus) sont alignées et déviées l'une de l'autre, il arrive parfois que le seuil soit élevé et le seuil soit bas. Nous effectuons des transactions de couplage en achetant un indice et en vendant un autre. Ainsi, si les deux indices chutent ou montent ensemble, nous ne gagnons ni ne perdons de l'argent, c'est-à-dire que nous sommes neutres sur le marché.

En revenant à Y = X + e dans X et Y, et en faisant bouger le ratio ((Y / X) autour de son axe de moyenne, nous gagnons de l'argent grâce au ratio de retour de la moyenne. Pour ce faire, nous faisons attention aux situations où X et Y sont très éloignés, c'est-à-dire que le seuil est trop élevé ou trop bas:

  • Faire plus de ratios: c'est lorsque le ratio est très faible et que nous nous attendons à ce qu'il soit plus grand. Dans l'exemple ci-dessus, nous ouvrons une position en faisant plus de Y et en faisant un X vide.

  • Le taux de vacance: c'est quand le taux de vacance est élevé et que nous nous attendons à ce qu'il change d'heure. Dans l'exemple ci-dessus, nous ouvrons une position en vacant Y et en faisant plus X.

Notez que nous avons toujours une position de couverture de couverture de couverture: si la valeur de l'achat ou de la perte de l'indice de négociation est négative, la position de couverture de couverture gagne, et vice versa, donc nous sommes immunisés contre les mouvements globaux du marché.

Si les indices X et Y se déplacent par rapport à l'autre, nous gagnons ou perdons.

Utiliser les données pour rechercher des actions similaires à un indicateur de transaction

La meilleure façon de le faire est de commencer par l'indicateur de transaction que vous soupçonnez d'être synchrone et d'effectuer un test statistique.Variation de la comparaisonLes victimes de la guerre sont les victimes de la guerre.

Variation de la comparaisonIl s'agit d'une situation où les chances de générer des p-values importantes par erreur augmentent lorsque vous exécutez de nombreux tests, car nous avons besoin d'exécuter un grand nombre de tests. Si nous effectuons 100 tests sur des données aléatoires, nous devrions voir 5 p-values inférieures à 0.05. Si vous devez comparer n indicateurs de transaction pour effectuer des coordonnées entières, vous verrez beaucoup de p-values incorrectes, ce qui augmente avec l'augmentation de votre échantillon de tests. Pour éviter cela, choisissez quelques paires de transactions pour lesquelles vous avez des raisons de penser qu'elles peuvent être coordonnées, puis testez-les séparément.Variation de la comparaison

Prenons l'exemple d'un panier de grandes sociétés américaines de technologie dans le S&P 500, qui fonctionnent dans des segments de marché similaires et ont des prix de cohésion. Nous scannons la liste des indices et testons la cohésion entre toutes les paires.

Retourne la matrice de co-intégration de l'examen de fraction, la matrice de p-valeur et toutes les paires dont la valeur de p est inférieure à 0.05.Cette méthode est susceptible d'avoir des écarts de comparaison multiples, donc ils ont en fait besoin d'une deuxième vérification.Dans cet article, nous avons choisi d'ignorer cela dans l'exemple pour faciliter notre exposé.

def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs

Remarque: nous avons inclus dans les données le benchmark du marché (SPX) - le marché est à l'origine de la circulation de nombreux indices de négociation, et vous pouvez souvent trouver deux indices de négociation qui semblent coordonnées; mais en réalité, elles ne sont pas coordonnées entre elles, mais avec le marché.

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','AAPL','ADBE','SYMC','EBAY','MSFT','QCOM',
                 'HPQ','JNPR','AMD','IBM']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['Adj Close']
data.head(3)

img

Maintenant, essayons d'utiliser notre méthode pour trouver des paires de transactions qui sont coordonnées.

# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print pairs
[('ADBE', 'MSFT')]

img

Il semble que le sodium ADBE et le sodium MSFT fonctionnent ensemble.

S1 = data['ADBE']
S2 = data['MSFT']
score, pvalue, _ = coint(S1, S2)
print(pvalue)
ratios = S1 / S2
ratios.plot()
plt.axhline(ratios.mean())
plt.legend([' Ratio'])
plt.show()

img

Graphique des ratios de prix entre MSFT et ADBE de 2008 à 2017

Ce ratio ressemble en effet à une moyenne stable. Le ratio absolu n'est pas très utile en statistique. Il est plus utile de normaliser notre signal en le considérant comme un score z. Le score z est défini comme:

Le score Z (valeur) = (valeur moyenne) / écart type

Attention!

En fait, nous essayons généralement de faire des extensions aux données, mais à condition qu'elles soient normales. Cependant, beaucoup de données financières ne sont pas normales, nous devons donc être très prudents de ne pas simplement supposer la normalité ou une distribution particulière lors de la génération de statistiques.

def zscore(series):
    return (series - series.mean()) / np.std(series)
zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()

img

Ratio de prix Z entre MSFT et ADBE de 2008 à 2017

Il est maintenant plus facile d'observer les ratios se déplaçant près de la moyenne, mais il est parfois facile de voir de grandes différences avec la moyenne, et nous pouvons en profiter.

Maintenant que nous avons discuté des bases de la stratégie de couplage des transactions et que nous avons déterminé un indice de transaction commun, basé sur les prix historiques, essayons de développer un signal de transaction. Tout d'abord, revenons sur les étapes pour développer des signaux de transaction à l'aide de la technologie des données:

  • Rassembler des données fiables et les nettoyer

  • Création de fonctionnalités à partir des données pour identifier les signaux/logiques de transaction

  • Les fonctionnalités peuvent être des moyennes mobiles ou des données de prix, des ratios de pertinence ou de signaux plus complexes - les combiner pour créer de nouvelles fonctionnalités

  • Utilisez ces fonctionnalités pour générer des signaux de trading, c'est-à-dire des signaux d'achat, de vente ou de vente libre.

Heureusement, nous avons une plateforme de quantification pour les inventeurs.fmz.comLes développeurs de stratégies peuvent consacrer beaucoup d'énergie et de temps à la conception de la logique stratégique et à l'extension des fonctionnalités.

Dans la plateforme de quantification des inventeurs, il y a des interfaces de toutes sortes d'échanges traditionnels qui sont bien emballées, et tout ce que nous avons à faire est d'appeler ces interfaces API, le reste de la logique de mise en œuvre sous-jacente, qui a déjà été affinée par une équipe de professionnels.

Pour l'intégralité de la logique et l'explication des principes, nous présentons ici ces logiques sous-jacentes de manière déconcertante, mais en pratique, les lecteurs peuvent directement appeler l'API quantifiée par l'inventeur pour effectuer les quatre aspects ci-dessus.

Nous allons commencer:

Première étape: définissez votre problème

Ici, nous essayons de créer un signal qui nous indique si le taux est acheté ou vendu au moment suivant, c'est-à-dire que notre variable de prédiction Y:

Y = Ratio est acheter (1) ou vendre (-1)

Y ((t) = Sign ((Ratio ((t+1) Ratio ((t))

Notez que nous n'avons pas besoin de prédire le prix de l'indice de négociation réel, ni même la valeur réelle du ratio (bien que nous puissions), nous avons seulement besoin de prédire la direction du taux à suivre.

Deuxième étape: collecter des données fiables et précises

L'inventeur de la quantification est votre ami! Il vous suffit de spécifier l'indice à échanger et la source de données à utiliser, et il extrait les données nécessaires et les nettoie pour effectuer la fractionation des dividendes et des indices; nous avons donc les données ici propres.

Nous avons obtenu les données suivantes sur les jours de négociation des 10 dernières années (environ 2500 points de données) en utilisant Yahoo Finance: prix d'ouverture, prix de clôture, prix le plus élevé, prix le plus bas et volume des transactions.

Troisième étape: scinder les données

N'oubliez pas cette étape très importante pour tester l'exactitude du modèle. Nous sommes en train de faire une fraction de formation / vérification / test avec les données suivantes.

  • Formation 7 ans ~ 70%

  • Test ~ 3 ans 30%

ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]

Dans l'idéal, nous devrions également créer des ensembles de vérification, mais nous ne le ferons pas pour l'instant.

Quatrième étape: l'ingénierie des caractéristiques

Quelles peuvent être les fonctions associées? Nous voulons prédire la direction des changements des ratios. Nous avons vu que nos deux indicateurs de transaction sont synchronisés, de sorte que le ratio est souvent déplacé et retourné à la moyenne. Il semble que notre caractéristique devrait être une certaine mesure de la moyenne des ratios, la différence entre la valeur actuelle et la moyenne peut produire nos signaux de transaction.

Nous utilisons les fonctionnalités suivantes:

  • Moyenne mobile de 60 jours: mesure de la moyenne mobile

  • Moyenne mobile de 5 jours: mesure de la valeur actuelle de la moyenne

  • 60 jours d'écart

  • Le score z: ((5d MA - 60d MA) / 60d SD

ratios_mavg5 = train.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = train.rolling(window=60,
                               center=False).mean()
std_60 = train.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()

img

Ratio de prix entre 60d et 5d MA

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()

img

Proportion de prix de 60 à 5 Z

Le score z de l'équation de rotation a vraiment une nature de régression de l'équation!

Cinquième étape: le choix du modèle

Commençons par un modèle très simple. Regardez le graphique du z-score, et nous pouvons voir que si le z-score est trop haut ou trop bas, il revient.

  • Quand z est inférieur à -1, le ratio est acheter ((1) car on s'attend à ce que z revienne à 0, donc le ratio augmente.

  • Lorsque z est supérieur à 1.0, le taux est de vente (−1) car on s'attend à ce que z revienne à 0, donc le taux diminue.

Sixième étape: entraîner, vérifier et optimiser

Enfin, voyons l'impact réel de notre modèle sur les données réelles.

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1] = 0
buy[60:].plot(color=’g’, linestyle=’None’, marker=’^’)
sell[60:].plot(color=’r’, linestyle=’None’, marker=’^’)
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,ratios.min(),ratios.max()))
plt.legend([‘Ratio’, ‘Buy Signal’, ‘Sell Signal’])
plt.show()

img

Signaux de prix pour acheter et vendre

Ce signal semble raisonnable, nous semblons vendre le ratio quand il est élevé ou augmenté (points rouges) et nous le rachetons quand il est bas (points verts) et diminué.

# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1 = data['ADBE'].iloc[:1762]
S2 = data['MSFT'].iloc[:1762]
S1[60:].plot(color='b')
S2[60:].plot(color='c')
buyR = 0*S1.copy()
sellR = 0*S1.copy()
# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]
# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['ADBE','MSFT', 'Buy Signal', 'Sell Signal'])
plt.show()

img

Signaux pour acheter et vendre des actions MSFT et ADBE

Remarquez comment nous gagnons parfois de l'argent sur les jambes courtes, parfois sur les jambes longues, parfois les deux.

Nous sommes satisfaits du signal des données d'entraînement. Voyons quel profit ce signal peut générer. Lorsque le ratio est bas, nous pouvons fabriquer un simple retoucheur, acheter 1 ratio (acheter 1 action ADBE et vendre le ratio x action MSFT), vendre 1 ratio (acheter 1 action ADBE et acheter le ratio x action MSFT) et calculer les transactions PnL de ces ratios.

# Trade using a simple strategy
def trade(S1, S2, window1, window2):
    
    # If window length is 0, algorithm doesn't make sense, so exit
    if (window1 == 0) or (window2 == 0):
        return 0
    
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2
    ma1 = ratios.rolling(window=window1,
                               center=False).mean()
    ma2 = ratios.rolling(window=window2,
                               center=False).mean()
    std = ratios.rolling(window=window2,
                        center=False).std()
    zscore = (ma1 - ma2)/std
    
    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
            print('Selling Ratio %s %s %s %s'%(money, ratios[i], countS1,countS2))
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
            print('Buying Ratio %s %s %s %s'%(money,ratios[i], countS1,countS2))
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.75:
            money += S1[i] * countS1 + S2[i] * countS2
            countS1 = 0
            countS2 = 0
            print('Exit pos %s %s %s %s'%(money,ratios[i], countS1,countS2))
            
            
    return money
trade(data['ADBE'].iloc[:1763], data['MSFT'].iloc[:1763], 60, 5)

Le résultat est: 1783.375

Cette stratégie semble donc rentable! Maintenant, nous pouvons optimiser davantage la performance des données de vérification en modifiant la fenêtre de temps moyen mobile, en modifiant le seuil de vente/achat des positions de marché et ainsi de suite.

On peut aussi essayer des modèles plus complexes, comme la régression logistique, la SVM, etc., pour faire des prédictions de 1/1.

Maintenant, allons plus loin dans ce modèle, et cela nous amène à

Étape 7: réévaluer les données du test

Encore une fois, la plate-forme de quantification de l'inventeur, qui utilise un moteur de retouche QPS/TPS performant, une reproduction réelle de l'environnement historique, élimine les pièges de retouche quantifiée courants et détecte les lacunes stratégiques en temps opportun, ce qui aide à mieux investir dans la réalité.

Dans cet article, nous allons expliquer le principe, ou bien choisir de montrer la logique sous-jacente, ou encore recommander aux lecteurs d'utiliser la plate-forme de quantification des inventeurs, en plus de gagner du temps, il est important d'améliorer le taux d'erreur.

La répétition est très simple, et nous pouvons utiliser la fonction ci-dessus pour voir le PnL des données de test.

trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)

Le résultat est: 5262 868.

Le modèle a bien fonctionné! C'est devenu notre premier modèle simple de paire de transactions.

Évitez de trop vous adapter

Avant de terminer la discussion, j'aimerais parler en particulier de l'hyper-conformité. L'hyper-conformité est le piège le plus dangereux de la stratégie de négociation. Un algorithme d'hyper-conformité peut très bien fonctionner dans les rétrospectives mais échouer sur de nouvelles données invisibles - ce qui signifie qu'il ne révèle pas vraiment de tendances dans les données et n'a pas une véritable capacité de prédiction.

Dans notre modèle, nous utilisons les prévisions des paramètres de défilement et souhaitons optimiser la longueur de la fenêtre de temps. Nous pouvons décider simplement d'irriger toutes les possibilités, la longueur de la fenêtre de temps raisonnable, et de choisir la longueur de temps selon la meilleure performance de notre modèle. Ci-dessous, nous écrivons un cycle simple pour évaluer la longueur de la fenêtre de temps en fonction des données de formation et trouver le cycle optimal.

# Find the window length 0-254 
# that gives the highest returns using this strategy
length_scores = [trade(data['ADBE'].iloc[:1762], 
                data['MSFT'].iloc[:1762], l, 5) 
                for l in range(255)]
best_length = np.argmax(length_scores)
print ('Best window length:', best_length)
('Best window length:', 40)

Maintenant que nous avons examiné la performance du modèle sur les données de test, nous avons constaté que la longueur de cette fenêtre de temps n'était pas optimale!

# Find the returns for test data
# using what we think is the best window length
length_scores2 = [trade(data['ADBE'].iloc[1762:], 
                  data['MSFT'].iloc[1762:],l,5) 
                  for l in range(255)]
print (best_length, 'day window:', length_scores2[best_length])
# Find the best window length based on this dataset, 
# and the returns using this window length
best_length2 = np.argmax(length_scores2)
print (best_length2, 'day window:', length_scores2[best_length2])
(40, 'day window:', 1252233.1395)
(15, 'day window:', 1449116.4522)

Il est évident que les données de notre échantillon ne produisent pas toujours de bons résultats à l'avenir. Juste pour tester, nous allons tracer les fractions de longueur calculées à partir de deux ensembles de données.

plt.figure(figsize=(15,7))
plt.plot(length_scores)
plt.plot(length_scores2)
plt.xlabel('Window length')
plt.ylabel('Score')
plt.legend(['Training', 'Test'])
plt.show()

img

Nous pouvons voir que tout ce qui se situe entre 20 et 50 est une bonne option pour la fenêtre de temps.

Afin d'éviter de trop s'adapter, nous pouvons choisir la longueur d'une fenêtre de temps en utilisant la nature de la logique économique ou des algorithmes. Nous pouvons également utiliser un filtre Kalman, qui ne nous oblige pas à spécifier la longueur; cette méthode sera présentée plus loin dans un autre article.

La prochaine étape

Dans cet article, nous proposons quelques méthodes d'introduction simples pour démontrer le processus de développement d'une stratégie de négociation. Dans la pratique, il est préférable d'utiliser des statistiques plus complexes.

  • Indice du Hearst

  • La demi-vie de la régression moyenne déduite du processus Ornstein-Uhlenbeck

  • Filtreur Kalman


Relationnée

Plus de

bk_fundJe n'ai pas trouvé ce paquet.

bk_fundOù installer le backtester.dataSource.yahoo_data_source? Je suis en train de faire une mise à jour de mon système.