'HTTP 429 Error and very slow execution using APIs from financial modeling prep

I am trying to create a script in python using APIs from https://site.financialmodelingprep.com/ , but am running into an issue.

The main goal behind this script is to grab all the stocks within the Nasdaq using the function def nasdaq_api_call(url): and then grabbing their 1 year / 1 month price with the two functions def historic_stock_price_api_call_1year(URL): & def historic_stock_price_api_call_1month(url):

I then calculate the percentage change using the current price with function def current_stock_price(url):. Additionally, I loop through raw_data in the Main(): function which lets me grab the stock symbol for each stock in the Nasdaq and use that to find all the prices. I added time.sleep(2) to all the functions with loops since I kept getting an HTTP 429 error.

The issue:

The code seems to work for a few iterations but then shoots back an HTTP error again. I am asking two things:

  1. is there a way to help alleviate the server from my pulls where I would not get an HTTP 429 error and all the code will execute?
  2. I am not sure if I have a bottleneck anywhere, but when I run the code it runs super slow regardless of the time.sleep. Is there any optimization I can do to speed up the execution or anything I can add/remove to help speed it up?
Symbol = ATVI      || Company Name = Activision Blizzard                || 1 Year Change = -0.21
Symbol = ADBE      || Company Name = Adobe                              || 1 Year Change = -0.07
Symbol = ADP       || Company Name = ADP                                || 1 Year Change =  0.20
Symbol = ABNB      || Company Name = Airbnb                             || 1 Year Change = -0.09
Symbol = ALGN      || Company Name = Align                              || 1 Year Change = -0.16
Symbol = GOOGL     || Company Name = Alphabet (Class A)                 || 1 Year Change =  0.25
Symbol = GOOG      || Company Name = Alphabet (Class C)                 || 1 Year Change =  0.24
Symbol = AMZN      || Company Name = Amazon                             || 1 Year Change = -0.07
Symbol = AMD       || Company Name = AMD                                || 1 Year Change =  0.25
Traceback (most recent call last):
  File "C:\Users\leona\PycharmProjects\PythonMain\Training files\testing.py", line 144, in <module>
    one_year_ago_price = float(historic_stock_price_api_call_1year(historic_price_url))
  File "C:\Users\leona\PycharmProjects\PythonMain\Training files\testing.py", line 29, in historic_stock_price_api_call_1year
    response = urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))
  File "C:\Python39\lib\urllib\request.py", line 214, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Python39\lib\urllib\request.py", line 523, in open
    response = meth(req, response)
  File "C:\Python39\lib\urllib\request.py", line 632, in http_response
    response = self.parent.error(
  File "C:\Python39\lib\urllib\request.py", line 561, in error
    return self._call_chain(*args)
  File "C:\Python39\lib\urllib\request.py", line 494, in _call_chain
    result = func(*args)
  File "C:\Python39\lib\urllib\request.py", line 641, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 429: 

Process finished with exit code 1
# Libraries needed for functions
import ssl
import time
from urllib.request import urlopen
import certifi
import json
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta

# Dates for one year ago today and one month ago today
one_year_ago_list = (str(datetime.now() - relativedelta(years=1))[0:10]).split('-')
one_month_ago_list = (str(datetime.now() - relativedelta(months=1))[0:10]).split('-')
month_timestamp = datetime(int(one_month_ago_list[0]), int(one_month_ago_list[1]), int(one_month_ago_list[2]))
year_timestamp = datetime(int(one_year_ago_list[0]), int(one_year_ago_list[1]), int(one_year_ago_list[2]))
one_year = str(datetime.now() - relativedelta(years=1))[0:10]
one_month = str(datetime.now() - relativedelta(months=1))[0:10]
api_key = "insert here" # FIX ME insert API key from https://site.financialmodelingprep.com/


# Api call to grab list of NASDAQ stocks
def nasdaq_api_call(url):
    response = urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))
    data = response.read().decode("utf-8")
    return json.loads(data)


