Nell’articolo precedente abbiamo introdotto i concetti alla base dell’analisi delle serie storiche dei dati azionari. In questo articolo descriviamo come ottenere ed elaborare di dati dei mercati finanziari di Stooq. Stooq è un fornitori di dati storici gratuiti per i principali mercati mondiali.
Stooq è un sito web polacco che è stato parzialmente tradotto in inglese. Al momento in cui scrivo, Stooq offre dati OHLCV su 21.332 titoli ed ETF globali, 1980 coppie di valute e 132 criptovalute. Offrono anche dati su indici globali, materie prime e obbligazioni. Proprio come Yahoo, tutti i dati offerti sono accessibili tramite un’interfaccia web e i dati OHLCV possono essere scaricati in formato CSV. Non esiste un’API per Stooq. Per le azioni quotate sulle borse statunitensi è anche possibile ottenere alcuni dati fondamentali come il rapporto prezzo/utili e valore di mercato. Purtroppo i dati fondamentali non sono disponibili per il download degli storici. Puoi cercare un ticker e scaricare tutti i dati attuali ad esso relativi tramite la pagina dei simboli oppure puoi accedere ai dati attuali e storici in qesta pagina .
Una nota sulla nomenclatura del ticker
Puoi trovare o confermare un ticker di borsa utilizzando la barra di ricerca fornita nella parte superiore della pagina. Di seguito alcune delle specifiche nomenclature adottare da Stooq:
- Gli indici sono preceduti da ^ es. ^DJI (Dow Jones Industrial), ^UK100 (FTSE100)
- Le azioni statunitensi hanno il suffisso .US, ad esempio AAPL.US, MSFT.US, TSLA.US
- Le criptovalute hanno il suffisso .V, ad esempio BTC.V (BitCoin)
- Le azioni del Regno Unito hanno il suffisso .UK, ad esempio AV.UK (Aviva)
- Il prezzo/utile ha il suffisso _PE.US, ad esempio AAPL_PE.US
Dati storici in Stooq
Stooq offre dati storici giornalieri, orari e a 5 minuti su indici, ETF, azioni, obbligazioni, forex e criptovalute. Per ottenere i dati è necessario scegliere la regione e poi il timeframe. Possiamo scaricare gli ETF e le azioni per una specifica area geografica, mentre i dati su criptovalute, forex, indici e obbligazioni sono disponibili all’interno della regione denominata mondo. Dopo aver selezionato il set di dati preferito dobbiamo premere sui collegamenti nella colonna ASCII, completare il CAPTCHA e confermare il download. Riceviamo un file zip contenente i dati nel timeframe selezionato. In questo tutorial usiamo i dati giornalieri dell’area geografica degli Stati Uniti.
Una volta decompresso, la dimensione del file varierà a seconda della regione e deltimeframe. I dati storici giornalieri per alcune azioni statunitensi possono risalire a più di 30 anni fa e il file decompresso occupa più di 1,4 Gb di spazio, quindi dobbiamo assicurarci di avere abbastanza spazio disponibile sul disco fisso. Stooq fornisce i dati orari degli ultimi 1400 punti dati disponibili, il che equivale a circa 9 mesi a seconda del titolo azionario. I dati con timeframe a 5 minuti sono disponibili al massimo fino agli ultimi 2000 punti dati che equivalgono a circa 1 mese.
Stooq suddivide i dati di ciascuna regione a livello di borsa, quindi divide le azioni e gli ETF. Per gli exchange con un elevato numero di stock i file sono ulteriormente suddivisi per consentire un massimo di 2000 stock per directory. Questo rende l’accesso alle informazioni più impegnativo, tuttavia il sito Web di Stooq fornisce informazioni sulla struttura della directory che si vuole scaricare, come mostrato nella figura seguente.
Accesso a un singolo titolo
Dopo aver scaricato e decompresso il file da Stooq, iniziamo aggiungendo le importazioni alle librerie necessarie. Per cominciare dobbiamo importare la libreria Pandas di Python.
import pandas as pd
Dobbiamo ora familiarizzare con la posizione dei dati scaricati nel disco fisso, inserendo il percorso della directory in Pandas. La funzione read_csv()
di Pandas è incredibilmente versatile. Possiamo leggere i file .csv e .txt direttamente in un DataFrame per ulteriori analisi. Possiamo definire gran parte della struttura del DataFrame all’interno di questa funzione. È possibile selezionare una riga per le intestazioni delle colonne e una colonna da utilizzare come indice. Si può saltare righe o piè di pagina, limitare il numero di righe da leggere, e anche dedurre date e orari. C’è anche la possibilità di passare un dizionario di nomi delle colonne con valori che sono funzioni da applicare alle colonne. Maggiori informazioni sono disponibile nella documentazione ufficiale.
Per cominciare, leggiamo semplicemente i dati in un DataFrame e effettuiamo una post-elaborazione dopo l’acquisizione. In questo caso esaminiamo i dati forniti per AAPL. Questi dati dovrebbero trovarsi nel percorso .../data/daily/us/nasdaq stocks/1/aapl.us.txt
. Una volta individuato il file, tutto ciò che dobbiamo fare è passarlo alla funzione read_csv()
. Richiamando il metodo head()
di Pandas possiamo visualizzare il DataFrame.
stooq_aapl = pd.read_csv("cartella/al/download/data/daily/us/nasdaq stocks/1/aapl.us.txt")
stooq_aapl.head()
Ora abbiamo i nostri dati OHLCV in un DataFrame, ma dobbiamo fare delle elaborazioni per portarli in uno stato utilizzabile. Se eseguiamo stooq_aapl.dtypes
possiamo vedere il tipo di dati per ciascuna delle colonne del dataframe. Notiamo che la data è memorizzata come numero intero. Per poter eseguire qualsiasi tipo analisi delle serie temporali, dobbiamo convertire la colonna “Date” in un oggetto datetime. Per convertirlo possiamo usare pd.to_datetime()
. Tuttavia, questo metodo prevede una stringa come input, quindi dobbiamo prima eseguire il cast di un numero intero in una stringa tramite il metodo astype()
. Possiamo quindi usare la formattazione strftime per creare l’oggetto datetime. Ora possiamo usare la colonna della data come indice. Abbiamo anche alcune colonne che non ci servono e le etichette o le intestazioni delle colonne potrebbero essere più leggibili. Il codice seguente apporta le modifiche necessarie.
# Cancella le colonne non necessarie
stooq_aapl = stooq_aapl.drop(['', '', '', ''], axis=1)
# Rinomina le intestazione delle colonne
stooq_aapl.columns = ["date","open", "high", "low", "close", "volume"]
# Converte gli interi in un oggetto datetime
stooq_aapl["date"] = pd.to_datetime(stooq_aapl['date'].astype(str), format = '%Y%m%d')
# Imposta la colonna Date come indice
stooq_aapl = stooq_aapl.set_index('date')
Il DataFrame finale ha il seguente aspetto ed è pronto per ulteriori analisi.
Una nota sul prezzo di chiusura
Sottolineiamo che il prezzo di chiusura fornito da Stooq è in realtà il prezzo di chiusura aggiustato. Questo può essere verificato tracciando il grafico del prezzo di chiusura in un periodo di tempo che include uno split azionario. Nel caso di Apple, il 28 agosto 2020 si è verificato un frazionamento azionario 4 a 1. In questo caso il prezzo di chiusura dovrebbe scendere drasticamente durante la notte causando la comparsa di una linea retta quasi verticale sul grafico delle serie temporali.
stooq_aapl.plot(y="close")
Nella grafico seguente possiamo vedere che non ci sono discese drastiche in corrispondenza dello split. Questo indica che il prezzo di chiusura è stato effettivamente rettificato. Uno dei problemi nell’uso di fornitori di dati gratuiti è spesso poter determinare se sono stati effettuati aggiustamenti al prezzo di chiusura e in quali modalità.
Accedere ai primi dieci dell’S&P500
Abbiamo visto come acquisire ed elaborare i dati di un singolo titolo. Possiamo anche accedere ai dati di più titoli e analizzarli tutti insieme. La struttura del download di Stooq rende questo compito più complicato. Conoscere l’area geografica e l’exchange dove si trova un titolo non ci garantisce in quale sottocartella si troverà. Nel caso di AAPL si trovava nella cartella us/nasdaq stocks/1/
. Questo significa che dobbiamo sprecare del tempo per cercare un ticker all’interno di tutte le sottocartelle. Fortunatamente Python include il pacchetto glob, un’espansione del modello di percorso in stile Unix. Glob permette di cercare in modo ricorsivo un determinato file nelle sottodirectory di un determinato percorso.
Per dimostrarlo, creiamo un DataFrame di prezzi di chiusura per i primi dieci componenti dell’S&P500. Creiamo un dizionario di DataFrame dove le chiavi sono i simboli e i valori sono i DataFrame contenenti i dati storici OHLCV. Inoltre per ciascuno dei DataFrame creaiamo un MultiIndex con la data e il ticker. In questo modo possiamo concatenarli insieme e disimpilarli per creare un DataFrame finale le cui righe sono indicizzate per date e le colonne sono indicizzate dai ticker scelti. Iniziamo.
Usiamo le tre librerie Glob, OS e Pandas. OS e Glob fanno parte della libreria standard di Python 3, quindi aggiungiamo le importazioni ai rispettivi moduli separando con una riga vuota l’importazione di Pandas. Questo aiuta a distinguere tra importazioni standard e le importazione di librerie di terze parti. E’ una buona pratica di programmazione.
import glob
import os
import pandas as pd
Definiamo ora i nomi dei ticker dei primi dieci componenti dell’S&P500. In pratica, potrebbe essere qualsiasi raggruppamento di titoli che volgiamo analizzare, purché siano tutti contenuti nella regione degli Stati Uniti del download di Stooq. Ora creiamo una tupla contenente gli specific ticker. Usiamo una tupla perchè vogliamo creare un dizionario di DataFrames, una tupla è immutabile quindi garantisce che l’ordine dei ticker non cambierà. Sebbene sia vero che Python 3.7 fornisce dizionari che mantengono il loro ordine, questo comportamento non è documentato e potrebbe non essere garantito. Un dizionario è una mappatura di coppie di chiave-valori, in quanto tale non ha un ordine. L’uso di una tupla assicurerà di mantenere l’ordine dei nostri ticker all’interno del dizionario.
# Primi 10 ticker dell'S&P 500
sp_10 = ('AAPL.US', 'MSFT.US', 'AMZN.US', 'GOOGL.US', 'GOOG.US', 'TSLA.US', 'NVDA.US', 'BRK-B.US', 'FB.US', 'UNH.US')
Successivamente creiamo una lista scorrendo ciascuno dei ticker nella tupla e richiamando la funzione glob.glob()
con os.path.join()
. In questo modo generiamo una lista di stringhe che rappresentano il percorso della directory di ciascun file di dati. Infine. Dato che glob restituisce una lista, in realtà otteniamo una lista di liste, con una singola stringa in ogni sottolista. Appiattiamo la lsita di liste in un’unica lista di stringhe in modo da poter creare il dizionario di DataFrame.
# Uso glob per trovare il file dei dati di ogni ticker
path = "/path/to/your/Downloads/data/daily/us/**/"
ohlcv_data = [glob.glob(os.path.join(path, ticker + ".txt"), recursive=True) for ticker in sp_10]
# Appiattimento della lista di liste di glob list
flat_ohlcv = [item for sublist in ohlcv_data for item in sublist]
Ora che abbiamo ottenuto tutti percorsi dei file, possiamo passarli alla funzione read_csv()
di Pandas come abbiamo fatto in precedenza. Questa volta usiamo l’argomento con parola chiave index_col
per impostare la colonna della data come indice. Richiamiamo la funzione all’interno di una comprensione del dizionario ed enumeriamo i ticker della tupla costituente la top ten dell’S&P per ottenere le chiavi del dizionario. I valori corrispondono ai DataFrames.
# Crea un dizionario di dataframes con la data come indice
stooq_data = {name: pd.read_csv(flat_ohlcv[i], index_col="") for i, name in enumerate(sp_10s)}
A questo punto possiamo creare un MultiIndex con indici un oggetto datetime e un ticker. Questo ci consentirà di concatenare tutti i DataFrame e separare i dati creando un DataFrame finale contenente la data e il prezzo di chiusura per i primi dieci componenti dell’S&P500. Per raggiungere questo obiettivo, rimuoveremo tutte le colonne indesiderate, convertiremo il numero intero della data in un oggetto datetime e imposteremo le colonne MultiIndex.
for k in stooq_data.keys():
# Modifica formato data
stooq_data[k].index = pd.to_datetime(stooq_data[k].index.astype(str), format="%Y-%m-%d")
# Imposta MultiIndex
stooq_data[k].set_index([stooq_data[k].index, ""], inplace=True)
# Elimita tutte le colonne ad eccezione della close
stooq_data[k].drop(["", "", "", "", "", "", ""], axis=1, inplace=True)
Possiamo concatenare i DataFrame tramite il metodo .items()
usando le parole chiavi join="outer"
e sort="False"
per non effettuare l’ordinamento in modo da preservare l’ordine iniziale. I valori di entrambe le chiavi sono i parametri predefiniti per le parole chiave, ma li specifichiamo per rendere il codice maggiormente comprensibile.
result = pd.concat([v for k, v in stooq_data.items()], join="outer", sort=False)
Infine separiamo il Dataframe MultiIndex per generare una colonna con il prezzo di chiusura di tutti i ticker. Usiamo il metodo unstack()
che ordina i dati in ordine alfabetico in base alle loro etichette. Quindi i ticker non saranno più ordinati per capitalizzazione di mercato. Per riordinare le colonne possiamo creare un MultiIndex dalla tupla originale della top ten S&P.
final_df = result.unstack()
mindex_tup = [("", ticker) for ticker in sp_10]
mindex_cols = pd.MultiIndex.from_tuples(mindex_tup, names=['Price', 'Ticker'])
stooq_sp10_close = pd.DataFrame(final_df, columns=mindex_cols)
Usando il comando Pandas pd.DataFrame.tail()
il DataFrame finale appare come segue
Usare una libreria per importare i dati di Stooq
Con la libreria Pandas-DataReader di Python possiamo accedere ai dati Stooq. Sebbene questo metodo sia molto più semplice di quelli delineati sopra, al momento della stesura era possibile accedere solo a cinque anni di dati storici tramite la libreria Data-Reader. Diamo un’occhiata a un esempio.
import pandas_datareader.data as web
stooq_aapl = web.DataReader('AAPL', 'stooq')
stooq_aapl.iloc[[0,-1]]
Importiamo la libreria Data-Reader come nei tutorial precedenti, creiamo un DataFrame per i dati AAPL e quindi utilizziamo il comando df.iloc[]
di Pandas per esaminare la prima e l’ultima riga. Come puoi vedere, la prima data disponibile è di aprile 2017, cinque anni dal momento in cui scrivo.
Dati attuali di Stooq
Stooq fornisce anche istantanee trasversali di un punto nel tempo del loro database. Assume la forma di CSV scaricabile per i dati giornalieri di oltre 12.000 titoli, indici e valute globali. Per i dati orari e 5 minuti offrono informazioni sui prezzi per 66 coppie di valute e 56 indici. Per accedere ai dati correnti o ai dati di una specifica data dobbiamo selezionare la data e quindi specificare le diverse combinazioni di dati giornalieri, orari o di 5 minuti.
Riepilogo
In questo articolo abbiamo descritto come ottenere ed elaborare di dati dei mercati finanziari di Stooq. Abbiamo esaminato i dati disponibili, come scaricarli e rimodellarli in base alle nostre esigenze. Esiste un’ampia offerta di dati disponibili per il download con diversi timeframe. Non esiste alcuna API e i file di dati, una volta decompressi, occupano una grande quantità di spazio. Il prezzo di chiusura fornito è stato già aggiustato e, per quanto ne sappiamo, non esistono dati separati non aggiustati. Ci sono anche alcune differenze nella nomenclatura dei ticker rispetto alle norme del settore. Se stiamo semplicemente cercando dati per iniziare i nostri esperimenti, Stooq offre una vasta cronologia di diversi tipi di dati che soddisfa la maggior parte delle esigenze. Nei prossimi articoli descriviamo altri fornitori di dati, come AlphaVantage e Tiingo.