-
Notifications
You must be signed in to change notification settings - Fork 112
TutorTask394_DataLoader_for_Historical_Causal_AutoML_and_FRED #404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
sonniki
merged 13 commits into
master
from
TutorTask394_DataLoader_for_Historical_Causal_AutoML_and_FRED
May 13, 2025
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
6fe2128
TutorTask394: PR1 -> FredDataLoader that returns DF
7b1f5c4
TutorTask394: Pushing a duplicate file to later delete it to debug a …
50ebad7
TutorTask394: Remove duplicate
6d21bf7
Reviewer Changes
de1d24b
TutorTask394: Remove fred_utils.py
2dab946
TutorTask394: Reviewer Changes again
9fcefeb
Merge branch 'master' into TutorTask394_DataLoader_for_Historical_Cau…
indrayudd 68f0f0b
TutorTask394: Reviewer changes.
dec20ea
TutorTask394: removed stray period.
c7b2c70
Merge branch 'master' into TutorTask394_DataLoader_for_Historical_Cau…
indrayudd 04b06c0
TutorTask394: Reviewer Changes
cd34a34
TutorTask394: Debugging commit
73e15eb
TutorTask394: Lint and improve comments
sonniki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| """ | ||
| Import as: | ||
|
|
||
| import causal_automl.download_fred_data as cadofrda | ||
| """ | ||
|
|
||
| import logging as log | ||
| import os | ||
| import time | ||
| from typing import Optional | ||
|
|
||
| import fredapi | ||
| import helpers.hdbg as hdbg | ||
| import pandas as pd | ||
| import ratelimit | ||
|
|
||
| _LOG = log.getLogger(__name__) | ||
|
|
||
|
|
||
| # ############################################################################# | ||
| # FredDataDownloader | ||
| # ############################################################################# | ||
|
|
||
|
|
||
| class FredDataDownloader: | ||
| """ | ||
| Download historical data from FRED. | ||
| """ | ||
|
|
||
| def __init__(self, api_key: Optional[str] = None) -> None: | ||
| """ | ||
| Initialize the FRED data downloader with the API key. | ||
|
|
||
| If no FRED API key is passed as a parameter, it is read from the | ||
| environment variable. | ||
|
|
||
| :param api_key: FRED API key | ||
| """ | ||
| key = api_key or os.getenv("FRED_API_KEY") | ||
| if not key: | ||
| raise ValueError("FRED API key is required") | ||
| self._client = fredapi.Fred(api_key=key) | ||
|
|
||
| @ratelimit.sleep_and_retry | ||
| @ratelimit.limits(calls=60, period=60) | ||
| def download_series( | ||
| self, | ||
| id_: str, | ||
| start_timestamp: Optional[pd.Timestamp] = None, | ||
| end_timestamp: Optional[pd.Timestamp] = None, | ||
| frequency: Optional[str] = None, | ||
| ) -> Optional[pd.DataFrame]: | ||
| """ | ||
| Download historical series data. | ||
|
|
||
| When no start and end timestamps are passed, the entire time series is downloaded. | ||
| If no frequency is passed, the highest available frequency is downloaded. | ||
|
|
||
| Example of a returned series: | ||
|
|
||
| ``` | ||
| GDP | ||
| 2019-10-01 21933.217 | ||
| 2020-01-01 21727.657 | ||
| 2020-04-01 19935.444 | ||
| ``` | ||
|
|
||
| :param id_: FRED series identifier (e.g., "GDP") | ||
| :param start_timestamp: first observation date | ||
| :param end_timestamp: last observation date | ||
| :param frequency: series data frequency | ||
| - "q": quarter | ||
| - "sa": semi-annual | ||
| - "a": annual | ||
| :return: relevant FRED series data | ||
| """ | ||
| # Validate the passed frequency value. | ||
| valid_freqs = ["q", "sa", "a"] | ||
| if frequency is not None: | ||
| hdbg.dassert_in( | ||
| frequency, | ||
| valid_freqs, | ||
| "Invalid frequency '%s'.", | ||
| frequency, | ||
| ) | ||
| # Set args. | ||
| loading_kwargs = {} | ||
| if start_timestamp is not None: | ||
| loading_kwargs["observation_start"] = start_timestamp | ||
| if end_timestamp is not None: | ||
| loading_kwargs["observation_end"] = end_timestamp | ||
| if frequency is not None: | ||
| loading_kwargs["frequency"] = frequency | ||
| attempt = 1 | ||
| max_attempts = 4 | ||
| err_msgs = {} | ||
| # Start attempts. | ||
| while attempt <= max_attempts: | ||
| try: | ||
| # Download the data for the series. | ||
| series = self._client.get_series( | ||
| id_, | ||
| **loading_kwargs, | ||
| ) | ||
| except Exception as err: | ||
| if "Internal Server Error" in str(err): | ||
| _LOG.error("Attempt %s: %s Retrying...", attempt, err) | ||
| # Wait before retrying. | ||
| time.sleep(10) | ||
| elif "Too Many Requests" in str(err): | ||
| # Retry after exponential backoff. | ||
| backoff = 4**attempt | ||
| _LOG.error( | ||
| "Attempt %d: %s Retrying after %ds... ", | ||
| attempt, | ||
| err, | ||
| backoff, | ||
| ) | ||
| time.sleep(backoff) | ||
| continue | ||
| else: | ||
| raise | ||
| err_msgs[f"Attempt {attempt}"] = str(err) | ||
| attempt += 1 | ||
| continue | ||
| # Package the output. | ||
| df = series.to_frame(name=id_) | ||
| _LOG.info( | ||
| "Downloaded series %s with %d records", | ||
| id_, | ||
| len(df), | ||
| ) | ||
|
indrayudd marked this conversation as resolved.
|
||
| return df | ||
| raise RuntimeError( | ||
| f"Failed to fetch after {max_attempts} attempts. Errors per run: {err_msgs}" | ||
| ) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.