Creazione di un Database di Securities con MySQL e Python

Ora aver introdotto l’idea alla base di un securities master database, vediamo è ora come implementarne uno. Per questo faremo uso di due tecnologie open source: il database MySQL e il linguaggio di programmazione Python. Alla fine di questo articolo avrete un vero e proprio database master di titoli azionari con cui condurre ulteriori analisi alla ricerca di una strategia di trading quantitativo.

I vantaggi di un Securities Master Database

Prima di iniziare, ricapitoliamo i vantaggi che si ottengo grazie all’introduzione di un securities master database nel nostro sistema di trading quantitativo:

  • Velocità – con i dati azionari memorazzati su un rigido locale, qualsiasi applicazione di analisi dati (come pandas) può accedere rapidamente ai dati senza dover eseguire lente operazioni di input / output (I / O) attraverso un collegamento di rete latente.
  • Fonti Multiple: i securities master database consentono la memorizzazione diretta da più sorgenti dati per lo stesso ticker. Quindi possiamo aggiungere un codice personalizzato per la correzione degli errori e / o tracciare i dati che devono essere controllati manualmente.
  • Tempo di inattività – Se ci affidiamo a una connessione Internet per i nostri dati, nel caso il fornitore (per qualsiasi motivo) stia affrontando un  periodo di inattività, non sarà possibile effettuare ricerche. Un database locale, con un sistema di backup, è sempre disponibile.
  • Meta-dati: un securities master database permette di memorizzare metadati sulle informazioni del nostro ticker. Possiamo includere tabelle degli exchange, fornitori e simboli di corrispondenza, aiutandoci a minimizzare gli errori dalle sorgenti dati.
 Esistono molti altri motivi per archiviare i dati localmente (o almeno su un server remoto) anziché fare affidamento sulle connessioni API ad un fornitore di dati. Un securities master fornisce il modello su cui costruire l’intero archivio dati delle nostre applicazioni di trading algoritmico. Tuttavia, ai fini di questo articolo ci concentreremo sulla memorizzazione dei dati storici giornalieri.
 

MySQL per i Securities Master Database

Per costruire ed interagire con un securities master database si può utilizzare MySQL e Python/pandas. Non mi soffermerò sulle specifiche di installazione di ciascuno di questi strumenti, poiché la procedura di installazione è piuttosto specifica per ogni piattaforma. Tuttavia, ti indicherò alcune guide che ti saranno sicuramente di aiuto per installare il software.

Installare MySQL

Per installare MySQL, è necessario selezionare la piattaforma appropriata:

  • Windows – Per le informazioni sulla procedura di installazione  di MySQL su Microsoft Windows, si può consultare la documentazione di MySQL. Se vuoi scaricare i file binari disponibili per Windows, puoi consultare questa pagina.
  • Mac OSX: è possibile scaricare i file binari per Mac OSX nella pagina dei download di MySQL. In alternativa, puoi installare MySQL tramite homebrew.
  • Linux / UNIX: puoi scegliere se scaricare un file binario dalla tua distribuzione o compilare dai codici sorgente. Su un sistema Debian / Ubuntu puoi digitare sudo apt-get install mysql-server. Se si utilizza una distribuzione basata su RPM come Fedora o Cent OS, è possibile digitare yum install mysql-server.

Creare un nuovo database e utente

Ora che MySQL è installato sul tuo sistema, possiamo creare un nuovo database e un utente per interagire con esso. All’installazione ti verrà richiesta una password di root. Per accedere a MySQL dalla riga di comando, si può utilizzare il seguente comando e inserire la password:

            $ mysql -u root -p
        

Una volta effettuato l’accesso a MySQL, puoi creare un nuovo database chiamato securities_master e selezionarlo:

            mysql> CREATE DATABASE securities_master; 
mysql> USE securities_master;
        