# Api call to grab the historic stock price of a stock
def historic_stock_price_api_call_1year(url):
    response = urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))
    data = response.read().decode("utf-8")
    raw_data = json.loads(data)
    # the below code skips to the second key in the api response dict which has the actual data
    raw_data = raw_data["historical"]
    # Looping through the historical data until we can find the EOD price for a year ago
    for i in raw_data:
        if i["date"] == one_year:
            return i["close"]
        elif datetime.strftime(year_timestamp, "%A") == 'Sunday':
            one_year_sunday = str(datetime.now() - relativedelta(years=1) - timedelta(days=1))[0:10]
            if i['date'] == one_year_sunday:
                return i['close']
            else:
                one_year_holiday = str(datetime.now() - relativedelta(years=1) - timedelta(days=2))[0:10]
                if i['date'] == one_year_holiday:
                    return i['close']
        elif datetime.strftime(year_timestamp, "%A") == 'Saturday':
            one_year_saturday = str(datetime.now() - relativedelta(years=1) + timedelta(days=1))[0:10]
            if i['date'] == one_year_saturday:
                return i['close']
            else:
                one_year_holiday = str(datetime.now() - relativedelta(years=1) + timedelta(days=2))[0:10]
                if i['date'] == one_year_holiday:
                    return i['close']
        else:
            continue
        time.sleep(2.0)


# API call to return current stock price
def current_stock_price(url):
    response = urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))
    data = response.read().decode("utf-8")
    raw_date = json.loads(data)
    return raw_date[0]["price"]


# API to call to return monthly stock price
def historic_stock_price_api_call_1month(url):
    response = urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))
    data = response.read().decode("utf-8")
    raw_data = json.loads(data)
    # the below code skips to the second key in the api response dict which has the actual data
    raw_data = raw_data["historical"]
    # Looping through the historical data until we can find the EOD price for a month ago
    for i in raw_data:
        if i["date"] == one_month:
            return i["close"]
        elif datetime.strftime(month_timestamp, "%A") == 'Sunday':
            one_month_sunday = str(datetime.now() - relativedelta(months=1) - timedelta(days=1))[0:10]
            if i['date'] == one_month_sunday:
                return i['close']
            else:
                one_month_holiday = str(datetime.now() - relativedelta(months=1) - timedelta(days=2))[0:10]
                if i['date'] == one_month_holiday:
                    return i['close']
        elif datetime.strftime(month_timestamp, "%A") == 'Saturday':
            one_month_saturday = str(datetime.now() - relativedelta(months=1) + timedelta(days=1))[0:10]
            if i['date'] == one_month_saturday:
                return i['close']
            else:
                one_month_holiday = str(datetime.now() - relativedelta(months=1) + timedelta(days=2))[0:10]
                if i['date'] == one_month_holiday:
                    return i['close']
        elif datetime.strftime(month_timestamp, "%A") == 'Monday' and i['date'] != one_month:
            one_month_holiday = str(datetime.now() - relativedelta(months=1) + timedelta(days=1))[0:10]
            if i['date'] == one_month_holiday:
                return i['close']
        elif datetime.strftime(month_timestamp, "%A") == 'Friday' and i['date'] != one_month:
            one_month_holiday = str(datetime.now() - relativedelta(months=1) - timedelta(days=1))[0:10]
            if i['date'] == one_month_holiday:
                return i['close']
        else:
            continue
        time.sleep(2.0)


def main():
    # API URL with my key
    nasdaq_url = "https://financialmodelingprep.com/api/v3/nasdaq_constituent?apikey="+api_key
    # Using the NASDAQ function and storing the results in the below variable
    nasdaq_raw_date = nasdaq_api_call(nasdaq_url)
    # Looping through the nasdaq_api_call and adding the symbol for each stock to the URL below so we can use it for the historic price API call
    for i in nasdaq_raw_date:
        # url that houses all listed stocks in teh index
        historic_price_url = "https://financialmodelingprep.com/api/v3/historical-price-full/" + i[
            'symbol'] + "?apikey="+api_key
        current_price_url = "https://financialmodelingprep.com/api/v3/quote-short/" + i[
            'symbol'] + "?apikey="+api_key
        one_year_ago_price = float(historic_stock_price_api_call_1year(historic_price_url))
        one_month_ago_price = float(historic_stock_price_api_call_1month(historic_price_url))
        current_price = float(current_stock_price(current_price_url))
        one_year_price_change = float((current_price - one_year_ago_price) / one_year_ago_price)
        one_month_price_change = float((current_price - one_month_ago_price) / one_month_ago_price)
        print(
            "Symbol = {:10s}|| Company Name = {:35s}|| 1 Year Change = {:5.2f} || 1 Month Change = {:5.2f}".format(
                i["symbol"], i["name"],
                one_year_price_change,
                one_month_price_change))
        time.sleep(2.0)


if __name__ == "__main__":
    main()


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source