Introduzione all’Ottimizzazione di una Strategia

Sommario

Nei precedenti articoli è stato descritto come creare un modello predittivo (come il Suppor Vector Machine e il Classificatore Random Forest) e una strategia di trading basato su di esso. E’ stato evidenziato come tali modelli prevedano molti parametri.
Nel caso di un SVM si ha i parametri di “tuning” \(\gamma\) e C. In una strategia di crossover della media mobile si ha i parametri per le due finestre di ricerca della media mobile, usata come filtro.

In questo articolo si descrivono i metodi di ottimizzazione per migliorare le prestazioni delle strategie di trading, definendo i parametri in modo sistematico. A tal fine si usano approcci statistici per la selezione del modello, come la convalida incrociata e la ricerca della griglia.
La letteratura sulla selezione dei modelli e l’ottimizzazione dei parametri è vasta e la maggior parte dei metodi
sono oltre lo scopo di questo articolo. Si vuole introdurre l’argomento in modo che si possa esplorare autonomamente le tecniche più avanzate.

Ottimizzazione dei Parametri

In questa fase si usano uno o più parametri per poter far lavorare quasi tutte le strategie di trading e i modelli statistici sottostanti. Nelle strategie di momentum che utilizzano indicatori tecnici,
come ad esempio le medie mobili (semplici o esponenziali), è necessario specificare una finestra di lookback, cioè il numero di periodi passati sui quali calcolare la media. Lo stesso vale per molte strategie di mean-reverting, che richiedono una finestra (rolling) di lookback per calcolare la regressione tra due serie temporali. In particolare i modelli di machine learning statistico, come la regressione logistica, lo SVM o il Random Forest, richiedono dei parametri per poter essere calcolati.

Il più grande pericolo quando si considera l’ottimizzazione dei parametri è quello dell’overfitting del modello o della strategia di trading. Questo problema si verifica quando un modello viene addestrato su un “in-sample” set di dati ed è ottimizzato per funzionare bene su tali dati (con una specifica misura di performance), ma
le prestazioni si riducono in modo sostanziale quanto sono applicati dati “out of sample”. Ad esempio, una strategia di trading potrebbe funzionare molto bene nel backtesting (dati in-sample) ma quando applicata al live trading può essere completamente inutile.

Un’ulteriore preoccupazione dell’ottimizzazione dei parametri è che può diventare computazionale molto costosa. Con i moderni sistemi computazionali questo problema è meno critico rispetto a qualche anno fa, grazie ad una maggiore parallelizzazione e CPU più veloci. Tuttavia, l’ottimizzazione di più parametri può aumentare la complessità del calcolo di alcuni ordini di grandezza.

Quali parametri ottimizzare?

Un modello di trading algoritmico basato sulle statistiche ha spesso molti parametri e diverse misure di performance, dato che il sottostante algoritmo di apprendimento statistico ha il proprio set di parametri. Nel caso di una multipla regressione lineare o logistica, questi sono i coefficienti \(\beta_i\).
Nel caso di una Random Forest un parametro è il numero di alberi decisionali da utilizzare. Una volta applicati a un modello di trading, altri parametri sono le soglie di entrata e di uscita, come lo z-score di una particolare serie storica. Lo stesso z-score ha un’implicita finestra di rollback. Come è evidente il numero di parametri può essere piuttosto grande.

Oltre ai parametri ci sono numerosi strumenti per valutare le prestazioni di un modello statistico e la strategia di trading basata su di esso. Si sono definiti concetti come l’Hit Rate e la Matrice di Confusione. Inoltre ci sono diverse misure statistiche come il Mean Squared Error (MSE). Si tratta di misure di rendimento che sono ottimizzate a livello di modello statistico, tramite parametri rilevanti per il loro dominio.
La strategia di trading effettiva viene valutata su diversi criteri, come il tasso di crescita annuale composto (CAGR) e il massimo drawdown massimo. E’ necessario variare i criteri di entrata e di uscita, così come le altre soglie che non sono direttamente correlate al modello statistico.