I database documentali/NoSQL, sebbene non siano un nuovo concetto, negli ultimi anni hanno acquisito una notevole importanza grazie a loro utilizzo da parte dei giganti del web come Google, Facebook e Twitter. Differiscono sostanzialmente dai sistemi RDBMS in quanto non esiste alcun concetto di schemi di tabelle. Invece, ci sono collezioni e documenti, che sono le analogie più vicine, rispettivamente, alle tabelle e ai record. Esiste un’ampia tassonomia di archivi documentali, la cui discussione è ben al di fuori di questo articolo! Tuttavia, alcuni delle soluzioni più popolari sono MongoDBCassandra e CouchDB.

I database documentali, nelle applicazioni finanziarie, sono adatti principalmente ai dati fondamentali o ai metadati. I dati fondamentali per le attività finanziarie sono disponibili in molte forme, come azioni aziendali, dichiarazioni di guadagni, archivi SEC ecc. Pertanto, la natura senza schema dei DB NoSQL è particolarmente adatta. Tuttavia, i DB NoSQL non sono ben progettati per le serie temporali come i dati sui prezzi ad alta risoluzione e quindi non li prenderemo in considerazione per tale scopo.

Una volta creato un database è necessario aggiungere un nuovo utente per interagire con il database. Anche se è possibile utilizzare l’utente root, è considerato una cattiva pratica dal punto di vista della sicurezza, in quanto garantisce troppe autorizzazioni e può portare a un sistema compromesso. Su una macchina locale questo è per lo più irrilevante, ma in un ambiente di produzione remoto sarà certamente necessario creare un utente con autorizzazioni ridotte. In questo caso il nostro utente verrà chiamato sec_user. Ricordarsi di sostituire ‘password’ con una password sicura:

            mysql> CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'password'; 
mysql> GRANT ALL PRIVILEGES ON securities_master.* TO 'sec_user'@'localhost'; 
mysql> FLUSH PRIVILEGES;
        

Con le tre righe precedenti si crea e si autorizza l’utente ad usare il db ‘securities_master’ e si applica tali privilegi. D’ora in poi qualsiasi interazione che si verifica con il database si dovrà far uso dell’utente ‘sec_user’.

Progettare lo schema per i Securities Master Azionari

Dopo aver installato MySQL e configurato un utente con cui interagire con il nostro database. In questa fase siamo pronti a costruire le tabelle necessarie per memorizzare i nostri dati finanziari. Per un semplice e diretto securities master azionario sono sufficienti quattro tabelle:

  • Exchange – La tabella elenca gli exchange da cui vogliamo ottenere le informazioni sui prezzi delle azioni. In questo caso sarà quasi esclusivamente la Borsa di New York (NYSE) e la National Association of Securities Dealers Automated Quotations (NASDAQ).
  • DataVendor – questa tabella elenca le informazioni sui fornitori di dati dei prezzi storici. Useremo Yahoo Finance per trovare i nostri dati di fine giornata (EOD). Introducendo questa tabella, rendiamo semplice aggiungere altri fornitori, se necessario, come ad esempio Google Finance.
  • Symbol: la tabella dei simboli memorizza l’elenco dei simboli dei ticker e delle informazioni aziendali. In questo momento eviteremo problemi come classi di azioni differenti e nomi di simboli multipli. Tratteremo tali questioni in articoli successivi!
  • DailyPrice – Questa tabella memorizza le informazioni dei prezzo giornaliero per ogni security. Può diventare molto grande se vengono aggiunti molti titoli. Quindi è necessario ottimizzare le prestazioni.

MySQL è un database estremamente flessibile in quanto consente di personalizzare la modalità di archiviazione dei dati tramite vari tipi di tabelle.  Le più usate sono senza dubbio le MyISAM e InnoDB. Anche se non entrerò nei dettagli dei vari tipi di tabelle gestite da MySQL (ce ne sono molte!), si può dire che MyISAM è più utile per una rapida lettura (come l’interrogazione sulle grandi quantità di informazioni relative ai prezzi), ma non supporta le transazioni (necessarie per il rollback completo di un’operazione a più passaggi che può fallire durante l’elaborazione). InnoDB permette la gestione delle foreign key e della transazionalità, con le quali è possibile creare una base di dati relazionale e transazionale, ma sono più lente a causa delle funzionalità aggiuntive di cui dispongono.

