/ TECHNOLOGY

Get Historical Price Data from Polygon.io

Learn how to use the Polygon.io Python API to get historical price data for crypto, stocks, futures, and forex.

Prerequisites

Install Polygon API

The first thing we’ll want to do is activate our virtual environement and install the Polygon Python API REST client. If you don’t know how to create a virtual environment:

!pip install polygon-api-client

Add Imports

Import the polygon RESTClient and the local_settings file, which should contain your api_key.

from polygon import RESTClient 
from local_settings import polygon as settings

Inhert RESTClient and Add Retry Strategy

Here we inherit the functionality from Polygon’s RESTClient. We call super().__init__ to get initialize our class using our RESTClient’s __init__ giving us the ability to modify the _session attribute with an adapter.

#from datetime import date
from datetime import date, datetime
from typing import Any, Optional
import pandas as pd
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

markets = ['crypto', 'stocks', 'fx']

class MyRESTClient(RESTClient):
    def __init__(self, auth_key: str=settings['api_key'], timeout:int=5):
        super().__init__(auth_key)
        retry_strategy = Retry(total=10,
                               backoff_factor=10,
                               status_forcelist=[429, 500, 502, 503, 504])
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self._session.mount('https://', adapter)

Create Get Tickers Method

Let’s create a client from our new child class MyRESTClient and see what we need to use the reference tickers method.

client = MyRESTClient(settings['api_key'])
help(client.reference_tickers_v3)

After reviewing the help, we can now create our get_tickers method.

class MyRESTClient(RESTClient):
    def __init__(self, auth_key: str=settings['api_key'], timeout:int=5):
        super().__init__(auth_key)
        retry_strategy = Retry(total=10,
                               backoff_factor=10,
                               status_forcelist=[429, 500, 502, 503, 504])
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self._session.mount('https://', adapter)

    def get_tickers(self, market:str=None) -> pd.DataFrame:
        if not market in markets:
            raise Exception(f'Market must be one of {markets}.')

        resp = self.reference_tickers_v3(market=market)
        if hasattr(resp, 'results'):
            df = pd.DataFrame(resp.results)

            while hasattr(resp, 'next_url'):
                resp = self.reference_tickers_v3(next_url=resp.next_url)
                df = df.append(pd.DataFrame(resp.results))

            if market == 'crypto':
                # Only use USD pairings.
                df = df[df['currency_symbol'] == 'USD']
                df['name'] = df['base_currency_name']
                df = df[['ticker', 'name', 'market', 'active']]

            df = df.drop_duplicates(subset='ticker')
            return df
        return None
client = MyRESTClient(settings['api_key'])
df = client.get_tickers(market='crypto')
df
ticker name market active
0 X:1INCHUSD 1inch crypto True
1 X:AAVEUSD Aave crypto True
2 X:ACATUSD Alphacat crypto True
3 X:ACHUSD Alchemy Pay crypto True
4 X:ACTUSD Achain crypto True
... ... ... ... ...
16 X:ZECUSD Zcash crypto True
17 X:ZENUSD Horizen crypto True
18 X:ZILUSD Zilliqa crypto True
19 X:ZRXUSD 0x crypto True
20 X:ZSCUSD Zeusshield crypto True

302 rows × 4 columns

Create Get Minute Bars Method

Let’s do the same thing for the get minute bars method. We need to keep looping until we have all the data, making sure we only append data we haven’t seen before.

help(client.stocks_equities_aggregates)
class MyRESTClient(RESTClient):
    def __init__(self, auth_key: str=settings['api_key'], timeout:int=5):
        super().__init__(auth_key)
        retry_strategy = Retry(total=10,
                               backoff_factor=10,
                               status_forcelist=[429, 500, 502, 503, 504])
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self._session.mount('https://', adapter)

    def get_tickers(self, market:str=None) -> pd.DataFrame:
        if not market in markets:
            raise Exception(f'Market must be one of {markets}.')

        resp = self.reference_tickers_v3(market=market)
        if hasattr(resp, 'results'):
            df = pd.DataFrame(resp.results)

            while hasattr(resp, 'next_url'):
                resp = self.reference_tickers_v3(next_url=resp.next_url)
                df = df.append(pd.DataFrame(resp.results))

            if market == 'crypto':
                # Only use USD pairings.
                df = df[df['currency_symbol'] == 'USD']
                df['name'] = df['base_currency_name']
                df = df[['ticker', 'name', 'market', 'active']]

            df = df.drop_duplicates(subset='ticker')
            return df
        return None

    def get_bars(self, market:str=None, ticker:str=None, multiplier:int=1,
                 timespan:str='minute', from_:date=None, to:date=None) -> pd.DataFrame:

        if not market in markets:
            raise Exception(f'Market must be one of {markets}.')

        if ticker is None:
            raise Exception('Ticker must not be None.')

        from_ = from_ if from_ else date(2000,1,1)
        to = to if to else date.today()

        if market == 'crypto':
            resp = self.crypto_aggregates(ticker, multiplier, timespan,
                                          from_.strftime('%Y-%m-%d'), to.strftime('%Y-%m-%d'),
                                          limit=50000)
            df = pd.DataFrame(resp.results)
            last_minute = 0
            while resp.results[-1]['t'] > last_minute:
                last_minute = resp.results[-1]['t'] # Last minute in response
                last_minute_date = datetime.fromtimestamp(last_minute/1000).strftime('%Y-%m-%d')
                resp = self.crypto_aggregates(ticker, multiplier, timespan,
                                          last_minute_date, to.strftime('%Y-%m-%d'),
                                          limit=50000)
                new_bars = pd.DataFrame(resp.results)
                df = df.append(new_bars[new_bars['t'] > last_minute])
                
            df['date'] = pd.to_datetime(df['t'], unit='ms')
            df = df.rename(columns={'o':'open',
                                    'h':'high',
                                    'l':'low',
                                    'c':'close',
                                    'v':'volume',
                                    'vw':'vwap',
                                    'n':'transactions'})
            df = df[['date','open','high','low','close','volume']]

            return df
        return None
start = datetime(2021,1,1)
client = MyRESTClient(settings['api_key'])
df = client.get_bars(market='crypto', ticker='X:BTCUSD', from_=start)
df
date open high low close volume
0 2021-01-01 00:00:00 28939.00 29032.87 28914.03 29030.19 178.512438
1 2021-01-01 00:01:00 29026.97 29086.90 28950.18 29018.00 119.447233
2 2021-01-01 00:02:00 29079.56 29079.56 28970.45 29049.76 86.455629
3 2021-01-01 00:03:00 29037.66 29069.39 28970.58 29041.72 117.940777
4 2021-01-01 00:04:00 28988.00 29057.73 28976.96 29034.30 38.084008
... ... ... ... ... ... ...
25480 2021-10-18 16:42:00 61828.85 61872.26 61819.00 61854.20 31.117746
25481 2021-10-18 16:43:00 61858.94 61897.34 61841.10 61862.40 23.213774
25482 2021-10-18 16:44:00 61876.89 61904.25 61831.00 61872.50 35.189237
25483 2021-10-18 16:45:00 61872.70 61910.12 61783.08 61825.10 45.262836
25484 2021-10-18 16:46:00 61816.45 61828.13 61549.49 61600.30 94.754344

417165 rows × 6 columns

leo

Leo Smigel

Based in Pittsburgh, Analyzing Alpha is a blog by Leo Smigel exploring what works in the markets.