Questo motiva la domanda su relativa a quale insieme di parametri ottimizzare e quando.
Nelle sezioni seguenti si descrive come ottimizzare sia parametri del modello statistico, nella fase iniziale di ricerca e sviluppo, sia i parametri associati alla strategia di trading utilizzando un sottostante modello statistico ottimizzato, su ciascuna delle rispettive misure delle prestazioni.

L’Ottimizzazione è Costosa

Con diversi parametri reali, l’ottimizzazione può diventare rapidamente costosa, dato che
ogni nuovo parametro aggiunge una dimensione spaziale. Se si considera l’esempio di una griglia di
ricerca
 (discussa nel dettagli di seguito) e avere un singolo parametro \(\alpha\), quindi si potrebbe desiderare di variare \(\alpha\) all’interno dell’insieme \big\{0.1,0.2,0.3,0.4,0.5\big\}. Questo richiede 5 simulazioni.

Se si considera un parametro aggiuntivo, che può variare nell’intervallo \big\{0.2,0.4,0.6,0.8,1\big\} allora si dovrà effettuare \(5^{2} = 25\) simulazioni. Aggiungendo un altro parametro con 5 possibili valore si arriva a \(5^{3} = 125\) simulazioni. Se ogni parametro avesse 10 diversi valori da testare separatamente, si avrebbero \(10^{3} = 1000\). Come si può vedere, lo spazio di ricerca dei parametri può rapidamente richiedere attività di simulazione estremamente costose.

È chiaro che esiste un compromesso tra lo svolgere un’esaustiva ricerca dei parametri e mantenere ragionevole il tempo totale di simulazione. Nonostante il parallelismo, comprese le CPU multi-core e le unità di elaborazione grafica (GPU), ha attenuato questo  problema, è necessario prestare molta attenzione quando si introducono nuovi parametri. La riduzione dei parametri è anche un problema di efficacia del modello, come descritto in seguito.

Overfitting

L’overfitting è il processo di ottimizzazione di un parametro, o set di parametri, rispetto a un particolare set di dati in modo tale che una specifica misura di performance (o misura dell’errore) sia massimizzata (o minimizzata), ma quando applicata a un set di dati invisibile, la stessa misura di performance degrata vertiginosamente. Il concetto è strettamente correlato al concetto del bias-variance dilemma.

Il dilemma del bias-variance riguarda il bilanciamento tra il bias e la varianza, dove il bias si riferisce alla differenza tra la stima di un parametro effettua dal modello e il vero valore del parametro nella “popolazione” reale, o assunzioni errate nel modello statistico, mentre la varianza si riferisce all’errore causato dalla sensibilità del modello a piccole fluttuazioni nel set di allenamento (nei dati in-sample).
In tutti i modelli statistici, si tenta contemporaneamente di ridurre al minimo sia l’errore di bias che l’errore di varianza al fine di migliorare l’accuratezza del modello. Tale situazione può portare a un overfitting dei modelli, in quanto l’errore di allenamento può essere sostanzialmente ridotto introducendo modelli con maggiore flessibilità (variazione). Tuttavia, tali modelli possono offrire prestazioni estremamente scarse su dati nuovi (non inclusi nel campione) dato che sono essenzialmente “adatti” ai dati in-sample.

Un esempio di modello con elevato bias e bassa varianza è quello della regressione lineare applicata a un set di dati non lineari. L’introduzione di nuovi punti non incide sull’inclinazione della regressione (supponendo che non siano troppo lontani dai restanti dati), ma poiché il problema è intrinsecamente non lineare, usando un modello lineare si verifica un errore sistematico nei risultati.

Un esempio di un modello con basso bias ed elevata varianza è quello di un spline polinomiale applicato a un set di dati non lineare. Il parametro del modello (il grado del polinomio) potrebbe essere regolato per adattarsi con precisione a tale modello (cioè basso bias sui dati in-sample), ma l’aggiunta di nuovi punti causa quasi certamente una modifica al grado di polinomio affinchè il modello possa adattarsi ai nuovi dati. Ciò causa inoltre un modello con un’elevata varianza sui dati in-sample. Un tale modello presenta una scarsa prevedibilità o capacità inferenziale su dati sample.

