diff --git a/README.md b/README.md index 7f0f561..c48229b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ pip install fear-and-greed ``` # Usage example +## Fetch Current Fear & Greed Index ```python import fear_and_greed @@ -22,11 +23,37 @@ Returns a three-element namedtuple with (a) the current value of the Fear & Gree FearGreedIndex( value=31.4266, description='fear', - last_update=datetime.datetime(2022, 4, 25, 16, 51, 9, 254000, tzinfo=datetime.timezone.utc)), + last_update=datetime.datetime(2022, 4, 25, 16, 51, 9, 254000, tzinfo=datetime.timezone.utc), ) ``` -Requests to CNN's website are locally [cached](https://pypi.org/project/requests-cache/) for 1m. +## Fetch Historical Fear & Greed Data + +```python +historical_data = fear_and_greed.historical() +``` +The historical function provides a list of historical Fear & Greed Index values, each with its corresponding description and timestamp. + +```python +[ + FearGreedIndex( + value=80.0, + description='extreme greed', + last_update=datetime.datetime(2022, 4, 20, 0, 0, 0, tzinfo=datetime.timezone.utc) + ), + FearGreedIndex( + value=60.5, + description='greed', + last_update=datetime.datetime(2022, 4, 21, 0, 0, 0, tzinfo=datetime.timezone.utc) + ) +] +... +``` + +## Features +* Fetch the current Fear & Greed Index value along with its description and timestamp. +* Retrieve historical Fear & Greed Index data to analyze trends. +* Uses locally [cached](https://pypi.org/project/requests-cache/) requests to CNN's website for 1 minute to minimize network usage. [![Test workflow](https://github.com/vterron/fear-and-greed/actions/workflows/test.yml/badge.svg)](https://github.com/vterron/fear-and-greed/actions/workflows/test.yml) [![PyPI badge](https://img.shields.io/pypi/v/fear-and-greed?color=blue)](https://pypi.org/project/fear-and-greed/) diff --git a/src/fear_and_greed/__init__.py b/src/fear_and_greed/__init__.py index fabcb30..8cd67f1 100644 --- a/src/fear_and_greed/__init__.py +++ b/src/fear_and_greed/__init__.py @@ -1,3 +1,3 @@ -from .cnn import FearGreedIndex, get +from .cnn import FearGreedIndex, get, historical __version__ = "0.4" diff --git a/src/fear_and_greed/cnn.py b/src/fear_and_greed/cnn.py index 049b1ea..dafe8c2 100644 --- a/src/fear_and_greed/cnn.py +++ b/src/fear_and_greed/cnn.py @@ -62,3 +62,28 @@ def get(fetcher: Fetcher = None) -> FearGreedIndex: description=response["rating"], last_update=datetime.datetime.fromisoformat(response["timestamp"]), ) + +def historical(fetcher: Fetcher = None) -> dict: + """Returns CNN's Fear & Greed Index historical data.""" + + if fetcher is None: + fetcher = Fetcher() + + response = fetcher().get("fear_and_greed_historical", {}) + fear_greed_historical = [] + + if "data" not in response: + raise ValueError("No historical data found") + + historical_data = response["data"] + for data in historical_data: + fear_greed_historical.append(FearGreedIndex( + value=data["y"], + description=data["rating"], + last_update=datetime.datetime.fromtimestamp(data["x"] / 1000), + )) + + fear_greed_historical.sort(key=lambda x: x.last_update) + + return fear_greed_historical + diff --git a/tests/test_cnn.py b/tests/test_cnn.py index 5da17ca..f3a9b32 100644 --- a/tests/test_cnn.py +++ b/tests/test_cnn.py @@ -37,6 +37,34 @@ def test_get(self): ) self.assertEqual(got, want) + def test_historical(self): + with open(FAKE_JSON_RESPONSE_GOLDEN_FILE, "rt") as fd: + # Lambda is evaluated lazily, force JSON load while file is open. + content = json.load(fd) + fake_fetcher = lambda: content + got = cnn.historical(fetcher=fake_fetcher) + + self.assertEqual(len(got), 269) + + first_five = [ + cnn.FearGreedIndex(51.03333333333334, "neutral", datetime.datetime.fromtimestamp(1619395200.0)), + cnn.FearGreedIndex(52.79999999999999, "neutral", datetime.datetime.fromtimestamp(1619481600.0)), + cnn.FearGreedIndex(54.133333333333326, "neutral", datetime.datetime.fromtimestamp(1619568000.0)), + cnn.FearGreedIndex(58.93333333333334, "greed", datetime.datetime.fromtimestamp(1619654400.0)), + cnn.FearGreedIndex(49.26666666666667, "neutral", datetime.datetime.fromtimestamp(1619740800.0)) + ] + + self.assertEqual(got[:5], first_five) + + last_five = [ + cnn.FearGreedIndex(41.1246, "fear", datetime.datetime.fromtimestamp(1650585600.0)), + cnn.FearGreedIndex(40.1512, "fear", datetime.datetime.fromtimestamp(1650672000.0)), + cnn.FearGreedIndex(40.1512, "fear", datetime.datetime.fromtimestamp(1650758400.0)), + cnn.FearGreedIndex(30.8254, "fear", datetime.datetime.fromtimestamp(1650844800.0)), + cnn.FearGreedIndex(30.8254, "fear", datetime.datetime.fromtimestamp(1650903669.254)) + ] + + self.assertEqual(got[-5:], last_five) if __name__ == "__main__": absltest.main()