{"id":7014,"date":"2024-03-14T14:22:19","date_gmt":"2024-03-14T21:22:19","guid":{"rendered":"https:\/\/jeremywhittaker.com\/?p=7014"},"modified":"2024-04-08T14:11:59","modified_gmt":"2024-04-08T21:11:59","slug":"python-and-yfinance-free-fundamental-data-for-algorithmic-trading","status":"publish","type":"post","link":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/","title":{"rendered":"Python and yfinance: Free Fundamental Data for Algorithmic Trading"},"content":{"rendered":"\n<p>Fundamental data offers a plethora of data points about a company&#8217;s financial health and market position. I want to share a streamlined approach to accessing and storing fundamental data for a wide array of stocks using <code>yfinance<\/code>, a powerful tool that offers free access to financial data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">This Python code leverages <code>yfinance<\/code> to download fundamental data for stocks and store it in an HDF5 file. This approach not only ensures quick access to a vast array of fundamental data but also organizes it in a structured, easily retrievable manner.<\/h4>\n\n\n\n<p>The code is structured into two main functions: <code>save_fundamental_data<\/code> and <code>download_and_save_symbols<\/code>. Here&#8217;s a breakdown of their functionality:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>save_fundamental_data<\/code><\/strong>: This function serves as the entry point. It checks for the existence of an HDF5 file that serves as our data repository. If the file doesn&#8217;t exist, it&#8217;s created during the first run. The function then identifies which symbols need their data downloaded and saved, distinguishing between those not yet present in the file and those requiring updates.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"210\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6-1024x210.png\" alt=\"\" class=\"wp-image-7017 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6-1024x210.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6-300x62.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6-768x158.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6-500x103.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-6.png 1170w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/210;\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>download_and_save_symbols<\/code><\/strong>: As the workhorse of our code, this function iterates through the list of symbols, fetching their fundamental data from <code>yfinance<\/code> and handling any special cases, such as columns that need renaming due to naming convention conflicts. It employs a retry logic to ensure reliability even in the face of temporary network issues or API limitations.<\/li>\n<\/ul>\n\n\n\n<p>The entire process is designed to be incremental, meaning it prioritizes adding new symbols to the HDF5 file before updating existing entries. This approach optimizes the use of network resources and processing time.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Hurdles<\/h1>\n\n\n\n<p>Throughout the development process, I encountered several interesting challenges, notably:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Naming Convention Conflicts<\/strong>: PyTables, the underlying library used for handling HDF5 files in Python, imposes strict naming conventions that caused issues with certain column names returned by <code>yfinance<\/code> (e.g., <code>52WeekChange<\/code>). To circumvent this, the code includes logic to rename problematic columns, ensuring compatibility with PyTables.<\/li>\n\n\n\n<li><strong>Serialization Issues<\/strong>: Some columns contain complex data types that need special handling before they can be stored in HDF5 format. The code serializes these columns, converting them into a format suitable for storage.<\/li>\n\n\n\n<li><strong>Retry Logic for Robustness<\/strong>: Network unreliability and API rate limiting can disrupt data download processes. Implementing a retry mechanism significantly improves the robustness of our data fetching routine, making our script more reliable.<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Functions to Create and Save Data<\/h1>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def save_fundamental_data(symbols=None):\n    \"\"\"\n    Incrementally save fundamental data for a list of stock symbols to an HDF file.\n    Prioritizes saving data for symbols not already present in the file before updating existing entries.\n\n    Args:\n        symbols (list, optional): List of stock symbols. Defaults to None, meaning it will fetch active assets.\n\n    Returns:\n        None\n    \"\"\"\n    hdf_file_path = '\/home\/shared\/algos\/data\/fundamental_data.h5'\n    existing_symbols = set()\n    download_failures = []\n\n    # Check if the HDF5 file exists before attempting to read existing symbols\n    if os.path.exists(hdf_file_path):\n        with pd.HDFStore(hdf_file_path, mode='r') as store:\n            existing_symbols = set(store.keys())\n            existing_symbols = {symbol.strip('\/') for symbol in existing_symbols}  # Remove leading slashes\n    else:\n        logging.info(\"HDF5 file does not exist. It will be created on the first write operation.\")\n\n    if symbols is None:\n        symbols = list(get_active_assets().keys())\n        symbols = [s.replace('.', '-') for s in symbols]\n\n    # Separate symbols into those that need to be added and those that need updating\n    symbols_to_add = [symbol for symbol in symbols if symbol not in existing_symbols]\n    symbols_to_update = [symbol for symbol in symbols if symbol in existing_symbols]\n\n    # Download and save data for symbols not already in the HDF5 file\n    download_and_save_symbols(symbols_to_add, hdf_file_path, download_failures, \"Adding new symbols\")\n\n    # Update data for symbols already in the HDF5 file\n    download_and_save_symbols(symbols_to_update, hdf_file_path, download_failures, \"Updating existing symbols\")\n\n    if download_failures:\n        logging.info(f\"Failed to download data for the following symbols: {', '.join(download_failures)}\")\n    logging.info(\"All fundamental data processing attempted.\")\n\n\ndef download_and_save_symbols(symbols, hdf_file_path, download_failures, description):\n    \"\"\"\n    Helper function to download and save fundamental data for a list of symbols.\n\n    Args:\n        symbols (list): List of symbols to process.\n        hdf_file_path (str): Path to the HDF5 file.\n        download_failures (list): List to track symbols that failed to download.\n        description (str): Description of the current process phase.\n\n    Returns:\n        None\n    \"\"\"\n\n    max_retries = 5\n    retry_delay = 5\n\n    for symbol in tqdm(symbols, desc=\"Processing symbols\"):\n        try:\n            stock = yf.Ticker(symbol)\n            info = stock.info\n\n            # Special handling for 'companyOfficers' column if it's causing serialization issues\n            if 'companyOfficers' in info and isinstance(info['companyOfficers'], (list, dict)):\n                info['companyOfficers'] = json.dumps(info['companyOfficers'])\n\n            info_df = pd.DataFrame([info])\n\n            if '52WeekChange' in info_df.columns:\n                info_df = info_df.rename(columns={'52WeekChange': 'WeekChange_52'})\n            if 'yield' in info_df.columns:\n                info_df = info_df.rename(columns={'yield': 'yield_value'})\n\n        except Exception as e:\n            logging.warning(f\"Failed to download data for {symbol}: {e}\")\n            download_failures.append(symbol)\n            continue  # Skip to the next symbol\n\n        # Attempt to save the data to HDF5 with retries for write errors\n        for attempt in range(max_retries):\n            try:\n                with pd.HDFStore(hdf_file_path, mode='a') as store:\n                    store.put(symbol, info_df, format='table', data_columns=True)\n                logging.info(f\"Fundamental data saved for {symbol}\")\n                break  # Success, exit retry loop\n            except Exception as e:\n                logging.warning(f\"Retry {attempt + 1} - Error saving data for {symbol} to HDF: {e}\")\n                if attempt &lt; max_retries - 1:\n                    time.sleep(retry_delay)  # Wait before retrying, but not after the last attempt\n<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\n\n\n\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Run Code<\/h2>\n\n\n\n<p>To run this code you will need to provide a list of symbols. In my instance, my symbols are generated from Alpaca API. It queries the API for active assets. Below is that function. But the code can also be run manually like this.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><\/code><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">symbols = ['AAPL', 'MSFT']\nsave_fundamental_data(symbols)<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Get Alpaca Active Assets<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code><\/code><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def get_active_assets():\n    api = tradeapi.REST(LIVE_API_KEY, LIVE_API_SECRET, LIVE_BASE_URL, api_version='v2')\n    assets = api.list_assets()\n    assets_dict = {}\n    for asset in assets:\n        if asset.status == 'active':\n            assets_dict[asset.symbol] = asset.name\n    return assets_dict\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Function to Query Data<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code><\/code><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def print_fundamental_data():\n    \"\"\"\n    Access and print the fundamental data for a given stock symbol from an HDF5 file,\n    ensuring all rows are displayed.\n\n    Returns:\n    None, but prints the fundamental data for the specified symbol if available.\n    \"\"\"\n    hdf_file_path = '\/home\/shared\/algos\/data\/fundamental_data.h5'\n    max_retries = 5\n    retry_delay = 5\n\n    for _ in range(max_retries):\n        try:\n            # Open the HDF5 file and retrieve all keys (symbols)\n            with pd.HDFStore(hdf_file_path, mode='r') as store:\n                keys = store.keys()\n                logging.info(\"Available symbols:\")\n                for key in keys:\n                    logging.info(key[1:])  # Remove leading '\/' from symbol name\n\n            # Prompt user to choose a symbol\n            symbol = input(\"Enter the symbol for which you want to view fundamental data: \").strip().upper()\n\n            # Check if the chosen symbol exists in the HDF5 file\n            with pd.HDFStore(hdf_file_path, mode='r') as store:\n                if f'\/{symbol}' in store:\n                    data_df = store[symbol]  # Read the dataframe for the symbol\n\n                    # Transpose the DataFrame to print all rows without abbreviation\n                    data_df_transposed = data_df.T\n\n                    # Print all columns without asking for user input\n                    print(f\"Fundamental data for {symbol}:\")\n                    print(data_df_transposed)\n                else:\n                    logging.info(f\"No data found for symbol: {symbol}\")\n\n            break  # Exit the retry loop if successful\n\n        except Exception as e:\n            logging.error(f\"Error accessing HDF5 file: {e}\")\n            logging.info(f\"Retrying in {retry_delay} seconds...\")\n            time.sleep(retry_delay)\n\n    else:\n        logging.error(\"Failed to access HDF5 file after multiple retries.\")\n\n# Example usage\nprint_fundamental_data()<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"562\" height=\"427\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-7.png\" alt=\"\" class=\"wp-image-7019 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-7.png 562w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-7-300x228.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/image-7-395x300.png 395w\" data-sizes=\"(max-width: 562px) 100vw, 562px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 562px; --smush-placeholder-aspect-ratio: 562\/427;\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fundamental data offers a plethora of data points about a company&#8217;s financial health and market position. I want to share a streamlined approach to accessing and storing fundamental&#8230;<\/p>\n","protected":false},"author":1,"featured_media":7015,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7014","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker\" \/>\n<meta property=\"og:description\" content=\"Fundamental data offers a plethora of data points about a company&#8217;s financial health and market position. I want to share a streamlined approach to accessing and storing fundamental...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\" \/>\n<meta property=\"og:site_name\" content=\"Jeremy Whittaker\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/WhittakerJeremy\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/WhittakerJeremy\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-14T21:22:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-08T21:11:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1792\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"JeremyWhittaker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"JeremyWhittaker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\"},\"author\":{\"name\":\"JeremyWhittaker\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"headline\":\"Python and yfinance: Free Fundamental Data for Algorithmic Trading\",\"datePublished\":\"2024-03-14T21:22:19+00:00\",\"dateModified\":\"2024-04-08T21:11:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\"},\"wordCount\":441,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"image\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\",\"url\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\",\"name\":\"Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker\",\"isPartOf\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp\",\"datePublished\":\"2024-03-14T21:22:19+00:00\",\"dateModified\":\"2024-04-08T21:11:59+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage\",\"url\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp\",\"contentUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp\",\"width\":1792,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/new.jeremywhittaker.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python and yfinance: Free Fundamental Data for Algorithmic Trading\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/#website\",\"url\":\"https:\/\/new.jeremywhittaker.com\/\",\"name\":\"Jeremy Whittaker\",\"description\":\"Research, software, markets, housing, and energy\",\"publisher\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/new.jeremywhittaker.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\",\"name\":\"JeremyWhittaker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"caption\":\"JeremyWhittaker\"},\"logo\":{\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\"},\"sameAs\":[\"http:\/\/www.jeremywhittaker.com\",\"https:\/\/www.facebook.com\/WhittakerJeremy\",\"https:\/\/www.linkedin.com\/in\/jeremywhittaker\/\"],\"url\":\"https:\/\/new.jeremywhittaker.com\/index.php\/author\/jeremywhittaker\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":"Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker","og_description":"Fundamental data offers a plethora of data points about a company&#8217;s financial health and market position. I want to share a streamlined approach to accessing and storing fundamental...","og_url":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/","og_site_name":"Jeremy Whittaker","article_publisher":"https:\/\/www.facebook.com\/WhittakerJeremy","article_author":"https:\/\/www.facebook.com\/WhittakerJeremy","article_published_time":"2024-03-14T21:22:19+00:00","article_modified_time":"2024-04-08T21:11:59+00:00","og_image":[{"width":1792,"height":1024,"url":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp","type":"image\/webp"}],"author":"JeremyWhittaker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"JeremyWhittaker","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#article","isPartOf":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/"},"author":{"name":"JeremyWhittaker","@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"headline":"Python and yfinance: Free Fundamental Data for Algorithmic Trading","datePublished":"2024-03-14T21:22:19+00:00","dateModified":"2024-04-08T21:11:59+00:00","mainEntityOfPage":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/"},"wordCount":441,"commentCount":0,"publisher":{"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"image":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage"},"thumbnailUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/","url":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/","name":"Python and yfinance: Free Fundamental Data for Algorithmic Trading - Jeremy Whittaker","isPartOf":{"@id":"https:\/\/new.jeremywhittaker.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage"},"image":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage"},"thumbnailUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp","datePublished":"2024-03-14T21:22:19+00:00","dateModified":"2024-04-08T21:11:59+00:00","breadcrumb":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#primaryimage","url":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp","contentUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2024\/03\/python-algorithmic-trading.webp","width":1792,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2024\/03\/14\/python-and-yfinance-free-fundamental-data-for-algorithmic-trading\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/new.jeremywhittaker.com\/"},{"@type":"ListItem","position":2,"name":"Python and yfinance: Free Fundamental Data for Algorithmic Trading"}]},{"@type":"WebSite","@id":"https:\/\/new.jeremywhittaker.com\/#website","url":"https:\/\/new.jeremywhittaker.com\/","name":"Jeremy Whittaker","description":"Research, software, markets, housing, and energy","publisher":{"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/new.jeremywhittaker.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c","name":"JeremyWhittaker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","caption":"JeremyWhittaker"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g"},"sameAs":["http:\/\/www.jeremywhittaker.com","https:\/\/www.facebook.com\/WhittakerJeremy","https:\/\/www.linkedin.com\/in\/jeremywhittaker\/"],"url":"https:\/\/new.jeremywhittaker.com\/index.php\/author\/jeremywhittaker\/"}]}},"_links":{"self":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/7014","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/comments?post=7014"}],"version-history":[{"count":6,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/7014\/revisions"}],"predecessor-version":[{"id":7264,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/7014\/revisions\/7264"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/media\/7015"}],"wp:attachment":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/media?parent=7014"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/categories?post=7014"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/tags?post=7014"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}