L’overfitting può anche manifestarsi sulla strategia di trading e non solo sul modello statistico.
Ad esempio, si può ottimizzare il Sharpe ratio modificando i parametri relativi alla soglia di entrata e uscita.

Nonostante questo approccio migliori la redditività del backtest (o minimizzare il rischio), molto probabilmente tale comportamento non può essere replicato quando la strategia è eseguita in live trading dato che tali ottimizzazioni sono state adattate al rumore nei dati storici.
Di seguito si evidenziano le principali tecniche usate per ridurre al minimo l’overfitting. Tuttavia è indispensabile essere consapevoli del fatto che l’overfitting è un pericolo sempre presente sia nel trading algoritmico che, più in generale, nell’analisi statistica.

Selezione del Modello

In questa sezione si descrive come ottimizzare il modello statistico che sottostà a una strategia di trading. Nel campo della statistica e del machine learning tale approccio è noto come selezione del modello.
In questo articolo non si vuole presentare una discussione esaustiva sulle varie tecniche di selezione dei modelli, ma si introduco solamente alcuni dei meccanismi di base, come Cross Validation e Grid Search, che funzionano bene per le strategie di trading.

Cross Validation

Il Cross Validation (o convalida incrociata) è una tecnica utilizzata per valutare come un modello statistico viene generalizzato a nuovi dati a cui non è stato esposto in precedenza. Tale tecnica viene solitamente utilizzata su modelli predittivi, come i già citati classificatori supervisionati utilizzati per prevedere il segno dei return dei giorni successivi ad una serie di prezzi patrimoniali. Fondamentalmente, l’obiettivo della convalida incrociata è di minimizzare l’errore sui dati di esempio senza produrre un modello “overfittato”.
In questo paragrafo si descrive il training/test split e la k-fold cross-validation, e si utilizza gli strumenti all’interno di Scikit-Learn per eseguire automaticamente queste procedure su modelli statistici che sono già stati sviluppati.

Trading/Test Split

L’esempio più semplice di cross validation è noto come trading/test split o convalida incrociata per 2 volte. Una volta assemblato un set di dati storici precedenti (ad esempio una serie temporale giornaliera di prezzi degli asset), viene suddiviso in due componenti. Il rapporto della divisione varia solitamente tra 0,5 e
0.8. In quest’ultimo caso ciò significa che l’80% dei dati viene utilizzato per il traning e il 20% viene utilizzato per i test. Tutte le statistiche di interesse, come il tasso di successo, la matrice di confusione o l’errore medio al quadrato sono calcolate sul set di test, che non è stato utilizzato all’interno del processo di training.
Per eseguire questo processo in Python tramite la libreria Scikit-Learn si può usare il metodo sklearncross _validation train_test_split. Di seguito si amplia quanto già descritto nel precedente articolo. In particolare, si modifica forecast.py e si crea un nuovo file chiamato train_test_split.py:

            #!/usr/bin/python
# -*- coding: utf-8 -*-
# train_test_split.py

import datetime
import sklearn

from sklearn.cross_validation import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.lda import LDA
from sklearn.metrics import confusion_matrix
from sklearn.qda import QDA
from sklearn.svm import LinearSVC, SVC
from forecast import create_lagged_series
        
Originariamente in forecast.py i dati sono stati suddivisi in base a una data specifica all’interno delle serie temporali:
            # forecast.py
..
# The test data is split into two parts: Before and after 1st Jan 2005.
start_test = datetime.datetime(2005,1,1)
# Create training and test sets
X_train = X[X.index < start_test] X_test = X[X.index >= start_test]
y_train = y[y.index < start_test] y_test = y[y.index >= start_test]
..
        
Nle file train_test_split.py questo codice è sostituito con il metodo train_test_split di Scikit-Learn . Per completezza, il metodo principale è implementato come segue:
            # train_test_split.py

