In questo articolo descriviamo Come effettuare lo scraping dal web in un database Sqlite3 dei dati degli ETF per il backtest di una strategia mean-reverting. L’articolo fa parte della miniserie “Backtest di una strategia di mean reverting con gli ETF”.
Gli articoli che fanno parte di questa serie sono:
- Backtest ETF: Web scraping e Database Sqlite3
- Backtest ETF: Creazione di coppie di Ticker
- Backtest ETF: Mean-reverting con Python
- Backtest ETF: Strategia di Trading con lo Z-score
- Backtest ETF: Pair trading con Python
Usiamo SQLite perché è semplice da installare e facile da configurare e installare. Per prima cosa dobbiamo visitare la pagina di download di SQLite e scaricare i binari precompilati dalla sezione Windows.
In dettaglio abbiamo bisogno di:
- Scaricare i file compressi sqlite-shell-win32-*.zip e sqlite-dll-win32-*.zip
- Creare una cartella C:\>sqlite e decomprimere al suo interno i due file zippati che fornisce i file sqlite3.def, sqlite3.dll e sqlite3.exe.
- Aggiungere C:\>sqlite nella variabile d’ambiente PATH, aprire il prompt dei comandi e scrivire il comando sqlite3. Otteniamo un risultato come il seguente
C:\>;sqlite3
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
Successivamente dobbiamo creare il database con cui lavoreremo. Dobbiamo trovare ed eseguire il file sqlitebrowser.exe. Questo apre la GUI da usare per creare il database. È abbastanza autoesplicativo e l’opzione “crea database” si trova nell’angolo in alto a sinistra della GUI.
Una volta che SQLite è installato e abbiamo creato un database, possiamo iniziare a scrivere lo script python per lo scraping dei dati e caricarli nel database. Possiamo usare il sito www.etf.com per raccogliere le informazioni relative agli ETF.
Il sito contiene tutti i dati di cui abbiamo bisogno. Ogni pagina che riteniamo pertinente può essere analizzata ed acquisita semplicemente copiando e incollando l’URL della pagina nel nostro script Python. Abbiamo riportato gli indirizzi di molte pagine del sito, quindi è sufficiente copiare e incollare il seguente codice:
import pandas as pd
import sqlite3 as db
import requests
# creare una lista vuota per archiviare i dati prelevati dal web
frames = []
# creare una stringa di pagine web che inseriremo nel parser html
s = '''
https://www.etf.com/channels/bond-etfs
https://www.etf.com/channels/mlp-etfs
https://www.etf.com/channels/silver-etfs
https://www.etf.com/channels/china-etfs
https://www.etf.com/channels/muni-etfs
https://www.etf.com/channels/us-broad-market-bond-etfs
https://www.etf.com/channels/dividend-etfs
https://www.etf.com/channels/natural-gas-etfs
https://www.etf.com/channels/global-bond-etfs
https://www.etf.com/channels/oil-etfs
https://www.etf.com/channels/treasury-etfs
https://www.etf.com/channels/gold-etfs
https://www.etf.com/channels/reit-etfs
https://www.etf.com/channels/high-dividend-yield-etfs
https://www.etf.com/channels/japan-etfs
https://www.etf.com/channels/smart-beta-etfs
https://www.etf.com/etf-lists/alternatives-etfs
https://www.etf.com/etf-lists/asset-allocation-etfs
https://www.etf.com/etf-lists/currency-etfs
https://www.etf.com/etf-lists/fixed-income-etfs
https://www.etf.com/channels/alpha-seeking-etfs
https://www.etf.com/channels/basic-materials-etfs
https://www.etf.com/channels/consumer-cyclicals-etfs
https://www.etf.com/channels/consumer-non-cyclicals-etfs
https://www.etf.com/channels/energy-etfs
https://www.etf.com/channels/extended-market-etfs
https://www.etf.com/channels/financials-etfs
https://www.etf.com/channels/health-care-etfs
https://www.etf.com/channels/high-dividend-yield-etfs
https://www.etf.com/channels/industrials-etfs
https://www.etf.com/channels/real-estate-etfs
https://www.etf.com/channels/small-cap-etfs
https://www.etf.com/channels/technology-etfs
https://www.etf.com/channels/telecommunications-etfs
https://www.etf.com/channels/theme-etfs
https://www.etf.com/channels/total-market-etfs
https://www.etf.com/channels/utilities-etfs
https://www.etf.com/channels/asia-pacific-etfs
https://www.etf.com/channels/developed-markets-etfs
https://www.etf.com/channels/emerging-markets-etfs
https://www.etf.com/channels/europe-etfs
https://www.etf.com/channels/global-etfs
https://www.etf.com/channels/global-ex-us-etfs
https://www.etf.com/channels/latin-america-etfs
https://www.etf.com/channels/middle-east-and-africa-etfs
'''
# divide gli URL in una stringa e li inserisce nel parser html di pandas
# per creare un dataframe delle informazioni raccolte
for i in s.split():
print("Scraping data from {}.".format(i))
df = pd.read_html(requests.get(i,headers={'User-agent': 'Mozilla/5.0'}).text)
# df contiene più DataFrame.
# l'indice [5] è il DataFrame a cui siamo interessati per i dati raccolti hanno intestazioni
# leggermente diverse su pagine Web diverse, quindi reimpostiamo le intestazioni di colonna
# in modo che siano identiche per ogni DataFrame, questi nomi corrispondono anche alle
# colonne che imposteremo nel nostro database SQLite
df[5].columns = ['Fund Name','Ticker','Asset Class','Region','Geography','Category','Focus',
'Niche', 'Inverse','Leveraged','ETN','Underlying Index','Selection Criteria',
'Weighting Scheme','Active per SEC']
frames.append(df[5])
# crea un dataframe "master" che concatena insieme tutti i DataFrame pertinenti (indice 5).
masterFrame = pd.concat(frames)
# crea una connessione al database SQLite precedentemente creato
# usa il percorso e il nome che corrisponde al database locale
cnx = db.connect('C:\Users\DataTrading-info\sqlite_databases\etfs.db')
cur = cnx.cursor()
# rimuovere la tabella se esiste già e tutti i dati che contiene
cur.execute('DROP TABLE IF EXISTS etftable;')
# crea la tabella all'interno del database
sql = '''CREATE TABLE etftable ('Fund Name' TEXT, 'Ticker' TEXT, 'Asset Class' TEXT,
'Region' TEXT, 'Geography' TEXT, 'Category' TEXT, 'Focus' TEXT,
'Niche' TEXT, 'Inverse' TEXT, 'Leveraged' TEXT, 'ETN' TEXT,
'Underlying Index' TEXT, 'Selection Criteria' TEXT, 'Weighting Scheme' TEXT,
'Active per SEC' TEXT)'''
cur.execute(sql)
# aggiunge i dati
masterFrame.to_sql(name='etftable', con=cnx, if_exists = 'append', index=False)
cnx.close()
Se nel codice precedente abbiamo impostato correttamente il database, insieme al nome e al percorso, siamo in grado di eseguirlo e ottenere un database SQLite pieno di centinaia e centinaia di Ticker ETF insieme a circa 12 colonne di informazioni di supporto tra cui “indice sottostante”, “regione” e “focus” ETF .
Ecco come dovrebbe il contenuto del database:
Questo script si può dimostrare molto utile e ci permette di usare un po’ di magia SQL per fare richieste dallo script principale del backtest in Python per inserire i ticker ETF in base a criteri come “asset ETF sottostante” o regione geografica… in modo da ottenere i ticker ETF che hanno maggiori probabilità di mostrare un comportamento di cointegrazione a causa di dei razionali economici sottostanti, oppure testare il momentum di ogni singolo ETF, l’uno contro l’altro.
Nel prossimo articolo, descriviamo la vera logica del backtest.
Codice completo
In questo articolo abbiamo descritto come effettuare lo scraping dal web in un database Sqlite3 dei dati degli ETF. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/Backtest_Strategie