diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 98bdf27b..aa8722e3 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -3,6 +3,7 @@ from .quotes import QuotesClient from .snapshot import SnapshotClient from .indicators import IndicatorsClient +from .summaries import SummariesClient from .reference import ( MarketsClient, TickersClient, @@ -34,6 +35,7 @@ class RESTClient( ExchangesClient, ContractsClient, IndicatorsClient, + SummariesClient, ): def __init__( self, diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 75b91716..dce4aed0 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -151,8 +151,11 @@ def _get_params( or argname.endswith("_lte") or argname.endswith("_gt") or argname.endswith("_gte") + or argname.endswith("_any_of") ): - argname = ".".join(argname.rsplit("_", 1)) + argname = ".".join(argname.split("_", 1)) + if argname.endswith("any_of"): + val = ",".join(val) params[argname] = val return params diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index c76311bb..2c9a8086 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -12,3 +12,4 @@ from .splits import * from .tickers import * from .trades import * +from .summaries import * diff --git a/polygon/rest/models/summaries.py b/polygon/rest/models/summaries.py new file mode 100644 index 00000000..549c6fe0 --- /dev/null +++ b/polygon/rest/models/summaries.py @@ -0,0 +1,70 @@ +from sqlite3 import Timestamp +from typing import Optional +from ...modelclass import modelclass +from .tickers import Branding + + +@modelclass +class Session: + "Contains Session data for the summaries endpoint." + change: Optional[float] = None + change_percent: Optional[float] = None + early_trading_change: Optional[float] = None + early_trading_change_percent: Optional[float] = None + late_trading_change: Optional[float] = None + late_trading_change_percent: Optional[float] = None + close: Optional[float] = None + high: Optional[float] = None + low: Optional[float] = None + open: Optional[float] = None + previous_close: Optional[float] = None + volume: Optional[float] = None + + @staticmethod + def from_dict(d): + return Session(**d) + + +@modelclass +class Options: + "Contains options data for the summaries endpoint" + contract_type: Optional[str] = None + exercise_style: Optional[str] = None + expiration_date: Optional[str] = None + shares_per_contract: Optional[float] = None + strike_price: Optional[float] = None + underlying_ticker: Optional[float] = None + + @staticmethod + def from_dict(d): + return Options(**d) + + +@modelclass +class SummaryResult: + "Contains summary result data for a list of tickers" + price: Optional[float] = None + name: Optional[str] = None + ticker: Optional[str] = None + branding: Optional[Branding] = None + market_status: Optional[str] = None + type: Optional[str] = None + session: Optional[Session] = None + options: Optional[Options] = None + error: Optional[str] = None + message: Optional[str] = None + + @staticmethod + def from_dict(d): + return SummaryResult( + price=d.get("price", None), + name=d.get("name", None), + ticker=d.get("ticker", None), + branding=None if "branding" not in d else Branding.from_dict(d["branding"]), + market_status=d.get("market_status", None), + type=d.get("type", None), + session=None if "session" not in d else Session.from_dict(d["session"]), + options=None if "options" not in d else Options.from_dict(d["options"]), + error=d.get("error", None), + message=d.get("message", None), + ) diff --git a/polygon/rest/summaries.py b/polygon/rest/summaries.py new file mode 100644 index 00000000..110f8fbe --- /dev/null +++ b/polygon/rest/summaries.py @@ -0,0 +1,33 @@ +from polygon.rest.models.summaries import SummaryResult +from .base import BaseClient +from typing import Optional, Any, Dict, List, Union, Iterator +from .models import Order +from urllib3 import HTTPResponse +from datetime import datetime, date + + +class SummariesClient(BaseClient): + def get_summaries( + self, + ticker_any_of: Optional[List[str]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[List[SummaryResult], HTTPResponse]: + """ + GetSummaries retrieves summaries for the ticker list with the given params. + For more details see https://polygon.io/docs/stocks/get_v1_summaries. + + :param ticker_any_of: The ticker symbol + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: SummaryResults + """ + + url = f"/v1/summaries" + return self._get( + path=url, + params=self._get_params(self.get_summaries, locals()), + result_key="results", + deserializer=SummaryResult.from_dict, + raw=raw, + ) diff --git a/test_rest/mocks/v1/summaries&ticker.any_of=NCLH%2CO%3ANCLH221014C00005000%2CC%3AEURUSD%2CX%3ABTCUSD%2CAPx.json b/test_rest/mocks/v1/summaries&ticker.any_of=NCLH%2CO%3ANCLH221014C00005000%2CC%3AEURUSD%2CX%3ABTCUSD%2CAPx.json new file mode 100644 index 00000000..3d4e504c --- /dev/null +++ b/test_rest/mocks/v1/summaries&ticker.any_of=NCLH%2CO%3ANCLH221014C00005000%2CC%3AEURUSD%2CX%3ABTCUSD%2CAPx.json @@ -0,0 +1,101 @@ +{ + "request_id":"abc123", + "results":[ + { + "branding":{ + "icon_url":"https://api.polygon.io/icon.png", + "logo_url":"https://api.polygon.io/logo.svg" + }, + "market_status":"closed", + "name":"Norwegian Cruise Lines", + "price":22.3, + "session":{ + "change":-1.05, + "change_percent":-4.67, + "close":21.4, + "early_trading_change":-0.39, + "early_trading_change_percent":-0.07, + "high":22.49, + "late_trading_change":1.2, + "late_trading_change_percent":3.92, + "low":21.35, + "open":22.49, + "previous_close":22.45, + "volume":37 + }, + "ticker":"NCLH", + "type":"stocks" + }, + { + "market_status":"closed", + "name":"NCLH $5 Call", + "options":{ + "contract_type":"call", + "exercise_style":"american", + "expiration_date":"2022-10-14", + "shares_per_contract":100, + "strike_price":5, + "underlying_ticker":"NCLH" + }, + "price":6.6, + "session":{ + "change":-0.05, + "change_percent":-1.07, + "close":6.65, + "early_trading_change":-0.01, + "early_trading_change_percent":-0.03, + "high":7.01, + "late_trading_change":-0.4, + "late_trading_change_percent":-0.02, + "low":5.42, + "open":6.7, + "previous_close":6.71, + "volume":67 + }, + "ticker":"O:NCLH221014C00005000", + "type":"options" + }, + { + "market_status":"open", + "name":"Euro - United States Dollar", + "price":0.97989, + "session":{ + "change":-0.0001, + "change_percent":-0.67, + "close":0.97989, + "high":0.98999, + "low":0.96689, + "open":0.97889, + "previous_close":0.98001 + }, + "ticker":"C:EURUSD", + "type":"fx" + }, + { + "branding":{ + "icon_url":"https://api.polygon.io/icon.png", + "logo_url":"https://api.polygon.io/logo.svg" + }, + "market_status":"open", + "name":"Bitcoin - United States Dollar", + "price":32154.68, + "session":{ + "change":-201.23, + "change_percent":-0.77, + "close":32154.68, + "high":33124.28, + "low":28182.88, + "open":31129.32, + "previous_close":33362.18 + }, + "ticker":"X:BTCUSD", + "type":"crypto" + }, + { + "error":"NOT_FOUND", + "message":"Ticker not found.", + "ticker":"APx" + } + ], + "status":"OK" +} \ No newline at end of file diff --git a/test_rest/test_summaries.py b/test_rest/test_summaries.py new file mode 100644 index 00000000..97737eee --- /dev/null +++ b/test_rest/test_summaries.py @@ -0,0 +1,106 @@ +from polygon.rest.models import SummaryResult, Branding, Session, Options +from base import BaseTest + + +class SummariesTest(BaseTest): + def test_get_summaries_list(self): + ticker_any_of = ["NCLH", "O:NCLH221014C00005000", "C:EURUSD", "X:BTCUSD", "APx"] + summary_results = self.c.get_summaries(ticker_any_of) + expected = [ + SummaryResult( + price=22.3, + name="Norwegian Cruise Lines", + ticker="NCLH", + branding=Branding( + icon_url="https://api.polygon.io/icon.png", + logo_url="https://api.polygon.io/logo.svg", + ), + market_status="closed", + type="stocks", + session=Session( + change=-1.05, + change_percent=-4.67, + close=21.4, + early_trading_change=-0.39, + early_trading_change_percent=-0.07, + high=22.49, + late_trading_change=1.2, + late_trading_change_percent=3.92, + low=21.35, + open=22.49, + previous_close=22.45, + volume=37, + ), + ), + SummaryResult( + price=6.6, + name="NCLH $5 Call", + ticker="O:NCLH221014C00005000", + market_status="closed", + type="options", + session=Session( + change=-0.05, + change_percent=-1.07, + close=6.65, + early_trading_change=-0.01, + early_trading_change_percent=-0.03, + high=7.01, + late_trading_change=-0.4, + late_trading_change_percent=-0.02, + low=5.42, + open=6.7, + previous_close=6.71, + volume=67, + ), + options=Options( + contract_type="call", + exercise_style="american", + expiration_date="2022-10-14", + shares_per_contract=100, + strike_price=5, + underlying_ticker="NCLH", + ), + ), + SummaryResult( + price=0.97989, + name="Euro - United States Dollar", + ticker="C:EURUSD", + market_status="open", + type="fx", + session=Session( + change=-0.0001, + change_percent=-0.67, + close=0.97989, + high=0.98999, + low=0.96689, + open=0.97889, + previous_close=0.98001, + ), + ), + SummaryResult( + price=32154.68, + name="Bitcoin - United States Dollar", + ticker="X:BTCUSD", + branding=Branding( + icon_url="https://api.polygon.io/icon.png", + logo_url="https://api.polygon.io/logo.svg", + ), + market_status="open", + type="crypto", + session=Session( + change=-201.23, + change_percent=-0.77, + close=32154.68, + high=33124.28, + low=28182.88, + open=31129.32, + previous_close=33362.18, + ), + ), + SummaryResult( + ticker="APx", + error="NOT_FOUND", + message="Ticker not found.", + ), + ] + self.assertEqual(summary_results, expected)