if __name__ == "__main__":
   # Create a lagged series of the S&P500 US stock market index
   snpret = create_lagged_series(
          "^GSPC", datetime.datetime(2001,1,10),
          datetime.datetime(2005,12,31), lags=5
         )

   # Use the prior two days of returns as predictor
   # values, with direction as the response
   X = snpret[["Lag1","Lag2"]]
   y = snpret["Direction"]

   # Train/test split
   X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.8, random_state=42
   )

   # Create the (parametrised) models
   print("Hit Rates/Confusion Matrices:\n")
   models = [("LR", LogisticRegression()),
             ("LDA", LDA()),
             ("QDA", QDA()),
             ("LSVC", LinearSVC()),
             ("RSVM", SVC(
                    C=1000000.0, cache_size=200, class_weight=None,
                    coef0=0.0, degree=3, gamma=0.0001, kernel=’rbf’,
                    max_iter=-1, probability=False, random_state=None,
                    shrinking=True, tol=0.001, verbose=False)
             ),
            ("RF", RandomForestClassifier(
                   n_estimators=1000, criterion=’gini’,
                   max_depth=None, min_samples_split=2,
                   min_samples_leaf=1, max_features=’auto’,
                   bootstrap=True, oob_score=False, n_jobs=1,
                   random_state=None, verbose=0)
             )]

   # Iterate through the models
   for m in models:

       # Train each of the models on the training set
       m[1].fit(X_train, y_train)

       # Make an array of predictions on the test set
       pred = m[1].predict(X_test)

       # Output the hit-rate and the confusion matrix for each model
       print("%s:\n%0.3f" % (m[0], m[1].score(X_test, y_test)))
       print("%s\n" % confusion_matrix(pred, y_test))
        
Da notare che è stato scelto un set di training come 80% dei dati, lasciando solo il 20% per i dati di test. Inoltre è stato specificato un random_state per randomizzare il campionamento all’interno del set dei dati. Ciò significa che i dati non sono suddivisi sequenzialmente in ordine cronologico, ma vengono invece campionati casualmente. I risultati della cross validation sul modello sono i seguenti (probabilmente sarà leggermente diverso a causa della natura della procedura di fitting):
            Hit Rates/Confusion Matrices:

LR: 0.511
[[ 70	70]
 [ 419 441]]

LDA: 0.513
[[ 69	67]
 [420  444]]

QDA: 0.503
[[ 83	91]
 [406  420]]

LSVC: 0.513
[[ 69	67]
 [420  444]]

RSVM: 0.506
[[  8	13]
 [481  498]]

RF:
0.490
[[200 221]
 [289 290]]
        

Si può notare che i tassi di successo sono sostanzialmente inferiori a quelli rilevati nell’articolo precedentemente citato. Di conseguenza, è probabile che si possa concludere che la particolare scelta del rapporto allenamento / test porti a una visione eccessivamente ottimistica della capacità predittiva del classificatore.
Il passaggio successivo consiste nell’aumentare il numero di volte in cui viene eseguita una cross validation al fine di ridurre al minimo l’eventuale overfitting. Per questo useremo la convalida incrociata k-fold.

K-Fold Cross Validation

Piuttosto che suddividere il set di dati in un singolo set di training e un singolo set di test, si può utilizzare una validazione incrociata k-fold per partizionare in modo casuale il set in k sottocampioni di dimensioni uguali. Per ogni iterazione (del totale k), uno dei sottocampioni viene mantenuto come un set di test, mentre i restanti k-1 sottocampioni formano un set di traning. Un modello statistico viene quindi addestrato su ciascuna delle k-fold e le sue prestazioni vengono valutate sulla specifica serie di test k-esima.

Lo scopo di questo è di combinare i risultati di ciascun modello in un emsemble mediante la media dei risultati della previsione (o altro) per produrre una singola previsione. Il vantaggio principale dell’utilizzo della k-fold cross-validation è l’utilizzo di ogni predittore all’interno del set di dati originale sia per il training che per il test, almeno per una volta.

Questo motiva la particolare attenzione su su come scegliere k, che ora è un altro parametro! Generalmente, si usa k = 10 ma si può anche eseguire un’altra analisi per scegliere un valore ottimale di k.

Nel codice si usa il modulo cross_validation di Scikit-Learn per ottenere l’oggetto KFold relativo alla convalida incrociata k-fold. Si crea quindi un nuovo file chiamato k_fold_cross_val.py, che è una copia di train_test_split.py e modifica le importazioni aggiungendo la seguente riga:

            #!/usr/bin/python