InnoDB consente inoltre il blocco a livello di riga durante le operazioni di scrittura, mentre MyISAM blocca l’intera tabella durante la scrittura. Questo può avere problemi di prestazioni quando si scrivono molte informazioni su punti arbitrari nella tabella (come con le istruzioni UPDATE). Questo è un argomento molto vasto, quindi rimando la discussione per un’altro articolo.

Utilizzeremo InnoDB poiché è nativamente più sicuro per le transazioni e offre il blocco a livello di riga. Nel caso una tabella fosse lenta da leggere, possiamo in prima analisi creare degli indici e solo nel caso le prestazioni fossero ancora poco soddisfacenti si procederebbe alla modifica del tipo di tabella. Tutte le nostre tabelle utilizzeranno il set di caratteri UTF-8, poiché desideriamo supportare gli exchange internazionali. Puoi leggere ulteriori informazioni sulla codifica UTF-8 in questa pagina di Wikipedia.

Iniziamo con schema e l’istruzione CREATE TABLE del linguaggio SQL per creazione della tabella exchange. Questa tabella memorizza la sigla e il nome dello exchange (ad esempio NYSE – New York Stock Exchange) così come la posizione geografica. Prevede anche una valuta e una differenza di fuso orario da UTC. Per scopi interni memorizziamo anche una data di creazione e dell’ultimo aggiornamento. Infine, impostiamo la chiave dell’indice primario come un numero intero a incremento automatico (che è sufficiente per gestire i record 232):

            CREATE TABLE `exchange` (
  `id` int NOT NULL AUTO_INCREMENT,
  `abbrev` varchar(32) NOT NULL,
  `name` varchar(255) NOT NULL,
  `city` varchar(255) NULL,
  `country` varchar(255) NULL,
  `currency` varchar(64) NULL,
  `timezone_offset` time NULL,
  `created_date` datetime NOT NULL,
  `last_updated_date` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
        
Di seguito lo schema e l’istruzione CREATE TABLE di SQL per la tabelladata_vendor. Questa memorizza il nome, il sito web e l’email del fornitore dei dati. In caso di necessità potremmo aggiungere più informazioni, come l’API endpoint URL:
            CREATE TABLE `data_vendor` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  `website_url` varchar(255) NULL,
  `support_email` varchar(255) NULL,
  `created_date` datetime NOT NULL,
  `last_updated_date` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
        
Successivamente si passa allo schema e l’istruzione CREATE TABLE di SQL per la tabella symbol. Questa tabella contiene un link alla foreign key di un exchange (in questo articolo ci focalizziamo solamente sui strumenti tradati degli exchange), un simbolo di  ticker (ad esempio GOOG), il tipo di strumento (‘azione’ o ‘indice’), il nome del titolo azionario o dell’indici del mercato, il settore e la valuta di riferimento.
            CREATE TABLE `symbol` (
  `id` int NOT NULL AUTO_INCREMENT,
  `exchange_id` int NULL,
  `ticker` varchar(32) NOT NULL,
  `instrument` varchar(64) NOT NULL,
  `name` varchar(255) NULL,
  `sector` varchar(255) NULL,
  `currency` varchar(32) NULL,
  `created_date` datetime NOT NULL,
  `last_updated_date` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `index_exchange_id` (`exchange_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
        

Infine si riporta lo schema e l’istruzione CREATE TABLE di SQL per la tabella daily_price. In questa tabella vengono memorizzati i dati storici dei prezzi. Il nome della tabella ha il prefisso daily_ poiché potremmo voler creare dati con diverse risoluzioni temporali (come minuti o secondi) e quindi gestirli in tabelle separate, in caso successivamente si vuole implementare strategie con frequenze più elevate. La tabella contiene due chiavi esterne: una verso il fornitore di dati e l’altra verso un simbolo. In questo modo si identifica in modo univoco il dato e ci consente di memorizzare nella stessa tabella gli stessi dati di prezzo per più fornitori. Per i nostri scopi memorizziamo anche la data del prezzo (vale a dire il periodo giornaliero su cui i dati OHLC sono validi) e le date di creazione e di ‘ultima aggiornamento.

I campi rimanenti memorizzano i prezzi di apertura-massimo-minimo-chiusura ti-alti-bassi e il prezzo di chiusura aggiustato. Alcuni fornitori di dati calcola anche i dividendi e scissioni, e quindi memorizziamo il prezzo corretto nella colonna adj_close_price. Da notare che il tipo di dato corrisponde a decimal(19,4). Quando si tratta di dati finanziari è assolutamente necessario essere precisi. Se avessimo usato il tipo di dati float, avremmo riscontrato errori di arrotondamento dovuti alle modalità con le quali i dati float sono archiviati internamente. Il campo finale memorizza il volume di scambi giornalieri. Questo usa il tipo di dati bigint in modo da non troncare accidentalmente giorni di volumi estremamente elevati.

            CREATE TABLE `daily_price` (
  `id` int NOT NULL AUTO_INCREMENT,
  `data_vendor_id` int NOT NULL,
  `symbol_id` int NOT NULL,
  `price_date` datetime NOT NULL,
  `created_date` datetime NOT NULL,
  `last_updated_date` datetime NOT NULL,
  `open_price` decimal(19,4) NULL,
  `high_price` decimal(19,4) NULL,
  `low_price` decimal(19,4) NULL,
  `close_price` decimal(19,4) NULL,
  `adj_close_price` decimal(19,4) NULL,
  `volume` bigint NULL,
  PRIMARY KEY (`id`),
  KEY `index_data_vendor_id` (`data_vendor_id`),
  KEY `index_synbol_id` (`symbol_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
        

Inserendo tutti i precedenti comandi SQL nella riga di comando MySQL verranno create le quattro tabelle previste.

Usare Python/Pandas per l'interazione con i Securities Master

Per iniziare a popolare il nostro database è necessario installare Python e Panda.

Installare Python/Pandas

Il modo migliore per installare Python consiste nell’utilizzare lo strumento dell’ambiente virtuale virtualenv e il gestore di pacchetti pip. Per installare Python in questo modo, è necessario attenersi alla seguente procedura:
  • Windows: visita la pagina Download Python per scaricare una versione di Python. Raccomando di usare l’ultima versione stabile disponibile di Python3. Una volta installato Python, è necessario scaricare setuptools. I passaggi finali consistono nell’eseguire easy_install pip e pip install virtualenv nella shell dei comandi.
  • Mac OSX – Il modo migliore per installare Python su Mac è usare homebrew. Quindi puoi installare Python tramite brew install python. Quindi è necessario eseguire pip install virtualenv per installare virtualenv.
  • Linux / UNIX – Per le distribuzioni di tipo Debian / Ubuntu sudo apt-get install python3-pip python3-dev per installare pip e le librerie di sviluppo Python. Quindi eseguire pip install virtualenv per installare virtualenv a livello globale.

Una volta installato virtualenv, è possibile creare un nuovo ambiente virtuale Python in una directory separata e quindi installare pandas (comandi per un ambiente UNIX):

            $ cd ~
$ mkdir -p python-apps/trading
$ cd python-apps/trading
$ virtualenv .
$ source bin/activate
$ pip install pandas
        
Il passaggio finale è installare la libreria Python-MySQL. Sulle macchine Debian/Ubuntu bisogna eseguire i seguenti comandi:
            sudo apt-get install default-libmysqlclient-dev
pip install mysqlclient
        
Ora siamo pronti per iniziare a interagire con il nostro database MySQL tramite Python e Pandas.

Usare un Object-Relational Mapper

Quelli di voi che hanno un background tecnico e sono familiari con lo sviluppo e la gestione di database, si potranno chiedere se sia più ragionevole utilizzare un Object-Relational Mapper (ORM). Un ORM consente agli oggetti all’interno di un linguaggio di programmazione di essere mappati direttamente nelle tabelle nei database in modo tale che il codice del programma sia completamente inconsapevole del motore di archiviazione sottostante. Tali software non sono esenti da errori, ma sono comunque in grado di far risparmiare molto tempo. Tuttavia, il risparmio di tempo viene generalmente a discapito delle prestazioni.

Un ORM popolare per Python è SQLAlchemy. Permette di specificare lo schema del database all’interno di Python stesso e quindi genera automaticamente il codice CREATE TABLE. Poiché abbiamo scelto specificamente MySQL e sono interessato alle prestazioni, ho scelto di non utilizzare un ORM per questo articolo.

Ottenere i dati dei simboli listati

Iniziamo con il recuperare i simboli associati all’elenco di Standard & Poor’s dei 500 titoli a grande capitalizzazione, ad esempio S&P500. Naturalmente, questo è semplicemente un esempio. Se stai operando sul mercato italiano e desideri utilizzare gli indici domestici dell’Italia, puoi anche ottenere l’elenco delle società FTSE MIB quotate alla Borsa di Milano (LSE).

Inoltre Wikipedia elenca le componenti del S&P500. Analizzeremo questo sito web usando la libreria lxml di Python ed aggiungeremo direttamente il contenuto direttamente al database in MySQL. Innanzitutto assicurati che la libreria sia installata:

            pip install lxml
        

Il seguente codice utilizzerà la libreria lxml e aggiungerà i simboli direttamente al database MySQL creato in precedenza. Ricordarsi di sostituire “password” con la password scelta durante la creazione dell’utente del db:

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

import datetime
import lxml.html
import PyMySQL as mdb

from math import ceil


def obtain_parse_wiki_snp500():
    """
    Scarica e analizza l'elenco dei costituenti
    dell'S&P500 da Wikipedia utilizzando le librerie
    requests e libxml.

    Restituisce un elenco di tuple da aggiungere a al
    database MySQL.
    """

    # Memorizza l'ora corrente, per il record created_at
    now = datetime.datetime.utcnow()

    # Usa libxml per scaricare l'elenco delle società S&P500 e ottenere
    # la tabella dei simboli
    page = lxml.html
               .parse('http://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
    symbolslist = page.xpath('//table[1]/tr')[1:]

    # Ottenere le informazioni sui simboli per ogni riga nella tabella 
    # dei componenti S&P500
    symbols = []
    for symbol in symbolslist:
        tds = symbol.getchildren()
        sd = {'ticker': tds[0].getchildren()[0].text,
            'name': tds[1].getchildren()[0].text,
            'sector': tds[3].text}

        # Crea una tupla (per il formato DB) e la aggiunge alla lista
        symbols.append( (sd['ticker'], 'stock', sd['name'],
          sd['sector'], 'USD', now, now) )
    return symbols

def insert_snp500_symbols(symbols):
    """Inserimento dei simboli dell'S&P500 nel database MySQL."""

    # Connessione all'instanza di MySQL
    db_host = 'localhost'
    db_user = 'sec_user'
    db_pass = 'password'
    db_name = 'securities_master'
    con = mdb.connect(host=db_host, user=db_user, passwd=db_pass, db=db_name)

    # Creazione delle stringe per l'insert
    column_str = 
    'ticker, instrument, name, sector, currency, created_date, last_updated_date'
    insert_str = ("%s, " * 7)[:-2]
    final_str = "INSERT INTO symbol (%s) VALUES (%s)" % (column_str, insert_str)
    print(final_str, len(symbols))

    # Usando la connessione MySQL, si effettua un INSERT INTO per ogni simbolo
    with con:
        cur = con.cursor()
        # Questa riga evita MySQL MAX_PACKET_SIZE
        # Anche se ovviamente potrebbe essere impostato più grande!
        for i in range(0, int(ceil(len(symbols) / 100.0))):
            cur.executemany(final_str, symbols[i*100:(i+1)*100-1])

if __name__ == "__main__":
    symbols = obtain_parse_wiki_snp500()
    insert_snp500_symbols(symbols)
        

A questo punto tutti gli attuali 500 simboli che compongono l’indice S&P500 sono inseriti nel database. Il nostro prossimo obiettivo sarà quello di ottenere lo storico dei prezzi da diverse fonti e collegarli ai simboli appena salvati.

Recuperare i dati storici

Per ottenere i dati storici degli attuali titoli che compongono l’S&P500, dobbiamo prima interrogare il database per farci restituire l’elenco di tutti i simboli. Una volta ottenuto l’elenco dei simboli (insieme agli ID dei simboli), è possibile richiamare l’API di Yahoo Finance e scaricare lo storico dei prezzi da ciascun simbolo. Quindi possiamo inserire i dati nel database per ogni simboli ottenuto. Ecco il codice Python che effettua queste operazioni:

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

import datetime
import pymysql as mdb
from urllib.request import urlopen

# create una connessione ad un'instanza del database MySQL
db_host = 'localhost'
db_user = 'sec_user'
db_pass = 'password'
db_name = 'securities_master'
con = mdb.connect(db_host, db_user, db_pass, db_name)


def obtain_list_of_db_tickers():
    """Ottenere una lista di ticker dalla tabella Symbols del database."""
    with con:
        cur = con.cursor()
        cur.execute("SELECT id, ticker FROM symbol")
        data = cur.fetchall()
        return [(d[0], d[1]) for d in data]


def get_daily_historic_data_yahoo(ticker,
                                  start_date=(2000, 1, 1),
                                  end_date=datetime.date.today().timetuple()[0:3]):
    """
    Ricavare i dati da Yahoo Finance e restituisce una lista di tuple.

    ticker: simbolo di un ticker di Yahoo Finance, e.g. "GOOG" for Google, Inc.
    start_date: data iniziale nel formato (YYYY, M, D)
    end_date: data finale nel formato (YYYY, M, D)
    """

    # Construzione del URL di Yahoo con la corretta query di parametri integer
    # per le date di inizio e fine. Da notare che alcuni parametri sono base zero!
    yahoo_url = "http://ichart.finance.yahoo.com/table.csv?s=%s&a=%s&b=%s&c=%s&d=%s&e=%s&f=%s" % \
                (ticker, start_date[1] - 1, start_date[2], start_date[0], end_date[1] - 1, end_date[2], end_date[0])

    # Prova di connessione a Yahoo Finance e ottenere i dati
    # In caso di mancata ricezione si stampa un messaggio di errore.
    try:
        yf_data = urlopen(yahoo_url).readlines()[1:]  # Ignora l'header
        prices = []
        for y in yf_data:
            p = y.strip().split(',')
            prices.append((datetime.datetime.strptime(p[0], '%Y-%m-%d'),
                           p[1], p[2], p[3], p[4], p[5], p[6]))
    except Exception as e:
        print("Could not download Yahoo data: %s" % e)
    return prices


def insert_daily_data_into_db(data_vendor_id, symbol_id, daily_data):
    """
    Prende una lista di tuples di dati giornalieri e il inserisce nel 
    database MySQL. Si aggiunge un vendor ID e un symbol ID nei dati.

    daily_data: Lista di tuples di dati OHLC (con adj_close e volume)
    """

    # Ottenere l'ora attuale
    now = datetime.datetime.utcnow()

    # Creazione dei dati giornalieri con vendor ID e symbol ID
    daily_data = [(data_vendor_id, symbol_id, d[0], now, now,
                   d[1], d[2], d[3], d[4], d[5], d[6]) for d in daily_data]

    # Creazione delle stringhe di insert
    column_str = """data_vendor_id, symbol_id, price_date, created_date, 
          last_updated_date, open_price, high_price, low_price, 
          close_price, volume, adj_close_price"""
    insert_str = ("%s, " * 11)[:-2]
    final_str = "INSERT INTO daily_price (%s) VALUES (%s)" % (column_str, insert_str)

    # Uso della connessione di MySQL per eseguire un INSERT INTO per ogni simbolo
    with con:
        cur = con.cursor()
        cur.executemany(final_str, daily_data)


if __name__ == "__main__":
    # Ciclo su tutti i ticker e inserimento dei dati storici
    # giornalieri nel database
    tickers = obtain_list_of_db_tickers()
    for t in tickers:
        print("Adding data for %s" % t[1])
        yf_data = get_daily_historic_data_yahoo(t[1])
        insert_daily_data_into_db('1', t[0], yf_data)
        

Da notare che ci sono sicuramente molti per ottimizzare questo codice. Ad esempio si può utilizzare la libreria Python ScraPy per ottenere dei download ad elevata concorrenza, dato che ScraPy è basato sul framework ad eventi chiamato Twisted

Nel nostro codice ogni download viene eseguito in sequenza.

Interfaccia Python/Pandas per i dati dei prezzi

Ora che abbiamo scaricato lo storico dei prezzi per tutti i titoli che compongono l’S&P500, vogliamo poter accedere a questi dati tramite strutture logiche implementante in Python. La libreria pandas rende passaggio questo estremamente semplice. Ecco uno script per ottiene i dati OHLC del titolo  Google in un determinato periodo di tempo dal nostro database master dei titoli e restituisce il tail del dataset:

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

import pandas as pd
import pandas.io.sql as psql
import pymysql as mdb


# Connessione all'instanza di MySQL
db_host = 'localhost'
db_user = 'sec_user'
db_pass = 'password'
db_name = 'securities_master'
con = mdb.connect(db_host, db_user, db_pass, db_name)

# Selezione di tutti i dati storici di Google con il campo "adjusted close"
sql = """SELECT dp.price_date, dp.adj_close_price
         FROM symbol AS sym
         INNER JOIN daily_price AS dp
         ON dp.symbol_id = sym.id
         WHERE sym.ticker = 'GOOG'
         ORDER BY dp.price_date ASC;"""

# Creazione di un dataframe pandas dalla query SQL
goog = psql.frame_query(sql, con=con, index_col='price_date')

# Stampa della coda del dataframe
print(goog.tail())
        

L’output dello script è il seguente:

price_date              adj_close_price
2013-05-20            908.53
2013-05-21            906.97
2013-05-22            889.42
2013-05-23            882.79
2013-05-24            873.32

Ovviamente questo è solo un semplice script, ma mostra tutte le potenzialità di un securities master archiviato localmente. Con tale approccio è possibile testare in modo estremamente rapido alcune strategie, poiché l’I / O dal database sarà notevolmente più veloce rispetto a quello effettuato tramite una connessione Internet.

Il prossimo passo è quello di automatizzare la raccolta di dati in modo che ogni simbolo abbia i dati OHLC aggiornati dopo la chiusura di ogni giorno di negoziazione. Utilizzando un programma di pianificazione delle attività come Windows Task Scheduler o crontab, questo processo può essere programmato per essere eseguito in background. Ci porterà un passo avanti verso la creazione di un sistema di trading completamente automatizzato.

 

Per il codice completo riportato in questo articolo utilizzando il modulo di backtesting vettoriale VectorBacktest si può consultare il seguente repository di github:
https://github.com/datatrading-info/VectorBacktest

Scroll to Top