From eb6e385dc503d30b888bbdc40ed2941c03fb6e0e Mon Sep 17 00:00:00 2001 From: Virat Singh Date: Fri, 12 Jan 2024 20:52:09 -0500 Subject: [PATCH] community: Add PolygonAPIWrapper and get_last_quote endpoint (#15971) - **Description:** Added a `PolygonAPIWrapper` and an initial `get_last_quote` endpoint, which allows us to get the last price quote for a given `ticker`. Once merged, I can add a Polygon tool in `tools/` for agents to use. - **Twitter handle:** [@virattt](https://twitter.com/virattt) The Polygon.io Stocks API provides REST endpoints that let you query the latest market data from all US stock exchanges. --- docs/docs/integrations/tools/polygon.ipynb | 112 ++++++++++++++++++ .../langchain_community/utilities/polygon.py | 46 +++++++ .../utilities/test_polygon.py | 9 ++ 3 files changed, 167 insertions(+) create mode 100644 docs/docs/integrations/tools/polygon.ipynb create mode 100644 libs/community/langchain_community/utilities/polygon.py create mode 100644 libs/community/tests/integration_tests/utilities/test_polygon.py diff --git a/docs/docs/integrations/tools/polygon.ipynb b/docs/docs/integrations/tools/polygon.ipynb new file mode 100644 index 0000000000..7f7be71168 --- /dev/null +++ b/docs/docs/integrations/tools/polygon.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "245a954a", + "metadata": { + "id": "245a954a" + }, + "source": [ + "# Polygon Stock Market API\n", + "\n", + ">[Polygon](https://polygon.io/) The Polygon.io Stocks API provides REST endpoints that let you query the latest market data from all US stock exchanges.\n", + "\n", + "Use the ``PolygonAPIWrapper`` to get stock market data like the latest quote for a ticker." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34bb5968", + "metadata": { + "id": "34bb5968", + "is_executing": true + }, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "os.environ[\"POLYGON_API_KEY\"] = getpass.getpass()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4910f8", + "metadata": { + "id": "ac4910f8", + "is_executing": true + }, + "outputs": [], + "source": [ + "from langchain_community.utilities.polygon import PolygonAPIWrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84b8f773", + "metadata": { + "id": "84b8f773" + }, + "outputs": [], + "source": [ + "polygon = PolygonAPIWrapper()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "068991a6", + "metadata": { + "id": "068991a6", + "outputId": "c5cdc6ec-03cf-4084-cc6f-6ae792d91d39" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': {'P': 185.86, 'S': 1, 'T': 'AAPL', 'X': 11, 'i': [604], 'p': 185.81, 'q': 106551669, 's': 2, 't': 1705098436014023700, 'x': 12, 'y': 1705098436014009300, 'z': 3}}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "polygon.run(\"get_last_quote\", \"AAPL\")" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "venv", + "language": "python", + "display_name": "venv" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + }, + "vscode": { + "interpreter": { + "hash": "53f3bc57609c7a84333bb558594977aa5b4026b1d6070b93987956689e367341" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/community/langchain_community/utilities/polygon.py b/libs/community/langchain_community/utilities/polygon.py new file mode 100644 index 0000000000..bd7aa9964f --- /dev/null +++ b/libs/community/langchain_community/utilities/polygon.py @@ -0,0 +1,46 @@ +""" +Util that calls several of Polygon's stock market REST APIs. +Docs: https://polygon.io/docs/stocks/getting-started +""" +import json +from typing import Dict, Optional + +import requests +from langchain_core.pydantic_v1 import BaseModel, root_validator +from langchain_core.utils import get_from_dict_or_env + +POLYGON_BASE_URL = "https://api.polygon.io/" + + +class PolygonAPIWrapper(BaseModel): + """Wrapper for Polygon API.""" + + polygon_api_key: Optional[str] = None + + @root_validator() + def validate_environment(cls, values: Dict) -> Dict: + """Validate that api key in environment.""" + polygon_api_key = get_from_dict_or_env( + values, "polygon_api_key", "POLYGON_API_KEY" + ) + values["polygon_api_key"] = polygon_api_key + + return values + + def get_last_quote(self, ticker: str) -> Optional[dict]: + """Get the most recent National Best Bid and Offer (Quote) for a ticker.""" + url = f"{POLYGON_BASE_URL}v2/last/nbbo/{ticker}?apiKey={self.polygon_api_key}" + response = requests.get(url) + data = response.json() + + status = data.get("status", None) + if status != "OK": + raise ValueError(f"API Error: {data}") + + return data.get("results", None) + + def run(self, mode: str, ticker: str) -> str: + if mode == "get_last_quote": + return json.dumps(self.get_last_quote(ticker)) + else: + raise ValueError(f"Invalid mode {mode} for Polygon API.") diff --git a/libs/community/tests/integration_tests/utilities/test_polygon.py b/libs/community/tests/integration_tests/utilities/test_polygon.py new file mode 100644 index 0000000000..4aecc9cb39 --- /dev/null +++ b/libs/community/tests/integration_tests/utilities/test_polygon.py @@ -0,0 +1,9 @@ +"""Integration test for Polygon API Wrapper.""" +from langchain_community.utilities.polygon import PolygonAPIWrapper + + +def test_get_last_quote() -> None: + """Test for getting the last quote of a ticker from the Polygon API.""" + polygon = PolygonAPIWrapper() + output = polygon.run("get_last_quote", "AAPL") + assert output is not None