# -*- coding: utf-8 -*- # k_fold_cross_val.py

import datetime

import pandas as pd
import sklearn
from sklearn import cross_validation
from sklearn.metrics import confusion_matrix
from sklearn.svm import SVC

from create_lagged_series import create_lagged_series
        

Si deve quindi modificare la funzione principale __main__ rimuovendo il metodo train_test_split
e sostituendolo con un’istanza di KFold. Sono necessari cinque parametri. Il primo è la lunghezza del set di dati, che in questo caso è parti a 1250 giorni. Il secondo valore è K che rappresenta il numero di folds, o sottoinsiemi, che in questo caso è 10. Il terzo valore è indices, impostato su False (quindi gli effettivi valori degli indici sono utilizzati per navigare sull’array durante iterazione. Il quarto e il quinto sono usati per randomizzare l’ordine dei campioni.

Come in forecast.py e train_test_split.py si acquisisce la serie temporale S&P500. Si crea quindi una serie di vettori per i predittori (X) e le risposte (y). Quindi si utilizza l’oggetto KFold e lo effettua iterazioni su di esso. Durante ogni iterazione si crea un set di training e e un set di testing per ciascuno dei vettori X e Y. Questi vengono quindi inseriti in una SMV radiale con parametri identici ai file sopra citatiò.
Infine vengono calcolati e restituiti l’Hit Rate e la Matrice di Confusione per ogni istanza di SVM.

            # k_fold_cross_val.py

if  name 	== " main ":
    # Create a lagged series of the S&P500 US stock market index
    snpret = create_lagged_series(
            "^GSPC", datetime.datetime(2001,1,10), datetime.datetime(2005,12,31), lags=5
           )

    # Use the prior two days of returns as predictor # values,  with  direction  as  the  response
    X = snpret[["Lag1","Lag2"]] y = snpret["Direction"]

    # Create a k-fold cross validation object
    kf = cross_validation.KFold(
             len(snpret), n_folds=10, indices=False, shuffle=True, random_state=42
          )

    # Use the kf object to create index arrays that
    #  state  which  elements  have  been  retained  for  training 
    #  and  which  elements  have  beenr  retained  for  testing
    #  for  each  k-element  iteration
    for train_index, test_index in kf: 
        X_train = X.ix[X.index[train_index]] 
        X_test = X.ix[X.index[test_index]] 
        y_train = y.ix[y.index[train_index]] 
        y_test = y.ix[y.index[test_index]]

       # In this instance only use the
       #  Radial  Support  Vector  Machine  (SVM) 
       print("Hit Rate/Confusion Matrix:") model = SVC(
            C=1000000.0, cache_size=200, class_weight=None,
            coef0=0.0, degree=3, gamma=0.0001, kernel=’rbf’,
            shrinking=True, tol=0.001, verbose=False
          )

       #  Train  the  model  on  the  retained  training  data
       model.fit(X_train, y_train)

       # Make an array of predictions on the test set
       pred = model.predict(X_test)

       #  Output  the  hit-rate  and  the  confusion  matrix  for  each  model
       print("%0.3f" % model.score(X_test, y_test))
       print("%s\n" % confusion_matrix(pred, y_test))
        

L’output del codice è il seguente:

            Hit Rate/Confusion Matrix:
0.528
[[11 10]
 [49 55]]

Hit Rate/Confusion Matrix:
0.400
[[ 2  5]
 [70 48]]

Hit Rate/Confusion Matrix:
0.528
[[ 8  8]
 [51 58]]

Hit Rate/Confusion Matrix:
0.536
[[ 6  3]
 [55 61]]

Hit Rate/Confusion Matrix:
0.512
[[ 7  5]
 [56 57]]

Hit Rate/Confusion Matrix:
0.480
[[11 11]
 [54 49]]

Hit Rate/Confusion Matrix:
0.608
[[12 13]
 [36 64]]

Hit Rate/Confusion Matrix:
0.440
[[ 8 17]
 [53 47]]

Hit Rate/Confusion Matrix:
0.560
[[10  9]
 [46 60]]

Hit Rate/Confusion Matrix:
0.528
[[ 9 11]
 [48 57]]
        

È chiaro che il tasso di successo e le matrici di confusione variano notevolmente tra i vari “folds”. Questo indicata la possibilità che il modello è soggetto ad overfitting su questo particolare set di dati. Per risolvere questa criticità si può usare un numero significativamente maggiore di dati, ad una frequenza più alta o per una maggiore durata.

Per utilizzare questo modello in una strategia di trading sarebbe necessario combinare ciascuno di questi classificatori individualmente addestrati (vale a dire ciascuno degli oggetti K) in un insieme medio e quindi utilizzare quel modello combinato per la classificazione all’interno della strategia.
Da notare che tecnicamente non è appropriato utilizzare semplici tecniche di convalida incrociata su dati ordinati (ad es. Serie temporali). Esistono meccanismi più sofisticati per analizzare l’autocorrelazione in questo modo, ma si è voluto evidenziare che questo approccio sono stati utilizzati per semplicità i dati delle serie temporali.

Grid Search

Finora è stato descritto come il k-fold cross-validation aiuta ad evitare l’overfitting nei dati eseguendo la convalida su ogni elemento del campione. Ora si vuole approfondire come ottimizzare gli iper-parametri di un particolare modello statistico. Tali parametri sono quelli non appresi direttamente dalla procedura di stima del modello. Ad esempio, C e γ per una SVM. Essenzialmente sono i parametri che si devono specificare quando si inizializza ogni modello statistico. Per questa procedura si può usare un approcio noto come grid search.

L’idea base consiste nel prendere una serie di parametri e valutare le prestazioni del modello statistico su ciascun elemento del parametro all’interno dell’intervallo. Per ottenere si può creare un oggetto ParameterGrid tramite Scikit-Learn. Tale oggetto produce una lista di dizionari Python dove ciascuno contiene una combinazione di parametri da inserire in un modello statistico.

Di seguito è riportato un frammento di esempio del codice che produce una griglia di parametri, per i parametri relativi a una SVM:

            >>> from sklearn.grid_search import ParameterGrid
>>> param_grid = {’C’: [1, 10, 100, 1000], ’gamma’: [0.001, 0.0001]}
>>> list(ParameterGrid(param_grid))
[{’C’: 1, ’gamma’: 0.001},
{’C’: 1, ’gamma’: 0.0001},
{’C’: 10, ’gamma’: 0.001},
{’C’: 10, ’gamma’: 0.0001},
{’C’: 100, ’gamma’: 0.001},
{’C’: 100, ’gamma’: 0.0001},
{’C’: 1000, ’gamma’: 0.001},
{’C’: 1000, ’gamma’: 0.0001}]
        

Ora che si ha uno strumento adatto per generare un ParameterGrid, è necessario inserirlo in un modello statistico per cercare iterativamente un ottimale punteggio di prestazione. In questo caso si cerca di massimizzare il tasso di successo del classificatore.

Il metodo GridSearchCV di Scikit-Learn consente di calcolare l’effettiva grid search. Infatti, non consente solo di calcolare una grid search standard ma consente allo stesso tempo di calcolare uno schema di convalida incrociata.

Ora si crea un nuovo file, grid_search.py, che utilizza ancora una volta il create_lagged_series.py e una SVM per eseguire una grid search iperparametrica cross-validate. Per ottenere questo si deve importare le corrette librerie:

            #!/usr/bin/python
# -*- coding: utf-8 -*-
# grid_search.py

import datetime
import sklearn
from sklearn import cross_validation
from sklearn.cross_validation import train_test_split
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.svm import SVC
from create_lagged_series import create_lagged_series
        

Come in precedenza per il k_fold_cross_val.py, si crea una serie ritardata e quindi utilizza come predittori i returns degli ultimi due giorni precedenti. Inizialmente si crea una suddivisione di training / test in modo tale che il 50% dei dati possono essere utilizzati per il traning e la cross-validation, mentre i dati rimanenti possono essere “tenuti fuori” per la valutazione.

Successivamente si crea la lista tuned_parameters, che contiene un dizionario dei valori che si vogliono testare per ogni singolo parametro. Questo comporta la creazione di un prodotto cartesiano delle liste di tutti i parametri, cioè un elenco di coppie di ogni possibile combinazione dei parametri. Dopo ever creato l’elenco dei parametri, questo viene passato alla classe GridSearchCV, insieme al tipo di classificatore a cui si è interessati (ovvero una SVM radiale), con un valore k = 10 per il k-fold cross-validation.

Infine, si forma il modello e si produce la miglior stima e i relativi punteggi di hit rate associato. In questo modo non solo si sono ottimizzati i parametri del modello tramite la validazione incrociata, ma si è anche ottimizzato gli iperparametri del modello tramite una grid search parametrizzata, tutto in una classe! Tale concisione del codice consente una significativa sperimentazione senza essere impantanati da un eccessivo “conflitto di dati”.

            if __name__ == "__main__":
   # Create a lagged series of the S&P500 US stock market index
   snpret = create_lagged_series(
     "^GSPC", 
     datetime.datetime(2001,1,10),
     datetime.datetime(2005,12,31), lags=5
   )
   
   # Use the prior two days of returns as predictor
   # values, with direction as the response
   X = snpret[["Lag1","Lag2"]]
   y = snpret["Direction"]
   
   # Train/test split
   X_train, X_test, y_train, y_test = train_test_split(
       X, y, test_size=0.5, random_state=42
   )

   # Set the parameters by cross-validation
   tuned_parameters = [
       {’kernel’: [’rbf’], ’gamma’: [1e-3, 1e-4], ’C’: [1, 10, 100, 1000]}
   ]

   # Perform the grid search on the tuned parameters
   model = GridSearchCV(SVC(C=1), tuned_parameters, cv=10)
   model.fit(X_train, y_train)

   print("Optimised parameters found on training set:")
   print(model.best_estimator_, "\n")
   print("Grid scores calculated on training set:")
   for params, mean_score, scores in model.grid_scores_:
       print("%0.3f for %r" % (mean_score, params))
        
L’output della procedura di grid search cross validation procedure è il seguente:
            Optimised parameters found on training set:
   SVC(C=1, cache_size=200, class_weight=None, coef0=0.0, degree=3, gamma=0.001,
       kernel=’rbf’, max_iter=-1, probability=False, random_state=None,
       shrinking=True, tol=0.001, verbose=False)

Grid scores calculated on training set:
 0.541 for {’kernel’: ’rbf’, ’C’: 1, ’gamma’: 0.001}
 0.541 for {’kernel’: ’rbf’, ’C’: 1, ’gamma’: 0.0001}
 0.541 for {’kernel’: ’rbf’, ’C’: 10, ’gamma’: 0.001}
 0.541 for {’kernel’: ’rbf’, ’C’: 10, ’gamma’: 0.0001}
 0.541 for {’kernel’: ’rbf’, ’C’: 100, ’gamma’: 0.001}
 0.541 for {’kernel’: ’rbf’, ’C’: 100, ’gamma’: 0.0001}
 0.538 for {’kernel’: ’rbf’, ’C’: 1000, ’gamma’: 0.001}
 0.541 for {’kernel’: ’rbf’, ’C’: 1000, ’gamma’: 0.0001}
        
Come possiamo vedere, γ = 0.001 e C = 1 fornisce il miglior Hit Rate, sul set di convalida, per questa particolare SVM radiale. Questo modello potrebbe ora costituire la base di una strategia di trading basata sulle previsioni, come abbiamo descritto nel precedente articolo.

Benvenuto su DataTrading!

Sono Gianluca, ingegnere software e data scientist. Sono appassionato di coding, finanza e trading. Leggi la mia storia.

Ho creato DataTrading per aiutare le altre persone ad utilizzare nuovi approcci e nuovi strumenti, ed applicarli correttamente al mondo del trading.

DataTrading vuole essere un punto di ritrovo per scambiare esperienze, opinioni ed idee.

SCRIVIMI SU TELEGRAM

Per informazioni, suggerimenti, collaborazioni...

Torna in alto
Scroll to Top