From a363476919919d97c2065d531a12c4277d3a29a0 Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Mon, 25 Apr 2022 11:48:58 -0400 Subject: [PATCH 01/41] copy rfc over (#114) --- polygon/rest/__init__.py | 7 +- polygon/rest/aggs.py | 39 + polygon/rest/base.py | 90 + polygon/rest/client.py | 253 -- polygon/rest/models/__init__.py | 229 +- polygon/rest/models/aggs.py | 26 + polygon/rest/models/definitions.py | 4180 ---------------------------- polygon/rest/models/trades.py | 23 + polygon/rest/models/unmarshal.py | 9 - polygon/rest/trades.py | 41 + rest-example.py | 31 +- 11 files changed, 242 insertions(+), 4686 deletions(-) create mode 100644 polygon/rest/aggs.py create mode 100644 polygon/rest/base.py delete mode 100644 polygon/rest/client.py create mode 100644 polygon/rest/models/aggs.py delete mode 100644 polygon/rest/models/definitions.py create mode 100644 polygon/rest/models/trades.py delete mode 100644 polygon/rest/models/unmarshal.py create mode 100644 polygon/rest/trades.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index fb5d2b40..89861e3a 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1 +1,6 @@ -from .client import RESTClient +from .aggs import AggsClient +from .trades import TradesClient + +class RESTClient(AggsClient, TradesClient): + pass + diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py new file mode 100644 index 00000000..b345d0e1 --- /dev/null +++ b/polygon/rest/aggs.py @@ -0,0 +1,39 @@ +from .base import BaseClient +from typing import Optional, Any, Dict, List, Union +from .models import Agg, Sort + +# https://polygon.io/docs/stocks +class AggsClient(BaseClient): + def get_aggs(self, + ticker: str, + multiplier: int, + timespan: str, + # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp + from_: str, + to: str, + adjusted: Optional[bool]=None, + sort: Optional[Union[str, Sort]]=None, + limit: Optional[int]=None, + params: Optional[Dict[str, Any]]=None, + raw: bool=False + ) -> List[Agg]: + """ + Get aggregate bars for a ticker over a given date range in custom time window sizes. + + :param ticker: The ticker symbol. + :param multiplier: The size of the timespan multiplier. + :param timespan: The size of the time window. + :param _from: The start of the aggregate time window. + :param to: The end of the aggregate time window. + :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. + :param sort: Sort the results by timestamp. asc will return results in ascending order (oldest at the top), desc will return results in descending order (newest at the top).The end of the aggregate time window. + :param limit: Limits the number of base aggregates queried to create the aggregate results. Max 50000 and Default 5000. Read more about how limit is used to calculate aggregate results in our article on Aggregate Data API Improvements. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of aggregates + :rtype: List[Agg] + """ + url = f"/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" + + return self._get(path=url, params=self._get_params(self.get_aggs, locals()), resultKey="results", deserializer=Agg.from_dict, raw=raw) + diff --git a/polygon/rest/base.py b/polygon/rest/base.py new file mode 100644 index 00000000..2cbd985d --- /dev/null +++ b/polygon/rest/base.py @@ -0,0 +1,90 @@ +import os +import json +import urllib3 +import inspect +from enum import Enum +from typing import Optional, Any + +base = 'https://api.polygon.io' +env_key = "POLYGON_API_KEY" + +# https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html +class BaseClient: + def __init__( + self, + api_key: Optional[str] = os.getenv(env_key), + connect_timeout: float = 10.0, + read_timeout: float = 10.0, + num_pools: int = 10, + retries = 3, + base: str = base + ): + if api_key is None: + raise Exception(f"Must specify env var {env_key} or pass api_key in constructor") + self.API_KEY = api_key + self.BASE = base + + # https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool + self.client = urllib3.PoolManager(num_pools=num_pools, headers={ + 'Authorization': 'Bearer ' + self.API_KEY + }) + self.timeout=urllib3.Timeout(connect=connect_timeout, read=read_timeout) + self.retries = retries + + def _decode(self, resp): + return json.loads(resp.data.decode('utf-8')) + + def _get(self, path: str, params: Optional[dict] = None, resultKey: Optional[str] = None, deserializer = None, raw: bool = False) -> Any: + if params is None: + params = {} + params = {str(k): str(v) for k, v in params.items() if v is not None} + resp = self.client.request('GET', self.BASE + path, fields=params, retries=self.retries) + + if resp.status != 200: + raise Exception(resp.data.decode('utf-8')) + + if raw: + return resp + + obj = self._decode(resp) + + if resultKey: + obj = obj[resultKey] + + if deserializer: + obj = [deserializer(o) for o in obj] + + return obj + + def _get_params(self, fn, caller_locals): + params = caller_locals["params"] + if params is None: + params = {} + # https://docs.python.org/3.7/library/inspect.html#inspect.Signature + for argname, v in inspect.signature(fn).parameters.items(): + # https://docs.python.org/3.7/library/inspect.html#inspect.Parameter + if argname in ['params', 'raw']: + continue + if v.default != v.empty: + # timestamp_lt -> timestamp.lt + val = caller_locals.get(argname, v.default) + if isinstance(val, Enum): + val = val.value + if val is not None: + params[argname.replace("_", ".")] = val + + return params + + def _paginate(self, path: str, params: dict, raw: bool, deserializer): + while True: + resp = self._get(path=path, params=params, deserializer=deserializer, raw=True) + if raw: + return resp + decoded = self._decode(resp) + for t in decoded["results"]: + yield deserializer(t) + if "next_url" in decoded: + path = decoded["next_url"].replace(self.BASE, '') + params = {} + else: + return diff --git a/polygon/rest/client.py b/polygon/rest/client.py deleted file mode 100644 index 3b05fd75..00000000 --- a/polygon/rest/client.py +++ /dev/null @@ -1,253 +0,0 @@ -from typing import Dict, Type - -import requests - -from polygon.rest import models -from polygon.rest.models import unmarshal - - -class RESTClient: - """ This is a custom generated class """ - DEFAULT_HOST = "api.polygon.io" - - def __init__(self, auth_key: str, timeout: int=None): - self.auth_key = auth_key - self.url = "https://" + self.DEFAULT_HOST - - self._session = requests.Session() - self._session.params["apiKey"] = self.auth_key - self.timeout = timeout - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def close(self): - self._session.close() - - def _handle_response(self, response_type: str, endpoint: str, params: Dict[str, str]) -> Type[models.AnyDefinition]: - resp: requests.Response = self._session.get(endpoint, params=params, timeout=self.timeout) - if resp.status_code == 200: - return unmarshal.unmarshal_json(response_type, resp.json()) - else: - resp.raise_for_status() - - def reference_tickers(self, **query_params) -> models.ReferenceTickersApiResponse: - endpoint = f"{self.url}/v2/reference/tickers" - return self._handle_response("ReferenceTickersApiResponse", endpoint, query_params) - - def reference_tickers_v3(self, next_url=None, **query_params) -> models.ReferenceTickersV3ApiResponse: - endpoint = f"{self.url}/v3/reference/tickers" if not next_url else next_url - return self._handle_response("ReferenceTickersV3ApiResponse", endpoint, query_params) - - def reference_ticker_types(self, **query_params) -> models.ReferenceTickerTypesApiResponse: - endpoint = f"{self.url}/v2/reference/types" - return self._handle_response("ReferenceTickerTypesApiResponse", endpoint, query_params) - - def reference_ticker_details(self, symbol, **query_params) -> models.ReferenceTickerDetailsApiResponse: - endpoint = f"{self.url}/v1/meta/symbols/{symbol}/company" - return self._handle_response("ReferenceTickerDetailsApiResponse", endpoint, query_params) - - def reference_ticker_details_vx(self, symbol, **query_params) -> models.ReferenceTickerDetailsV3ApiResponse: - endpoint = f"{self.url}/vX/reference/tickers/{symbol}" - return self._handle_response("ReferenceTickerDetailsV3ApiResponse", endpoint, query_params) - - def reference_ticker_news(self, symbol, **query_params) -> models.ReferenceTickerNewsApiResponse: - endpoint = f"{self.url}/v1/meta/symbols/{symbol}/news" - return self._handle_response("ReferenceTickerNewsApiResponse", endpoint, query_params) - - def reference_ticker_news_v2(self, **query_params) -> models.ReferenceTickerNewsV2ApiResponse: - endpoint = f"{self.url}/v2/reference/news" - return self._handle_response("ReferenceTickerNewsV2ApiResponse", endpoint, query_params) - - def reference_markets(self, **query_params) -> models.ReferenceMarketsApiResponse: - endpoint = f"{self.url}/v2/reference/markets" - return self._handle_response("ReferenceMarketsApiResponse", endpoint, query_params) - - def reference_locales(self, **query_params) -> models.ReferenceLocalesApiResponse: - endpoint = f"{self.url}/v2/reference/locales" - return self._handle_response("ReferenceLocalesApiResponse", endpoint, query_params) - - def reference_stock_splits(self, symbol, **query_params) -> models.ReferenceStockSplitsApiResponse: - endpoint = f"{self.url}/v2/reference/splits/{symbol}" - return self._handle_response("ReferenceStockSplitsApiResponse", endpoint, query_params) - - def reference_stock_dividends(self, symbol, **query_params) -> models.ReferenceStockDividendsApiResponse: - endpoint = f"{self.url}/v2/reference/dividends/{symbol}" - return self._handle_response("ReferenceStockDividendsApiResponse", endpoint, query_params) - - def reference_stock_financials(self, symbol, **query_params) -> models.ReferenceStockFinancialsApiResponse: - endpoint = f"{self.url}/v2/reference/financials/{symbol}" - return self._handle_response("ReferenceStockFinancialsApiResponse", endpoint, query_params) - - def reference_market_status(self, **query_params) -> models.ReferenceMarketStatusApiResponse: - endpoint = f"{self.url}/v1/marketstatus/now" - return self._handle_response("ReferenceMarketStatusApiResponse", endpoint, query_params) - - def reference_market_holidays(self, **query_params) -> models.ReferenceMarketHolidaysApiResponse: - endpoint = f"{self.url}/v1/marketstatus/upcoming" - return self._handle_response("ReferenceMarketHolidaysApiResponse", endpoint, query_params) - - def stocks_equities_exchanges(self, **query_params) -> models.StocksEquitiesExchangesApiResponse: - endpoint = f"{self.url}/v1/meta/exchanges" - return self._handle_response("StocksEquitiesExchangesApiResponse", endpoint, query_params) - - def stocks_equities_historic_trades(self, symbol, date, - **query_params) -> models.StocksEquitiesHistoricTradesApiResponse: - endpoint = f"{self.url}/v1/historic/trades/{symbol}/{date}" - return self._handle_response("StocksEquitiesHistoricTradesApiResponse", endpoint, query_params) - - def historic_trades_v2(self, ticker, date, **query_params) -> models.HistoricTradesV2ApiResponse: - endpoint = f"{self.url}/v2/ticks/stocks/trades/{ticker}/{date}" - return self._handle_response("HistoricTradesV2ApiResponse", endpoint, query_params) - - def stocks_equities_historic_quotes(self, symbol, date, - **query_params) -> models.StocksEquitiesHistoricQuotesApiResponse: - endpoint = f"{self.url}/v1/historic/quotes/{symbol}/{date}" - return self._handle_response("StocksEquitiesHistoricQuotesApiResponse", endpoint, query_params) - - def historic_n___bbo_quotes_v2(self, ticker, date, **query_params) -> models.HistoricNBboQuotesV2ApiResponse: - endpoint = f"{self.url}/v2/ticks/stocks/nbbo/{ticker}/{date}" - return self._handle_response("HistoricNBboQuotesV2ApiResponse", endpoint, query_params) - - def stocks_equities_last_trade_for_a_symbol(self, symbol, - **query_params) -> models.StocksEquitiesLastTradeForASymbolApiResponse: - endpoint = f"{self.url}/v1/last/stocks/{symbol}" - return self._handle_response("StocksEquitiesLastTradeForASymbolApiResponse", endpoint, query_params) - - def stocks_equities_last_quote_for_a_symbol(self, symbol, - **query_params) -> models.StocksEquitiesLastQuoteForASymbolApiResponse: - endpoint = f"{self.url}/v1/last_quote/stocks/{symbol}" - return self._handle_response("StocksEquitiesLastQuoteForASymbolApiResponse", endpoint, query_params) - - def stocks_equities_daily_open_close(self, symbol, date, - **query_params) -> models.StocksEquitiesDailyOpenCloseApiResponse: - endpoint = f"{self.url}/v1/open-close/{symbol}/{date}" - return self._handle_response("StocksEquitiesDailyOpenCloseApiResponse", endpoint, query_params) - - def stocks_equities_condition_mappings(self, ticktype, - **query_params) -> models.StocksEquitiesConditionMappingsApiResponse: - endpoint = f"{self.url}/v1/meta/conditions/{ticktype}" - return self._handle_response("StocksEquitiesConditionMappingsApiResponse", endpoint, query_params) - - def stocks_equities_snapshot_all_tickers(self, - **query_params) -> models.StocksEquitiesSnapshotAllTickersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/us/markets/stocks/tickers" - return self._handle_response("StocksEquitiesSnapshotAllTickersApiResponse", endpoint, query_params) - - def stocks_equities_snapshot_single_ticker(self, ticker, - **query_params) -> models.StocksEquitiesSnapshotSingleTickerApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/us/markets/stocks/tickers/{ticker}" - return self._handle_response("StocksEquitiesSnapshotSingleTickerApiResponse", endpoint, query_params) - - def stocks_equities_snapshot_gainers_losers(self, direction, - **query_params) -> models.StocksEquitiesSnapshotGainersLosersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/us/markets/stocks/{direction}" - return self._handle_response("StocksEquitiesSnapshotGainersLosersApiResponse", endpoint, query_params) - - def stocks_equities_previous_close(self, ticker, **query_params) -> models.StocksEquitiesPreviousCloseApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/prev" - return self._handle_response("StocksEquitiesPreviousCloseApiResponse", endpoint, query_params) - - def stocks_equities_aggregates(self, ticker, multiplier, timespan, from_, to, - **query_params) -> models.StocksEquitiesAggregatesApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" - return self._handle_response("StocksEquitiesAggregatesApiResponse", endpoint, query_params) - - def stocks_equities_grouped_daily(self, locale, market, date, - **query_params) -> models.StocksEquitiesGroupedDailyApiResponse: - endpoint = f"{self.url}/v2/aggs/grouped/locale/{locale}/market/{market}/{date}" - return self._handle_response("StocksEquitiesGroupedDailyApiResponse", endpoint, query_params) - - def forex_currencies_historic_forex_ticks(self, from_, to, date, - **query_params) -> models.ForexCurrenciesHistoricForexTicksApiResponse: - endpoint = f"{self.url}/v1/historic/forex/{from_}/{to}/{date}" - return self._handle_response("ForexCurrenciesHistoricForexTicksApiResponse", endpoint, query_params) - - def forex_currencies_real_time_currency_conversion(self, from_, to, - **query_params) -> models.ForexCurrenciesRealTimeCurrencyConversionApiResponse: - endpoint = f"{self.url}/v1/conversion/{from_}/{to}" - return self._handle_response("ForexCurrenciesRealTimeCurrencyConversionApiResponse", endpoint, query_params) - - def forex_currencies_last_quote_for_a_currency_pair(self, from_, to, - **query_params) -> models.ForexCurrenciesLastQuoteForACurrencyPairApiResponse: - endpoint = f"{self.url}/v1/last_quote/currencies/{from_}/{to}" - return self._handle_response("ForexCurrenciesLastQuoteForACurrencyPairApiResponse", endpoint, query_params) - - def forex_currencies_grouped_daily(self, date, **query_params) -> models.ForexCurrenciesGroupedDailyApiResponse: - endpoint = f"{self.url}/v2/aggs/grouped/locale/global/market/fx/{date}" - return self._handle_response("ForexCurrenciesGroupedDailyApiResponse", endpoint, query_params) - - def forex_currencies_previous_close(self, ticker, **query_params) -> models.ForexCurrenciesGroupedDailyApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/prev" - return self._handle_response("ForexCurrenciesPreviousCloseApiResponse", endpoint, query_params) - - def forex_currencies_snapshot_all_tickers(self, - **query_params) -> models.ForexCurrenciesSnapshotAllTickersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/forex/tickers" - return self._handle_response("ForexCurrenciesSnapshotAllTickersApiResponse", endpoint, query_params) - - def forex_currencies_snapshot_single_ticker(self, ticker, **query_params) -> models.ForexCurrenciesSnapshotSingleTickerApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/forex/tickers/{ticker}" - return self._handle_response("ForexCurrenciesSnapshotSingleTickerApiResponse", endpoint, query_params) - - def forex_currencies_snapshot_gainers_losers(self, direction, - **query_params) -> models.ForexCurrenciesSnapshotGainersLosersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/forex/{direction}" - return self._handle_response("ForexCurrenciesSnapshotGainersLosersApiResponse", endpoint, query_params) - - def forex_currencies_aggregates(self, ticker, multiplier, timespan, from_, to, - **query_params) -> models.CurrenciesAggregatesApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" - return self._handle_response("CurrenciesAggregatesApiResponse", endpoint, query_params) - - def crypto_crypto_exchanges(self, **query_params) -> models.CryptoCryptoExchangesApiResponse: - endpoint = f"{self.url}/v1/meta/crypto-exchanges" - return self._handle_response("CryptoCryptoExchangesApiResponse", endpoint, query_params) - - def crypto_last_trade_for_a_crypto_pair(self, from_, to, - **query_params) -> models.CryptoLastTradeForACryptoPairApiResponse: - endpoint = f"{self.url}/v1/last/crypto/{from_}/{to}" - return self._handle_response("CryptoLastTradeForACryptoPairApiResponse", endpoint, query_params) - - def crypto_daily_open_close(self, from_, to, date, **query_params) -> models.CryptoDailyOpenCloseApiResponse: - endpoint = f"{self.url}/v1/open-close/crypto/{from_}/{to}/{date}" - return self._handle_response("CryptoDailyOpenCloseApiResponse", endpoint, query_params) - - def crypto_aggregates(self, ticker, multiplier, timespan, from_, to, - **query_params) -> models.CurrenciesAggregatesApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" - return self._handle_response("CurrenciesAggregatesApiResponse", endpoint, query_params) - - def crypto_historic_crypto_trades(self, from_, to, date, - **query_params) -> models.CryptoHistoricCryptoTradesApiResponse: - endpoint = f"{self.url}/v1/historic/crypto/{from_}/{to}/{date}" - return self._handle_response("CryptoHistoricCryptoTradesApiResponse", endpoint, query_params) - - def crypto_grouped_daily(self, date, **query_params) -> models.CryptoGroupedDailyApiResponse: - endpoint = f"{self.url}/v2/aggs/grouped/locale/global/market/crypto/{date}" - return self._handle_response("CryptoGroupedDailyApiResponse", endpoint, query_params) - - def crypto_previous_close(self, ticker, **query_params) -> models.CryptoPreviousCloseApiResponse: - endpoint = f"{self.url}/v2/aggs/ticker/{ticker}/prev" - return self._handle_response("CryptoPreviousCloseApiResponse", endpoint, query_params) - - def crypto_snapshot_all_tickers(self, **query_params) -> models.CryptoSnapshotAllTickersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/crypto/tickers" - return self._handle_response("CryptoSnapshotAllTickersApiResponse", endpoint, query_params) - - def crypto_snapshot_single_ticker(self, ticker, **query_params) -> models.CryptoSnapshotSingleTickerApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/crypto/tickers/{ticker}" - return self._handle_response("CryptoSnapshotSingleTickerApiResponse", endpoint, query_params) - - def crypto_snapshot_single_ticker_full_book(self, ticker, - **query_params) -> models.CryptoSnapshotSingleTickerFullBookApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/crypto/tickers/{ticker}/book" - return self._handle_response("CryptoSnapshotSingleTickerFullBookApiResponse", endpoint, query_params) - - def crypto_snapshot_gainers_losers(self, direction, - **query_params) -> models.CryptoSnapshotGainersLosersApiResponse: - endpoint = f"{self.url}/v2/snapshot/locale/global/markets/crypto/{direction}" - return self._handle_response("CryptoSnapshotGainersLosersApiResponse", endpoint, query_params) diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 8afea378..a912d6cc 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -1,223 +1,12 @@ -from .definitions import LastTrade -from .definitions import LastQuote -from .definitions import HistTrade -from .definitions import Quote -from .definitions import Aggregate -from .definitions import Company -from .definitions import CompanyV3 -from .definitions import Address -from .definitions import Symbol -from .definitions import SymbolV3 -from .definitions import Dividend -from .definitions import News -from .definitions import NewsV2 -from .definitions import Publisher -from .definitions import Earning -from .definitions import Financial -from .definitions import Exchange -from .definitions import Error -from .definitions import NotFound -from .definitions import Conflict -from .definitions import Unauthorized -from .definitions import MarketStatus -from .definitions import MarketHoliday -from .definitions import AnalystRatings -from .definitions import RatingSection -from .definitions import CryptoTick -from .definitions import CryptoTickJson -from .definitions import CryptoExchange -from .definitions import CryptoSnapshotTicker -from .definitions import CryptoSnapshotBookItem -from .definitions import CryptoSnapshotTickerBook -from .definitions import CryptoSnapshotAgg -from .definitions import Forex -from .definitions import LastForexTrade -from .definitions import LastForexQuote -from .definitions import ForexAggregate -from .definitions import ForexSnapshotTicker -from .definitions import ForexSnapshotAgg -from .definitions import Ticker -from .definitions import Split -from .definitions import Financials -from .definitions import Trade -from .definitions import StocksSnapshotTicker -from .definitions import StocksSnapshotBookItem -from .definitions import StocksSnapshotTickerBook -from .definitions import StocksV2Trade -from .definitions import StocksV2NBBO -from .definitions import StocksSnapshotAgg -from .definitions import StocksSnapshotQuote -from .definitions import Aggv2 -from .definitions import AggResponse -from .definitions import ReferenceTickersApiResponse -from .definitions import ReferenceTickersV3ApiResponse -from .definitions import ReferenceTickerTypesApiResponse -from .definitions import ReferenceTickerDetailsApiResponse -from .definitions import ReferenceTickerDetailsV3ApiResponse -from .definitions import ReferenceTickerNewsApiResponse -from .definitions import ReferenceTickerNewsV2ApiResponse -from .definitions import ReferenceMarketsApiResponse -from .definitions import ReferenceLocalesApiResponse -from .definitions import ReferenceStockSplitsApiResponse -from .definitions import ReferenceStockDividendsApiResponse -from .definitions import ReferenceStockFinancialsApiResponse -from .definitions import ReferenceMarketStatusApiResponse -from .definitions import ReferenceMarketHolidaysApiResponse -from .definitions import StocksEquitiesExchangesApiResponse -from .definitions import StocksEquitiesHistoricTradesApiResponse -from .definitions import HistoricTradesV2ApiResponse -from .definitions import StocksEquitiesHistoricQuotesApiResponse -from .definitions import HistoricNBboQuotesV2ApiResponse -from .definitions import StocksEquitiesLastTradeForASymbolApiResponse -from .definitions import StocksEquitiesLastQuoteForASymbolApiResponse -from .definitions import StocksEquitiesDailyOpenCloseApiResponse -from .definitions import StocksEquitiesConditionMappingsApiResponse -from .definitions import StocksEquitiesSnapshotAllTickersApiResponse -from .definitions import StocksEquitiesSnapshotSingleTickerApiResponse -from .definitions import StocksEquitiesSnapshotGainersLosersApiResponse -from .definitions import StocksEquitiesPreviousCloseApiResponse -from .definitions import StocksEquitiesAggregatesApiResponse -from .definitions import StocksEquitiesGroupedDailyApiResponse -from .definitions import ForexCurrenciesHistoricForexTicksApiResponse -from .definitions import ForexCurrenciesRealTimeCurrencyConversionApiResponse -from .definitions import ForexCurrenciesLastQuoteForACurrencyPairApiResponse -from. definitions import ForexCurrenciesGroupedDailyApiResponse -from .definitions import ForexCurrenciesPreviousCloseApiResponse -from .definitions import ForexCurrenciesSnapshotAllTickersApiResponse -from .definitions import ForexCurrenciesSnapshotSingleTickerApiResponse -from .definitions import ForexCurrenciesSnapshotGainersLosersApiResponse -from .definitions import CryptoCryptoExchangesApiResponse -from .definitions import CryptoLastTradeForACryptoPairApiResponse -from .definitions import CryptoDailyOpenCloseApiResponse -from .definitions import CryptoHistoricCryptoTradesApiResponse -from .definitions import CryptoGroupedDailyApiResponse -from .definitions import CryptoPreviousCloseApiResponse -from .definitions import CryptoSnapshotAllTickersApiResponse -from .definitions import CryptoSnapshotSingleTickerApiResponse -from .definitions import CryptoSnapshotSingleTickerFullBookApiResponse -from .definitions import CryptoSnapshotGainersLosersApiResponse -from .definitions import CurrenciesAggregatesApiResponse -from .definitions import StockSymbol -from .definitions import ConditionTypeMap -from .definitions import SymbolTypeMap -from .definitions import TickerSymbol +from .aggs import * +from .trades import * +from enum import Enum +class Sort(Enum): + ASC = 'asc' + DESC = 'desc' -import typing +class Order(Enum): + ASC = 'asc' + DESC = 'desc' -from .definitions import Definition - - -AnyDefinition = typing.TypeVar("AnyDefinition", bound=Definition) - -# noinspection SpellCheckingInspection -name_to_class: typing.Dict[str, typing.Callable[[], typing.Type[AnyDefinition]]] = { - "LastTrade": LastTrade, - "LastQuote": LastQuote, - "HistTrade": HistTrade, - "Quote": Quote, - "Aggregate": Aggregate, - "Company": Company, - "CompanyV3": CompanyV3, - "Address": Address, - "Symbol": Symbol, - "Dividend": Dividend, - "News": News, - "NewsV2": NewsV2, - "Publisher": Publisher, - "Earning": Earning, - "Financial": Financial, - "Exchange": Exchange, - "Error": Error, - "NotFound": NotFound, - "Conflict": Conflict, - "Unauthorized": Unauthorized, - "MarketStatus": MarketStatus, - "MarketHoliday": MarketHoliday, - "AnalystRatings": AnalystRatings, - "RatingSection": RatingSection, - "CryptoTick": CryptoTick, - "CryptoTickJson": CryptoTickJson, - "CryptoExchange": CryptoExchange, - "CryptoSnapshotTicker": CryptoSnapshotTicker, - "CryptoSnapshotBookItem": CryptoSnapshotBookItem, - "CryptoSnapshotTickerBook": CryptoSnapshotTickerBook, - "CryptoSnapshotAgg": CryptoSnapshotAgg, - "Forex": Forex, - "LastForexTrade": LastForexTrade, - "LastForexQuote": LastForexQuote, - "ForexAggregate": ForexAggregate, - "ForexSnapshotTicker": ForexSnapshotTicker, - "ForexSnapshotAgg": ForexSnapshotAgg, - "Ticker": Ticker, - "Split": Split, - "Financials": Financials, - "Trade": Trade, - "StocksSnapshotTicker": StocksSnapshotTicker, - "StocksSnapshotBookItem": StocksSnapshotBookItem, - "StocksSnapshotTickerBook": StocksSnapshotTickerBook, - "StocksV2Trade": StocksV2Trade, - "StocksV2NBBO": StocksV2NBBO, - "StocksSnapshotAgg": StocksSnapshotAgg, - "StocksSnapshotQuote": StocksSnapshotQuote, - "Aggv2": Aggv2, - "AggResponse": AggResponse, - "ReferenceTickersApiResponse": ReferenceTickersApiResponse, - "ReferenceTickersV3ApiResponse": ReferenceTickersV3ApiResponse, - "ReferenceTickerTypesApiResponse": ReferenceTickerTypesApiResponse, - "ReferenceTickerDetailsApiResponse": ReferenceTickerDetailsApiResponse, - "ReferenceTickerDetailsV3ApiResponse": ReferenceTickerDetailsV3ApiResponse, - "ReferenceTickerNewsApiResponse": ReferenceTickerNewsApiResponse, - "ReferenceTickerNewsV2ApiResponse": ReferenceTickerNewsV2ApiResponse, - "ReferenceMarketsApiResponse": ReferenceMarketsApiResponse, - "ReferenceLocalesApiResponse": ReferenceLocalesApiResponse, - "ReferenceStockSplitsApiResponse": ReferenceStockSplitsApiResponse, - "ReferenceStockDividendsApiResponse": ReferenceStockDividendsApiResponse, - "ReferenceStockFinancialsApiResponse": ReferenceStockFinancialsApiResponse, - "ReferenceMarketStatusApiResponse": ReferenceMarketStatusApiResponse, - "ReferenceMarketHolidaysApiResponse": ReferenceMarketHolidaysApiResponse, - "StocksEquitiesExchangesApiResponse": StocksEquitiesExchangesApiResponse, - "StocksEquitiesHistoricTradesApiResponse": StocksEquitiesHistoricTradesApiResponse, - "HistoricTradesV2ApiResponse": HistoricTradesV2ApiResponse, - "StocksEquitiesHistoricQuotesApiResponse": StocksEquitiesHistoricQuotesApiResponse, - "HistoricNBboQuotesV2ApiResponse": HistoricNBboQuotesV2ApiResponse, - "StocksEquitiesLastTradeForASymbolApiResponse": StocksEquitiesLastTradeForASymbolApiResponse, - "StocksEquitiesLastQuoteForASymbolApiResponse": StocksEquitiesLastQuoteForASymbolApiResponse, - "StocksEquitiesDailyOpenCloseApiResponse": StocksEquitiesDailyOpenCloseApiResponse, - "StocksEquitiesConditionMappingsApiResponse": StocksEquitiesConditionMappingsApiResponse, - "StocksEquitiesSnapshotAllTickersApiResponse": StocksEquitiesSnapshotAllTickersApiResponse, - "StocksEquitiesSnapshotSingleTickerApiResponse": StocksEquitiesSnapshotSingleTickerApiResponse, - "StocksEquitiesSnapshotGainersLosersApiResponse": StocksEquitiesSnapshotGainersLosersApiResponse, - "StocksEquitiesPreviousCloseApiResponse": StocksEquitiesPreviousCloseApiResponse, - "StocksEquitiesAggregatesApiResponse": StocksEquitiesAggregatesApiResponse, - "StocksEquitiesGroupedDailyApiResponse": StocksEquitiesGroupedDailyApiResponse, - "ForexCurrenciesHistoricForexTicksApiResponse": ForexCurrenciesHistoricForexTicksApiResponse, - "ForexCurrenciesRealTimeCurrencyConversionApiResponse": ForexCurrenciesRealTimeCurrencyConversionApiResponse, - "ForexCurrenciesLastQuoteForACurrencyPairApiResponse": ForexCurrenciesLastQuoteForACurrencyPairApiResponse, - "ForexCurrenciesGroupedDailyApiResponse": ForexCurrenciesGroupedDailyApiResponse, - "ForexCurrenciesPreviousCloseApiResponse": ForexCurrenciesPreviousCloseApiResponse, - "ForexCurrenciesSnapshotAllTickersApiResponse": ForexCurrenciesSnapshotAllTickersApiResponse, - "ForexCurrenciesSnapshotSingleTickerApiResponse": ForexCurrenciesSnapshotSingleTickerApiResponse, - "ForexCurrenciesSnapshotGainersLosersApiResponse": ForexCurrenciesSnapshotGainersLosersApiResponse, - "CryptoCryptoExchangesApiResponse": CryptoCryptoExchangesApiResponse, - "CryptoLastTradeForACryptoPairApiResponse": CryptoLastTradeForACryptoPairApiResponse, - "CryptoDailyOpenCloseApiResponse": CryptoDailyOpenCloseApiResponse, - "CryptoHistoricCryptoTradesApiResponse": CryptoHistoricCryptoTradesApiResponse, - "CryptoGroupedDailyApiResponse": CryptoGroupedDailyApiResponse, - "CryptoPreviousCloseApiResponse": CryptoPreviousCloseApiResponse, - "CryptoSnapshotAllTickersApiResponse": CryptoSnapshotAllTickersApiResponse, - "CryptoSnapshotSingleTickerApiResponse": CryptoSnapshotSingleTickerApiResponse, - "CryptoSnapshotSingleTickerFullBookApiResponse": CryptoSnapshotSingleTickerFullBookApiResponse, - "CryptoSnapshotGainersLosersApiResponse": CryptoSnapshotGainersLosersApiResponse, - "CurrenciesAggregatesApiResponse": CurrenciesAggregatesApiResponse, - -} - -# noinspection SpellCheckingInspection -name_to_type = { - "StockSymbol": StockSymbol, - "ConditionTypeMap": ConditionTypeMap, - "SymbolTypeMap": SymbolTypeMap, - "TickerSymbol": TickerSymbol, - -} \ No newline at end of file diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py new file mode 100644 index 00000000..b303c21d --- /dev/null +++ b/polygon/rest/models/aggs.py @@ -0,0 +1,26 @@ +from dataclasses import dataclass + +@dataclass +class Agg: + open: float + high: float + low: float + close: float + volume: float + vwap: float + timestamp: int + transactions: int + + @staticmethod + def from_dict(d): + return Agg( + d['o'], + d['h'], + d['l'], + d['c'], + d['v'], + d['vw'], + d['t'], + d['n'] + ) + diff --git a/polygon/rest/models/definitions.py b/polygon/rest/models/definitions.py deleted file mode 100644 index c05b7cde..00000000 --- a/polygon/rest/models/definitions.py +++ /dev/null @@ -1,4180 +0,0 @@ -import keyword -from typing import List, Dict, Any - -from polygon.rest import models - - -class Definition: - _swagger_name_to_python: Dict[str, str] - _attribute_is_primitive: Dict[str, bool] - _attributes_to_types: Dict[str, Any] - - def unmarshal_json(self, input_json): - if isinstance(input_json, list): - list_attribute_name = list(self._swagger_name_to_python.values())[0] - if list_attribute_name in self._attributes_to_types: - list_type = self._attributes_to_types[list_attribute_name] - known_type = list_type.split("[")[1][:-1] - list_items = self._unmarshal_json_list(input_json, known_type) - else: - list_items = input_json - self.__setattr__(list_attribute_name, list_items) - return self - elif isinstance(input_json, dict): - self._unmarshal_json_object(input_json) - return self - elif isinstance(input_json, float) or isinstance(input_json, int): - return input_json - - @staticmethod - def _unmarshal_json_list(input_json, known_type): - items = [] - for item in input_json: - new_item = models.name_to_class[known_type]() - items.append(new_item._unmarshal_json_object(item)) - - return items - - def _unmarshal_json_object(self, input_json): - for key, value in input_json.items(): - if key in self._swagger_name_to_python: - attribute_name = self._swagger_name_to_python[key] - if not self._attribute_is_primitive[attribute_name]: - if attribute_name in self._attributes_to_types: - attribute_type = self._attributes_to_types[attribute_name] - if attribute_type in models.name_to_class: - model = models.name_to_class[attribute_type]() - value = model.unmarshal_json(input_json[key]) - else: - attribute_name = key + ('_' if keyword.iskeyword(key) else '') - - self.__setattr__(attribute_name, value) - return self - - -# noinspection SpellCheckingInspection -class LastTrade(Definition): - _swagger_name_to_python = { - "price": "price", - "size": "size", - "exchange": "exchange", - "cond1": "cond1", - "cond2": "cond2", - "cond3": "cond3", - "cond4": "cond4", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "price": True, - "size": True, - "exchange": True, - "cond1": True, - "cond2": True, - "cond3": True, - "cond4": True, - "timestamp": True, - - } - - _attributes_to_types = { - "price": "int", - "size": "int", - "exchange": "int", - "cond1": "int", - "cond2": "int", - "cond3": "int", - "cond4": "int", - "timestamp": "int", - - } - - def __init__(self): - self.price: int - self.size: int - self.exchange: int - self.cond1: int - self.cond2: int - self.cond3: int - self.cond4: int - self.timestamp: int - - -# noinspection SpellCheckingInspection -class LastQuote(Definition): - _swagger_name_to_python = { - "askprice": "askprice", - "asksize": "asksize", - "askexchange": "askexchange", - "bidprice": "bidprice", - "bidsize": "bidsize", - "bidexchange": "bidexchange", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "askprice": True, - "asksize": True, - "askexchange": True, - "bidprice": True, - "bidsize": True, - "bidexchange": True, - "timestamp": True, - - } - - _attributes_to_types = { - "askprice": "int", - "asksize": "int", - "askexchange": "int", - "bidprice": "int", - "bidsize": "int", - "bidexchange": "int", - "timestamp": "int", - - } - - def __init__(self): - self.askprice: int - self.asksize: int - self.askexchange: int - self.bidprice: int - self.bidsize: int - self.bidexchange: int - self.timestamp: int - - -# noinspection SpellCheckingInspection -class HistTrade(Definition): - _swagger_name_to_python = { - "condition1": "condition1", - "condition2": "condition2", - "condition3": "condition3", - "condition4": "condition4", - "exchange": "exchange", - "price": "price", - "size": "size", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "condition1": True, - "condition2": True, - "condition3": True, - "condition4": True, - "exchange": True, - "price": True, - "size": True, - "timestamp": True, - - } - - _attributes_to_types = { - "condition1": "int", - "condition2": "int", - "condition3": "int", - "condition4": "int", - "exchange": "str", - "price": "int", - "size": "int", - "timestamp": "str", - - } - - def __init__(self): - self.condition1: int - self.condition2: int - self.condition3: int - self.condition4: int - self.exchange: str - self.price: int - self.size: int - self.timestamp: str - - -# noinspection SpellCheckingInspection -class Quote(Definition): - _swagger_name_to_python = { - "c": "condition_of_this_quote", - "bE": "bid_exchange", - "aE": "ask_exchange", - "aP": "ask_price", - "bP": "bid_price", - "bS": "bid_size", - "aS": "ask_size", - "t": "timestamp_of_this_trade", - - } - - _attribute_is_primitive = { - "condition_of_this_quote": True, - "bid_exchange": True, - "ask_exchange": True, - "ask_price": True, - "bid_price": True, - "bid_size": True, - "ask_size": True, - "timestamp_of_this_trade": True, - - } - - _attributes_to_types = { - "condition_of_this_quote": "int", - "bid_exchange": "str", - "ask_exchange": "str", - "ask_price": "int", - "bid_price": "int", - "bid_size": "int", - "ask_size": "int", - "timestamp_of_this_trade": "int", - - } - - def __init__(self): - self.condition_of_this_quote: int - self.bid_exchange: str - self.ask_exchange: str - self.ask_price: int - self.bid_price: int - self.bid_size: int - self.ask_size: int - self.timestamp_of_this_trade: int - - -# noinspection SpellCheckingInspection -class Aggregate(Definition): - _swagger_name_to_python = { - "o": "open_price", - "c": "close_price", - "l": "low_price", - "h": "high_price", - "v": "total_volume_of_all_trades", - "k": "transactions", - "t": "timestamp_of_this_aggregation", - - } - - _attribute_is_primitive = { - "open_price": True, - "close_price": True, - "low_price": True, - "high_price": True, - "total_volume_of_all_trades": True, - "transactions": True, - "timestamp_of_this_aggregation": True, - - } - - _attributes_to_types = { - "open_price": "int", - "close_price": "int", - "low_price": "int", - "high_price": "int", - "total_volume_of_all_trades": "int", - "transactions": "int", - "timestamp_of_this_aggregation": "int", - - } - - def __init__(self): - self.open_price: int - self.close_price: int - self.low_price: int - self.high_price: int - self.total_volume_of_all_trades: int - self.transactions: int - self.timestamp_of_this_aggregation: int - - -# noinspection SpellCheckingInspection -class Company(Definition): - _swagger_name_to_python = { - "logo": "logo", - "exchange": "exchange", - "name": "name", - "symbol": "symbol", - "listdate": "listdate", - "cik": "cik", - "bloomberg": "bloomberg", - "figi": "figi", - "lei": "lei", - "sic": "sic", - "country": "country", - "industry": "industry", - "sector": "sector", - "marketcap": "marketcap", - "employees": "employees", - "phone": "phone", - "ceo": "ceo", - "url": "url", - "description": "description", - "similar": "similar", - "tags": "tags", - "updated": "updated", - - } - - _attribute_is_primitive = { - "logo": True, - "exchange": True, - "name": True, - "symbol": False, - "listdate": True, - "cik": True, - "bloomberg": True, - "figi": True, - "lei": True, - "sic": True, - "country": True, - "industry": True, - "sector": True, - "marketcap": True, - "employees": True, - "phone": True, - "ceo": True, - "url": True, - "description": True, - "similar": False, - "tags": False, - "updated": True, - - } - - _attributes_to_types = { - "logo": "str", - "exchange": "str", - "name": "str", - "symbol": "StockSymbol", - "listdate": "str", - "cik": "str", - "bloomberg": "str", - "figi": "str", - "lei": "str", - "sic": "float", - "country": "str", - "industry": "str", - "sector": "str", - "marketcap": "float", - "employees": "float", - "phone": "str", - "ceo": "str", - "url": "str", - "description": "str", - "similar": "List[StockSymbol]", - "tags": "List[str]", - "updated": "str", - - } - - def __init__(self): - self.logo: str - self.exchange: str - self.name: str - self.symbol: StockSymbol - self.listdate: str - self.cik: str - self.bloomberg: str - self.figi: str - self.lei: str - self.sic: float - self.country: str - self.industry: str - self.sector: str - self.marketcap: float - self.employees: float - self.phone: str - self.ceo: str - self.url: str - self.description: str - self.similar: List[StockSymbol] - self.tags: List[str] - self.updated: str - -class Address(Definition): - _swagger_name_to_python = { - "address1": "address1", - "city": "city", - "state": "state", - } - - _attributes_is_primitive = { - "address1": True, - "city": True, - "state": True, - } - - _attributes_to_types = { - "address1": "str", - "city": "str", - "state": "str", - } - - def __init__(self): - self.address1: str - self.city: str - self.state: str - - -# noinspection SpellCheckingInspection -class CompanyV3(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "name": "name", - "market": "market", - "locale": "locale", - "primary_exchange": "primary_exchange", - "type": "type", - "active": "active", - "currency_name": "currency_name", - "cik": "cik", - "composite_figi": "composite_figi", - "share_class_figi": "share_class_figi", - "last_updated_utc": "last_updated_utc", - "outstanding_shares": "outstanding_shares", - "market_cap": "market_cap", - "phone_number": "phone_number", - "address": "address", - "sic_code": "sic_code", - "sic_description": "sic_description", - } - - _attributes_is_primitive = { - "ticker": True, - "name": True, - "market": True, - "primary_exchange": True, - "type": True, - "active": True, - "currency_name": True, - "cik": True, - "composite_figi": True, - "share_class_figi": True, - "last_updated_utc": True, - "outstanding_shares": True, - "market_cap": True, - "phone_number": True, - "address": False, - "sic_code": True, - "sic_description": True, - } - - _attributes_to_types = { - "ticker": "str", - "name": "str", - "market": "str", - "primary_exchange": "str", - "type": "str", - "active": "bool", - "currency_name": "str", - "cik": "str", - "composite_figi": "str", - "share_class_figi": "str", - "last_updated_utc": "str", - "outstanding_shares": "int", - "market_cap": "int", - "phone_number": "str", - "address": "Address", - "sic_code": "str", - "sic_description": "str", - } - - def __init__(self): - self.ticker: str - self.name: str - self.market: str - self.primary_exchange: str - self.type: str - self.active: bool - self.currency_name: str - self.cik: str - self.composite_figi: str - self.share_class_figi: str - self.last_updated_utc: str - self.outstanding_shares: int - self.market_cap: int - self.phone_number: str - self.address: Address - self.sic_code: str - self.sic_description: str - -# noinspection SpellCheckingInspection -class Symbol(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "name": "name", - "type": "type", - "url": "url", - "updated": "updated", - "isOTC": "is___otc", - - } - - _attribute_is_primitive = { - "symbol": False, - "name": True, - "type": True, - "url": True, - "updated": True, - "is___otc": True, - - } - - _attributes_to_types = { - "symbol": "StockSymbol", - "name": "str", - "type": "str", - "url": "str", - "updated": "str", - "is___otc": "bool", - - } - - def __init__(self): - self.symbol: StockSymbol - self.name: str - self.type: str - self.url: str - self.updated: str - self.is___otc: bool - - -# noinspection SpellCheckingInspection -class SymbolV3(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "name": "name", - "market": "market", - "locale": "locale", - "primary_exchange": "primary_exchange", - "type": "type", - "active": "active", - "currency_name": "currency_name", - "cik": "cik", - "composite_figi": "composite_figi", - "share_class_figi": "share_class_figi", - "last_updated_utc": "last_updated_utc", - "delisted_utc": "delisted_utc", - } - - _attributes_is_primitive = { - "ticker": True, - "name": True, - "market": True, - "primary_exchange": True, - "type": True, - "active": True, - "currency_name": True, - "cik": True, - "composite_figi": True, - "share_class_figi": True, - "last_updated_utc": True, - "delisted_utc": True, - } - - _attributes_to_types = { - "ticker": "str", - "name": "str", - "market": "str", - "primary_exchange": "str", - "type": "str", - "active": "bool", - "currency_name": "str", - "cik": "str", - "composite_figi": "str", - "share_class_figi": "str", - "last_updated_utc": "str", - "delisted_utc": "str", - } - - def __init__(self): - self.ticker: str - self.name: str - self.market: str - self.primary_exchange: str - self.type: str - self.active: bool - self.currency_name: str - self.cik: str - self.composite_figi: str - self.share_class_figi: str - self.last_updated_utc: str - self.delisted_utc: str - -# noinspection SpellCheckingInspection -class Dividend(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "type": "type", - "exDate": "ex_date", - "paymentDate": "payment_date", - "recordDate": "record_date", - "declaredDate": "declared_date", - "amount": "amount", - "qualified": "qualified", - "flag": "flag", - - } - - _attribute_is_primitive = { - "symbol": False, - "type": True, - "ex_date": True, - "payment_date": True, - "record_date": True, - "declared_date": True, - "amount": True, - "qualified": True, - "flag": True, - - } - - _attributes_to_types = { - "symbol": "StockSymbol", - "type": "str", - "ex_date": "str", - "payment_date": "str", - "record_date": "str", - "declared_date": "str", - "amount": "float", - "qualified": "str", - "flag": "str", - - } - - def __init__(self): - self.symbol: StockSymbol - self.type: str - self.ex_date: str - self.payment_date: str - self.record_date: str - self.declared_date: str - self.amount: float - self.qualified: str - self.flag: str - - -# noinspection SpellCheckingInspection -class News(Definition): - _swagger_name_to_python = { - "symbols": "symbols", - "title": "title", - "url": "url", - "source": "source", - "summary": "summary", - "image": "image", - "timestamp": "timestamp", - "keywords": "keywords", - - } - - _attribute_is_primitive = { - "symbols": False, - "title": True, - "url": True, - "source": True, - "summary": True, - "image": True, - "timestamp": True, - "keywords": False, - - } - - _attributes_to_types = { - "symbols": "List[StockSymbol]", - "title": "str", - "url": "str", - "source": "str", - "summary": "str", - "image": "str", - "timestamp": "str", - "keywords": "List[str]", - - } - - def __init__(self): - self.symbols: List[StockSymbol] - self.title: str - self.url: str - self.source: str - self.summary: str - self.image: str - self.timestamp: str - self.keywords: List[str] - -class Publisher(Definition): - _swagger_name_to_python = { - "name": "name", - "logo_url": "logo_url", - "homepage_url": "homepage_url", - "favicon_url": "favicon_url", - } - - _attribute_is_primitive = { - "name": True, - "logo_url": True, - "homepage_url": True, - "favicon_url": True, - } - - _attributes_to_type = { - "name": "str", - "logo_url": "str", - "homepage_url": "str", - "favicon_url": "str", - } - - def __init__(self): - self.name: str - self.logo_url: str - self.homepage_url: str - self.favicon_url: str - - -# noinspection SpellCheckingInspection -class NewsV2(Definition): - _swagger_name_to_python = { - "id": "id", - "publisher": "publisher", - "title": "title", - "author": "author", - "published_utc": "published_utc", - "tickers": "tickers", - "amp_url": "amp_url", - "image_url": "image_url", - "description": "description", - "keywords": "keywords", - } - - _attribute_is_primitive = { - "id": True, - "publisher": False, - "title": True, - "author": True, - "published_utc": True, - "tickers": True, - "amp_url": True, - "image_url": True, - "description": True, - "keywords": True, - } - - _attributes_to_type = { - "id": "str", - "publisher": "Publisher", - "title": "str", - "author": "str", - "published_utc": "str", - "tickers": "List[str]", - "amp_url": "str", - "image_url": "str", - "description": "str", - "keywords": "str", - } - - def __init__(self): - self.id: str - self.publisher: Publisher - self.title: str - self.author: str - self.published_utc: str - self.tickers: List[str] - self.amp_url: str - self.image_url: str - self.description: str - self.keywords: str - -# noinspection SpellCheckingInspection -class Earning(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "EPSReportDate": "e___psrep_ortdate", - "EPSReportDateStr": "e___psrep_ort_datestr", - "fiscalPeriod": "fiscal_period", - "fiscalEndDate": "fiscal_en_ddate", - "actualEPS": "actual___eps", - "consensusEPS": "consensus___eps", - "estimatedEPS": "estimated___eps", - "announceTime": "announce_time", - "numberOfEstimates": "number_o_festimates", - "EPSSurpriseDollar": "e___pssurpr_isedollar", - "yearAgo": "year_ago", - "yearAgoChangePercent": "year_ag_ochan_gepercent", - "estimatedChangePercent": "estimated_chang_epercent", - - } - - _attribute_is_primitive = { - "symbol": True, - "e___psrep_ortdate": True, - "e___psrep_ort_datestr": True, - "fiscal_period": True, - "fiscal_en_ddate": True, - "actual___eps": True, - "consensus___eps": True, - "estimated___eps": True, - "announce_time": True, - "number_o_festimates": True, - "e___pssurpr_isedollar": True, - "year_ago": True, - "year_ag_ochan_gepercent": True, - "estimated_chang_epercent": True, - - } - - _attributes_to_types = { - "symbol": "str", - "e___psrep_ortdate": "str", - "e___psrep_ort_datestr": "str", - "fiscal_period": "str", - "fiscal_en_ddate": "str", - "actual___eps": "float", - "consensus___eps": "float", - "estimated___eps": "float", - "announce_time": "str", - "number_o_festimates": "float", - "e___pssurpr_isedollar": "float", - "year_ago": "float", - "year_ag_ochan_gepercent": "float", - "estimated_chang_epercent": "float", - - } - - def __init__(self): - self.symbol: str - self.e___psrep_ortdate: str - self.e___psrep_ort_datestr: str - self.fiscal_period: str - self.fiscal_en_ddate: str - self.actual___eps: float - self.consensus___eps: float - self.estimated___eps: float - self.announce_time: str - self.number_o_festimates: float - self.e___pssurpr_isedollar: float - self.year_ago: float - self.year_ag_ochan_gepercent: float - self.estimated_chang_epercent: float - - -# noinspection SpellCheckingInspection -class Financial(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "reportDate": "report_date", - "reportDateStr": "report_dat_estr", - "grossProfit": "gross_profit", - "costOfRevenue": "cost_o_frevenue", - "operatingRevenue": "operating_revenue", - "totalRevenue": "total_revenue", - "operatingIncome": "operating_income", - "netIncome": "net_income", - "researchAndDevelopment": "research_an_ddevelopment", - "operatingExpense": "operating_expense", - "currentAssets": "current_assets", - "totalAssets": "total_assets", - "totalLiabilities": "total_liabilities", - "currentCash": "current_cash", - "currentDebt": "current_debt", - "totalCash": "total_cash", - "totalDebt": "total_debt", - "shareholderEquity": "shareholder_equity", - "cashChange": "cash_change", - "cashFlow": "cash_flow", - "operatingGainsLosses": "operating_gain_slosses", - - } - - _attribute_is_primitive = { - "symbol": True, - "report_date": True, - "report_dat_estr": True, - "gross_profit": True, - "cost_o_frevenue": True, - "operating_revenue": True, - "total_revenue": True, - "operating_income": True, - "net_income": True, - "research_an_ddevelopment": True, - "operating_expense": True, - "current_assets": True, - "total_assets": True, - "total_liabilities": True, - "current_cash": True, - "current_debt": True, - "total_cash": True, - "total_debt": True, - "shareholder_equity": True, - "cash_change": True, - "cash_flow": True, - "operating_gain_slosses": True, - - } - - _attributes_to_types = { - "symbol": "str", - "report_date": "str", - "report_dat_estr": "str", - "gross_profit": "float", - "cost_o_frevenue": "float", - "operating_revenue": "float", - "total_revenue": "float", - "operating_income": "float", - "net_income": "float", - "research_an_ddevelopment": "float", - "operating_expense": "float", - "current_assets": "float", - "total_assets": "float", - "total_liabilities": "float", - "current_cash": "float", - "current_debt": "float", - "total_cash": "float", - "total_debt": "float", - "shareholder_equity": "float", - "cash_change": "float", - "cash_flow": "float", - "operating_gain_slosses": "float", - - } - - def __init__(self): - self.symbol: str - self.report_date: str - self.report_dat_estr: str - self.gross_profit: float - self.cost_o_frevenue: float - self.operating_revenue: float - self.total_revenue: float - self.operating_income: float - self.net_income: float - self.research_an_ddevelopment: float - self.operating_expense: float - self.current_assets: float - self.total_assets: float - self.total_liabilities: float - self.current_cash: float - self.current_debt: float - self.total_cash: float - self.total_debt: float - self.shareholder_equity: float - self.cash_change: float - self.cash_flow: float - self.operating_gain_slosses: float - - -# noinspection SpellCheckingInspection -class Exchange(Definition): - _swagger_name_to_python = { - "id": "i_d_of_the_exchange", - "type": "type", - "market": "market", - "mic": "mic", - "name": "name", - "tape": "tape", - - } - - _attribute_is_primitive = { - "i_d_of_the_exchange": True, - "type": True, - "market": True, - "mic": True, - "name": True, - "tape": True, - - } - - _attributes_to_types = { - "i_d_of_the_exchange": "float", - "type": "str", - "market": "str", - "mic": "str", - "name": "str", - "tape": "str", - - } - - def __init__(self): - self.i_d_of_the_exchange: float - self.type: str - self.market: str - self.mic: str - self.name: str - self.tape: str - - -# noinspection SpellCheckingInspection -class Error(Definition): - _swagger_name_to_python = { - "code": "code", - "message": "message", - "fields": "fields", - - } - - _attribute_is_primitive = { - "code": True, - "message": True, - "fields": True, - - } - - _attributes_to_types = { - "code": "int", - "message": "str", - "fields": "str", - - } - - def __init__(self): - self.code: int - self.message: str - self.fields: str - - -# noinspection SpellCheckingInspection -class NotFound(Definition): - _swagger_name_to_python = { - "message": "message", - - } - - _attribute_is_primitive = { - "message": True, - - } - - _attributes_to_types = { - "message": "str", - - } - - def __init__(self): - self.message: str - - -# noinspection SpellCheckingInspection -class Conflict(Definition): - _swagger_name_to_python = { - "message": "message", - - } - - _attribute_is_primitive = { - "message": True, - - } - - _attributes_to_types = { - "message": "str", - - } - - def __init__(self): - self.message: str - - -# noinspection SpellCheckingInspection -class Unauthorized(Definition): - _swagger_name_to_python = { - "message": "message", - - } - - _attribute_is_primitive = { - "message": True, - - } - - _attributes_to_types = { - "message": "str", - - } - - def __init__(self): - self.message: str - - -# noinspection SpellCheckingInspection -class MarketStatus(Definition): - _swagger_name_to_python = { - "market": "market", - "serverTime": "server_time", - "exchanges": "exchanges", - "currencies": "currencies", - - } - - _attribute_is_primitive = { - "market": True, - "server_time": True, - "exchanges": True, - "currencies": True, - - } - - _attributes_to_types = { - "market": "str", - "server_time": "str", - "exchanges": "Dict[str, str]", - "currencies": "Dict[str, str]", - - } - - def __init__(self): - self.market: str - self.server_time: str - self.exchanges: Dict[str, str] - self.currencies: Dict[str, str] - - -# noinspection SpellCheckingInspection -class MarketHoliday(Definition): - _swagger_name_to_python = { - "exchange": "exchange", - "name": "name", - "status": "status", - "date": "date", - "open": "open", - "close": "close", - - } - - _attribute_is_primitive = { - "exchange": True, - "name": True, - "status": True, - "date": True, - "open": True, - "close": True, - - } - - _attributes_to_types = { - "exchange": "str", - "name": "str", - "status": "str", - "date": "str", - "open": "str", - "close": "str", - - } - - def __init__(self): - self.exchange: str - self.name: str - self.status: str - self.date: str - self.open: str - self.close: str - - -# noinspection SpellCheckingInspection -class AnalystRatings(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "analysts": "analysts", - "change": "change", - "strongBuy": "strong_buy", - "buy": "buy", - "hold": "hold", - "sell": "sell", - "strongSell": "strong_sell", - "updated": "updated", - - } - - _attribute_is_primitive = { - "symbol": True, - "analysts": True, - "change": True, - "strong_buy": False, - "buy": False, - "hold": False, - "sell": False, - "strong_sell": False, - "updated": True, - - } - - _attributes_to_types = { - "symbol": "str", - "analysts": "float", - "change": "float", - "strong_buy": "RatingSection", - "buy": "RatingSection", - "hold": "RatingSection", - "sell": "RatingSection", - "strong_sell": "RatingSection", - "updated": "str", - - } - - def __init__(self): - self.symbol: str - self.analysts: float - self.change: float - self.strong_buy: RatingSection - self.buy: RatingSection - self.hold: RatingSection - self.sell: RatingSection - self.strong_sell: RatingSection - self.updated: str - - -# noinspection SpellCheckingInspection -class RatingSection(Definition): - _swagger_name_to_python = { - "current": "current", - "month1": "month1", - "month2": "month2", - "month3": "month3", - "month4": "month4", - "month5": "month5", - - } - - _attribute_is_primitive = { - "current": True, - "month1": True, - "month2": True, - "month3": True, - "month4": True, - "month5": True, - - } - - _attributes_to_types = { - "current": "float", - "month1": "float", - "month2": "float", - "month3": "float", - "month4": "float", - "month5": "float", - - } - - def __init__(self): - self.current: float - self.month1: float - self.month2: float - self.month3: float - self.month4: float - self.month5: float - - -# noinspection SpellCheckingInspection -class CryptoTick(Definition): - _swagger_name_to_python = { - "price": "price", - "size": "size", - "exchange": "exchange", - "conditions": "conditions", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "price": True, - "size": True, - "exchange": True, - "conditions": False, - "timestamp": True, - - } - - _attributes_to_types = { - "price": "int", - "size": "int", - "exchange": "int", - "conditions": "List[int]", - "timestamp": "int", - - } - - def __init__(self): - self.price: int - self.size: int - self.exchange: int - self.conditions: List[int] - self.timestamp: int - - -# noinspection SpellCheckingInspection -class CryptoTickJson(Definition): - _swagger_name_to_python = { - "p": "trade_price", - "s": "size_of_the_trade", - "x": "exchange_the_trade_occured_on", - "c": "c", - "t": "timestamp_of_this_trade", - - } - - _attribute_is_primitive = { - "trade_price": True, - "size_of_the_trade": True, - "exchange_the_trade_occured_on": True, - "c": False, - "timestamp_of_this_trade": True, - - } - - _attributes_to_types = { - "trade_price": "int", - "size_of_the_trade": "int", - "exchange_the_trade_occured_on": "int", - "c": "List[int]", - "timestamp_of_this_trade": "int", - - } - - def __init__(self): - self.trade_price: int - self.size_of_the_trade: int - self.exchange_the_trade_occured_on: int - self.c: List[int] - self.timestamp_of_this_trade: int - - -# noinspection SpellCheckingInspection -class CryptoExchange(Definition): - _swagger_name_to_python = { - "id": "i_d_of_the_exchange", - "type": "type", - "market": "market", - "name": "name", - "url": "url", - - } - - _attribute_is_primitive = { - "i_d_of_the_exchange": True, - "type": True, - "market": True, - "name": True, - "url": True, - - } - - _attributes_to_types = { - "i_d_of_the_exchange": "float", - "type": "str", - "market": "str", - "name": "str", - "url": "str", - - } - - def __init__(self): - self.i_d_of_the_exchange: float - self.type: str - self.market: str - self.name: str - self.url: str - - -# noinspection SpellCheckingInspection -class CryptoSnapshotTicker(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "day": "day", - "lastTrade": "last_trade", - "min": "min", - "prevDay": "prev_day", - "todaysChange": "todays_change", - "todaysChangePerc": "todays_chang_eperc", - "updated": "updated", - - } - - _attribute_is_primitive = { - "ticker": True, - "day": False, - "last_trade": False, - "min": False, - "prev_day": False, - "todays_change": True, - "todays_chang_eperc": True, - "updated": True, - - } - - _attributes_to_types = { - "ticker": "str", - "day": "CryptoSnapshotAgg", - "last_trade": "CryptoTickJson", - "min": "CryptoSnapshotAgg", - "prev_day": "CryptoSnapshotAgg", - "todays_change": "int", - "todays_chang_eperc": "int", - "updated": "int", - - } - - def __init__(self): - self.ticker: str - self.day: CryptoSnapshotAgg - self.last_trade: CryptoTickJson - self.min: CryptoSnapshotAgg - self.prev_day: CryptoSnapshotAgg - self.todays_change: int - self.todays_chang_eperc: int - self.updated: int - - -# noinspection SpellCheckingInspection -class CryptoSnapshotBookItem(Definition): - _swagger_name_to_python = { - "p": "price_of_this_book_level", - "x": "exchange_to_size_of_this_price_level", - - } - - _attribute_is_primitive = { - "price_of_this_book_level": True, - "exchange_to_size_of_this_price_level": True, - - } - - _attributes_to_types = { - "price_of_this_book_level": "int", - "exchange_to_size_of_this_price_level": "Dict[str, str]", - - } - - def __init__(self): - self.price_of_this_book_level: int - self.exchange_to_size_of_this_price_level: Dict[str, str] - - -# noinspection SpellCheckingInspection -class CryptoSnapshotTickerBook(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "bids": "bids", - "asks": "asks", - "bidCount": "bid_count", - "askCount": "ask_count", - "spread": "spread", - "updated": "updated", - - } - - _attribute_is_primitive = { - "ticker": True, - "bids": False, - "asks": False, - "bid_count": True, - "ask_count": True, - "spread": True, - "updated": True, - - } - - _attributes_to_types = { - "ticker": "str", - "bids": "List[CryptoSnapshotBookItem]", - "asks": "List[CryptoSnapshotBookItem]", - "bid_count": "int", - "ask_count": "int", - "spread": "int", - "updated": "int", - - } - - def __init__(self): - self.ticker: str - self.bids: List[CryptoSnapshotBookItem] - self.asks: List[CryptoSnapshotBookItem] - self.bid_count: int - self.ask_count: int - self.spread: int - self.updated: int - - -# noinspection SpellCheckingInspection -class CryptoSnapshotAgg(Definition): - _swagger_name_to_python = { - "c": "close_price", - "h": "high_price", - "l": "low_price", - "o": "open_price", - "v": "volume", - - } - - _attribute_is_primitive = { - "close_price": True, - "high_price": True, - "low_price": True, - "open_price": True, - "volume": True, - - } - - _attributes_to_types = { - "close_price": "int", - "high_price": "int", - "low_price": "int", - "open_price": "int", - "volume": "int", - - } - - def __init__(self): - self.close_price: int - self.high_price: int - self.low_price: int - self.open_price: int - self.volume: int - - -# noinspection SpellCheckingInspection -class Forex(Definition): - _swagger_name_to_python = { - "a": "ask_price", - "b": "bid_price", - "t": "timestamp_of_this_trade", - - } - - _attribute_is_primitive = { - "ask_price": True, - "bid_price": True, - "timestamp_of_this_trade": True, - - } - - _attributes_to_types = { - "ask_price": "int", - "bid_price": "int", - "timestamp_of_this_trade": "int", - - } - - def __init__(self): - self.ask_price: int - self.bid_price: int - self.timestamp_of_this_trade: int - - -# noinspection SpellCheckingInspection -class LastForexTrade(Definition): - _swagger_name_to_python = { - "price": "price", - "exchange": "exchange", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "price": True, - "exchange": True, - "timestamp": True, - - } - - _attributes_to_types = { - "price": "int", - "exchange": "int", - "timestamp": "int", - - } - - def __init__(self): - self.price: int - self.exchange: int - self.timestamp: int - - -# noinspection SpellCheckingInspection -class LastForexQuote(Definition): - _swagger_name_to_python = { - "ask": "ask", - "bid": "bid", - "exchange": "exchange", - "timestamp": "timestamp", - - } - - _attribute_is_primitive = { - "ask": True, - "bid": True, - "exchange": True, - "timestamp": True, - - } - - _attributes_to_types = { - "ask": "int", - "bid": "int", - "exchange": "int", - "timestamp": "int", - - } - - def __init__(self): - self.ask: int - self.bid: int - self.exchange: int - self.timestamp: int - - -# noinspection SpellCheckingInspection -class ForexAggregate(Definition): - _swagger_name_to_python = { - "o": "open_price", - "c": "close_price", - "l": "low_price", - "h": "high_price", - "v": "volume_of_all_trades", - "t": "timestamp_of_this_aggregation", - - } - - _attribute_is_primitive = { - "open_price": True, - "close_price": True, - "low_price": True, - "high_price": True, - "volume_of_all_trades": True, - "timestamp_of_this_aggregation": True, - - } - - _attributes_to_types = { - "open_price": "int", - "close_price": "int", - "low_price": "int", - "high_price": "int", - "volume_of_all_trades": "int", - "timestamp_of_this_aggregation": "int", - - } - - def __init__(self): - self.open_price: int - self.close_price: int - self.low_price: int - self.high_price: int - self.volume_of_all_trades: int - self.timestamp_of_this_aggregation: int - - -# noinspection SpellCheckingInspection -class ForexSnapshotTicker(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "day": "day", - "lastTrade": "last_trade", - "min": "min", - "prevDay": "prev_day", - "todaysChange": "todays_change", - "todaysChangePerc": "todays_chang_eperc", - "updated": "updated", - - } - - _attribute_is_primitive = { - "ticker": True, - "day": False, - "last_trade": False, - "min": False, - "prev_day": False, - "todays_change": True, - "todays_chang_eperc": True, - "updated": True, - - } - - _attributes_to_types = { - "ticker": "str", - "day": "ForexSnapshotAgg", - "last_trade": "Forex", - "min": "ForexSnapshotAgg", - "prev_day": "ForexSnapshotAgg", - "todays_change": "int", - "todays_chang_eperc": "int", - "updated": "int", - - } - - def __init__(self): - self.ticker: str - self.day: ForexSnapshotAgg - self.last_trade: Forex - self.min: ForexSnapshotAgg - self.prev_day: ForexSnapshotAgg - self.todays_change: int - self.todays_chang_eperc: int - self.updated: int - - -# noinspection SpellCheckingInspection -class ForexSnapshotAgg(Definition): - _swagger_name_to_python = { - "c": "close_price", - "h": "high_price", - "l": "low_price", - "o": "open_price", - "v": "volume", - - } - - _attribute_is_primitive = { - "close_price": True, - "high_price": True, - "low_price": True, - "open_price": True, - "volume": True, - - } - - _attributes_to_types = { - "close_price": "int", - "high_price": "int", - "low_price": "int", - "open_price": "int", - "volume": "int", - - } - - def __init__(self): - self.close_price: int - self.high_price: int - self.low_price: int - self.open_price: int - self.volume: int - - -# noinspection SpellCheckingInspection -class Ticker(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "name": "name", - "market": "market", - "locale": "locale", - "currency": "currency", - "active": "active", - "primaryExch": "primary_exch", - "url": "url", - "updated": "updated", - "attrs": "attrs", - "codes": "codes", - - } - - _attribute_is_primitive = { - "ticker": False, - "name": True, - "market": True, - "locale": True, - "currency": True, - "active": True, - "primary_exch": True, - "url": True, - "updated": True, - "attrs": True, - "codes": True, - - } - - _attributes_to_types = { - "ticker": "StockSymbol", - "name": "str", - "market": "str", - "locale": "str", - "currency": "str", - "active": "bool", - "primary_exch": "str", - "url": "str", - "updated": "str", - "attrs": "Dict[str, str]", - "codes": "Dict[str, str]", - - } - - def __init__(self): - self.ticker: StockSymbol - self.name: str - self.market: str - self.locale: str - self.currency: str - self.active: bool - self.primary_exch: str - self.url: str - self.updated: str - self.attrs: Dict[str, str] - self.codes: Dict[str, str] - - -# noinspection SpellCheckingInspection -class Split(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "exDate": "ex_date", - "paymentDate": "payment_date", - "recordDate": "record_date", - "declaredDate": "declared_date", - "ratio": "ratio", - "tofactor": "tofactor", - "forfactor": "forfactor", - - } - - _attribute_is_primitive = { - "ticker": False, - "ex_date": True, - "payment_date": True, - "record_date": True, - "declared_date": True, - "ratio": True, - "tofactor": True, - "forfactor": True, - - } - - _attributes_to_types = { - "ticker": "TickerSymbol", - "ex_date": "str", - "payment_date": "str", - "record_date": "str", - "declared_date": "str", - "ratio": "float", - "tofactor": "float", - "forfactor": "float", - - } - - def __init__(self): - self.ticker: TickerSymbol - self.ex_date: str - self.payment_date: str - self.record_date: str - self.declared_date: str - self.ratio: float - self.tofactor: float - self.forfactor: float - - -# noinspection SpellCheckingInspection -class Financials(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "period": "period", - "calendarDate": "calendar_date", - "reportPeriod": "report_period", - "updated": "updated", - "accumulatedOtherComprehensiveIncome": "accumulated_othe_rcomprehensi_veincome", - "assets": "assets", - "assetsAverage": "assets_average", - "assetsCurrent": "assets_current", - "assetTurnover": "asset_turnover", - "assetsNonCurrent": "assets_no_ncurrent", - "bookValuePerShare": "book_valu_ep_ershare", - "capitalExpenditure": "capital_expenditure", - "cashAndEquivalents": "cash_an_dequivalents", - "cashAndEquivalentsUSD": "cash_an_dequivalen___tsusd", - "costOfRevenue": "cost_o_frevenue", - "consolidatedIncome": "consolidated_income", - "currentRatio": "current_ratio", - "debtToEquityRatio": "debt_t_oequi_tyratio", - "debt": "debt", - "debtCurrent": "debt_current", - "debtNonCurrent": "debt_no_ncurrent", - "debtUSD": "debt___usd", - "deferredRevenue": "deferred_revenue", - "depreciationAmortizationAndAccretion": "depreciation_amortizatio_na_ndaccretion", - "deposits": "deposits", - "dividendYield": "dividend_yield", - "dividendsPerBasicCommonShare": "dividends_pe_rbas_iccom_monshare", - "earningBeforeInterestTaxes": "earning_befor_eintere_sttaxes", - "earningsBeforeInterestTaxesDepreciationAmortization": "earnings_befor_eintere_stta_xesdeprecia_tionamortization", - "EBITDAMargin": "e______bitdamargin", - "earningsBeforeInterestTaxesDepreciationAmortizationUSD": "earnings_befor_eintere_stta_xesdeprecia_tionamortiz___ationusd", - "earningBeforeInterestTaxesUSD": "earning_befor_eintere_stta___xesusd", - "earningsBeforeTax": "earnings_befor_etax", - "earningsPerBasicShare": "earnings_pe_rbas_icshare", - "earningsPerDilutedShare": "earnings_pe_rdilut_edshare", - "earningsPerBasicShareUSD": "earnings_pe_rbas_icsh___areusd", - "shareholdersEquity": "shareholders_equity", - "averageEquity": "average_equity", - "shareholdersEquityUSD": "shareholders_equit___yusd", - "enterpriseValue": "enterprise_value", - "enterpriseValueOverEBIT": "enterprise_valu_eov____erebit", - "enterpriseValueOverEBITDA": "enterprise_valu_eov______erebitda", - "freeCashFlow": "free_cas_hflow", - "freeCashFlowPerShare": "free_cas_hfl_ow_pershare", - "foreignCurrencyUSDExchangeRate": "foreign_currenc____yusdexc_hangerate", - "grossProfit": "gross_profit", - "grossMargin": "gross_margin", - "goodwillAndIntangibleAssets": "goodwill_an_dintangib_leassets", - "interestExpense": "interest_expense", - "investedCapital": "invested_capital", - "investedCapitalAverage": "invested_capita_laverage", - "inventory": "inventory", - "investments": "investments", - "investmentsCurrent": "investments_current", - "investmentsNonCurrent": "investments_no_ncurrent", - "totalLiabilities": "total_liabilities", - "currentLiabilities": "current_liabilities", - "liabilitiesNonCurrent": "liabilities_no_ncurrent", - "marketCapitalization": "market_capitalization", - "netCashFlow": "net_cas_hflow", - "netCashFlowBusinessAcquisitionsDisposals": "net_cas_hfl_owbusin_essacquisit_ionsdisposals", - "issuanceEquityShares": "issuance_equit_yshares", - "issuanceDebtSecurities": "issuance_deb_tsecurities", - "paymentDividendsOtherCashDistributions": "payment_dividend_soth_erc_ashdistributions", - "netCashFlowFromFinancing": "net_cas_hfl_owf_romfinancing", - "netCashFlowFromInvesting": "net_cas_hfl_owf_rominvesting", - "netCashFlowInvestmentAcquisitionsDisposals": "net_cas_hfl_owinvestm_entacquisit_ionsdisposals", - "netCashFlowFromOperations": "net_cas_hfl_owf_romoperations", - "effectOfExchangeRateChangesOnCash": "effect_o_fexchan_ger_atecha_n_gesoncash", - "netIncome": "net_income", - "netIncomeCommonStock": "net_incom_ecomm_onstock", - "netIncomeCommonStockUSD": "net_incom_ecomm_onst___ockusd", - "netLossIncomeFromDiscontinuedOperations": "net_los_sinco_mef_romdisconti_nuedoperations", - "netIncomeToNonControllingInterests": "net_incom_e_to_noncontrol_linginterests", - "profitMargin": "profit_margin", - "operatingExpenses": "operating_expenses", - "operatingIncome": "operating_income", - "tradeAndNonTradePayables": "trade_an_dn_ontr_adepayables", - "payoutRatio": "payout_ratio", - "priceToBookValue": "price_t_obo_okvalue", - "priceEarnings": "price_earnings", - "priceToEarningsRatio": "price_t_oearnin_gsratio", - "propertyPlantEquipmentNet": "property_plan_tequipme_ntnet", - "preferredDividendsIncomeStatementImpact": "preferred_dividend_sinco_mestatem_entimpact", - "sharePriceAdjustedClose": "share_pric_eadjust_edclose", - "priceSales": "price_sales", - "priceToSalesRatio": "price_t_osal_esratio", - "tradeAndNonTradeReceivables": "trade_an_dn_ontr_adereceivables", - "accumulatedRetainedEarningsDeficit": "accumulated_retaine_dearnin_gsdeficit", - "revenues": "revenues", - "revenuesUSD": "revenues___usd", - "researchAndDevelopmentExpense": "research_an_ddevelopme_ntexpense", - "returnOnAverageAssets": "return_o_navera_geassets", - "returnOnAverageEquity": "return_o_navera_geequity", - "returnOnInvestedCapital": "return_o_ninvest_edcapital", - "returnOnSales": "return_o_nsales", - "shareBasedCompensation": "share_base_dcompensation", - "sellingGeneralAndAdministrativeExpense": "selling_genera_la_ndadministrat_iveexpense", - "shareFactor": "share_factor", - "shares": "shares", - "weightedAverageShares": "weighted_averag_eshares", - "weightedAverageSharesDiluted": "weighted_averag_eshar_esdiluted", - "salesPerShare": "sales_pe_rshare", - "tangibleAssetValue": "tangible_asse_tvalue", - "taxAssets": "tax_assets", - "incomeTaxExpense": "income_ta_xexpense", - "taxLiabilities": "tax_liabilities", - "tangibleAssetsBookValuePerShare": "tangible_asset_sbo_okva_lu_epershare", - "workingCapital": "working_capital", - - } - - _attribute_is_primitive = { - "ticker": False, - "period": True, - "calendar_date": True, - "report_period": True, - "updated": True, - "accumulated_othe_rcomprehensi_veincome": True, - "assets": True, - "assets_average": True, - "assets_current": True, - "asset_turnover": True, - "assets_no_ncurrent": True, - "book_valu_ep_ershare": True, - "capital_expenditure": True, - "cash_an_dequivalents": True, - "cash_an_dequivalen___tsusd": True, - "cost_o_frevenue": True, - "consolidated_income": True, - "current_ratio": True, - "debt_t_oequi_tyratio": True, - "debt": True, - "debt_current": True, - "debt_no_ncurrent": True, - "debt___usd": True, - "deferred_revenue": True, - "depreciation_amortizatio_na_ndaccretion": True, - "deposits": True, - "dividend_yield": True, - "dividends_pe_rbas_iccom_monshare": True, - "earning_befor_eintere_sttaxes": True, - "earnings_befor_eintere_stta_xesdeprecia_tionamortization": True, - "e______bitdamargin": True, - "earnings_befor_eintere_stta_xesdeprecia_tionamortiz___ationusd": True, - "earning_befor_eintere_stta___xesusd": True, - "earnings_befor_etax": True, - "earnings_pe_rbas_icshare": True, - "earnings_pe_rdilut_edshare": True, - "earnings_pe_rbas_icsh___areusd": True, - "shareholders_equity": True, - "average_equity": True, - "shareholders_equit___yusd": True, - "enterprise_value": True, - "enterprise_valu_eov____erebit": True, - "enterprise_valu_eov______erebitda": True, - "free_cas_hflow": True, - "free_cas_hfl_ow_pershare": True, - "foreign_currenc____yusdexc_hangerate": True, - "gross_profit": True, - "gross_margin": True, - "goodwill_an_dintangib_leassets": True, - "interest_expense": True, - "invested_capital": True, - "invested_capita_laverage": True, - "inventory": True, - "investments": True, - "investments_current": True, - "investments_no_ncurrent": True, - "total_liabilities": True, - "current_liabilities": True, - "liabilities_no_ncurrent": True, - "market_capitalization": True, - "net_cas_hflow": True, - "net_cas_hfl_owbusin_essacquisit_ionsdisposals": True, - "issuance_equit_yshares": True, - "issuance_deb_tsecurities": True, - "payment_dividend_soth_erc_ashdistributions": True, - "net_cas_hfl_owf_romfinancing": True, - "net_cas_hfl_owf_rominvesting": True, - "net_cas_hfl_owinvestm_entacquisit_ionsdisposals": True, - "net_cas_hfl_owf_romoperations": True, - "effect_o_fexchan_ger_atecha_n_gesoncash": True, - "net_income": True, - "net_incom_ecomm_onstock": True, - "net_incom_ecomm_onst___ockusd": True, - "net_los_sinco_mef_romdisconti_nuedoperations": True, - "net_incom_e_to_noncontrol_linginterests": True, - "profit_margin": True, - "operating_expenses": True, - "operating_income": True, - "trade_an_dn_ontr_adepayables": True, - "payout_ratio": True, - "price_t_obo_okvalue": True, - "price_earnings": True, - "price_t_oearnin_gsratio": True, - "property_plan_tequipme_ntnet": True, - "preferred_dividend_sinco_mestatem_entimpact": True, - "share_pric_eadjust_edclose": True, - "price_sales": True, - "price_t_osal_esratio": True, - "trade_an_dn_ontr_adereceivables": True, - "accumulated_retaine_dearnin_gsdeficit": True, - "revenues": True, - "revenues___usd": True, - "research_an_ddevelopme_ntexpense": True, - "return_o_navera_geassets": True, - "return_o_navera_geequity": True, - "return_o_ninvest_edcapital": True, - "return_o_nsales": True, - "share_base_dcompensation": True, - "selling_genera_la_ndadministrat_iveexpense": True, - "share_factor": True, - "shares": True, - "weighted_averag_eshares": True, - "weighted_averag_eshar_esdiluted": True, - "sales_pe_rshare": True, - "tangible_asse_tvalue": True, - "tax_assets": True, - "income_ta_xexpense": True, - "tax_liabilities": True, - "tangible_asset_sbo_okva_lu_epershare": True, - "working_capital": True, - - } - - _attributes_to_types = { - "ticker": "TickerSymbol", - "period": "str", - "calendar_date": "str", - "report_period": "str", - "updated": "str", - "accumulated_othe_rcomprehensi_veincome": "int", - "assets": "int", - "assets_average": "int", - "assets_current": "int", - "asset_turnover": "int", - "assets_no_ncurrent": "int", - "book_valu_ep_ershare": "int", - "capital_expenditure": "int", - "cash_an_dequivalents": "int", - "cash_an_dequivalen___tsusd": "int", - "cost_o_frevenue": "int", - "consolidated_income": "int", - "current_ratio": "int", - "debt_t_oequi_tyratio": "int", - "debt": "int", - "debt_current": "int", - "debt_no_ncurrent": "int", - "debt___usd": "int", - "deferred_revenue": "int", - "depreciation_amortizatio_na_ndaccretion": "int", - "deposits": "int", - "dividend_yield": "int", - "dividends_pe_rbas_iccom_monshare": "int", - "earning_befor_eintere_sttaxes": "int", - "earnings_befor_eintere_stta_xesdeprecia_tionamortization": "int", - "e______bitdamargin": "int", - "earnings_befor_eintere_stta_xesdeprecia_tionamortiz___ationusd": "int", - "earning_befor_eintere_stta___xesusd": "int", - "earnings_befor_etax": "int", - "earnings_pe_rbas_icshare": "int", - "earnings_pe_rdilut_edshare": "int", - "earnings_pe_rbas_icsh___areusd": "int", - "shareholders_equity": "int", - "average_equity": "int", - "shareholders_equit___yusd": "int", - "enterprise_value": "int", - "enterprise_valu_eov____erebit": "int", - "enterprise_valu_eov______erebitda": "int", - "free_cas_hflow": "int", - "free_cas_hfl_ow_pershare": "int", - "foreign_currenc____yusdexc_hangerate": "int", - "gross_profit": "int", - "gross_margin": "int", - "goodwill_an_dintangib_leassets": "int", - "interest_expense": "int", - "invested_capital": "int", - "invested_capita_laverage": "int", - "inventory": "int", - "investments": "int", - "investments_current": "int", - "investments_no_ncurrent": "int", - "total_liabilities": "int", - "current_liabilities": "int", - "liabilities_no_ncurrent": "int", - "market_capitalization": "int", - "net_cas_hflow": "int", - "net_cas_hfl_owbusin_essacquisit_ionsdisposals": "int", - "issuance_equit_yshares": "int", - "issuance_deb_tsecurities": "int", - "payment_dividend_soth_erc_ashdistributions": "int", - "net_cas_hfl_owf_romfinancing": "int", - "net_cas_hfl_owf_rominvesting": "int", - "net_cas_hfl_owinvestm_entacquisit_ionsdisposals": "int", - "net_cas_hfl_owf_romoperations": "int", - "effect_o_fexchan_ger_atecha_n_gesoncash": "int", - "net_income": "int", - "net_incom_ecomm_onstock": "int", - "net_incom_ecomm_onst___ockusd": "int", - "net_los_sinco_mef_romdisconti_nuedoperations": "int", - "net_incom_e_to_noncontrol_linginterests": "int", - "profit_margin": "int", - "operating_expenses": "int", - "operating_income": "int", - "trade_an_dn_ontr_adepayables": "int", - "payout_ratio": "int", - "price_t_obo_okvalue": "int", - "price_earnings": "int", - "price_t_oearnin_gsratio": "int", - "property_plan_tequipme_ntnet": "int", - "preferred_dividend_sinco_mestatem_entimpact": "int", - "share_pric_eadjust_edclose": "int", - "price_sales": "int", - "price_t_osal_esratio": "int", - "trade_an_dn_ontr_adereceivables": "int", - "accumulated_retaine_dearnin_gsdeficit": "int", - "revenues": "int", - "revenues___usd": "int", - "research_an_ddevelopme_ntexpense": "int", - "return_o_navera_geassets": "int", - "return_o_navera_geequity": "int", - "return_o_ninvest_edcapital": "int", - "return_o_nsales": "int", - "share_base_dcompensation": "int", - "selling_genera_la_ndadministrat_iveexpense": "int", - "share_factor": "int", - "shares": "int", - "weighted_averag_eshares": "int", - "weighted_averag_eshar_esdiluted": "int", - "sales_pe_rshare": "int", - "tangible_asse_tvalue": "int", - "tax_assets": "int", - "income_ta_xexpense": "int", - "tax_liabilities": "int", - "tangible_asset_sbo_okva_lu_epershare": "int", - "working_capital": "int", - - } - - def __init__(self): - self.ticker: TickerSymbol - self.period: str - self.calendar_date: str - self.report_period: str - self.updated: str - self.accumulated_othe_rcomprehensi_veincome: int - self.assets: int - self.assets_average: int - self.assets_current: int - self.asset_turnover: int - self.assets_no_ncurrent: int - self.book_valu_ep_ershare: int - self.capital_expenditure: int - self.cash_an_dequivalents: int - self.cash_an_dequivalen___tsusd: int - self.cost_o_frevenue: int - self.consolidated_income: int - self.current_ratio: int - self.debt_t_oequi_tyratio: int - self.debt: int - self.debt_current: int - self.debt_no_ncurrent: int - self.debt___usd: int - self.deferred_revenue: int - self.depreciation_amortizatio_na_ndaccretion: int - self.deposits: int - self.dividend_yield: int - self.dividends_pe_rbas_iccom_monshare: int - self.earning_befor_eintere_sttaxes: int - self.earnings_befor_eintere_stta_xesdeprecia_tionamortization: int - self.e______bitdamargin: int - self.earnings_befor_eintere_stta_xesdeprecia_tionamortiz___ationusd: int - self.earning_befor_eintere_stta___xesusd: int - self.earnings_befor_etax: int - self.earnings_pe_rbas_icshare: int - self.earnings_pe_rdilut_edshare: int - self.earnings_pe_rbas_icsh___areusd: int - self.shareholders_equity: int - self.average_equity: int - self.shareholders_equit___yusd: int - self.enterprise_value: int - self.enterprise_valu_eov____erebit: int - self.enterprise_valu_eov______erebitda: int - self.free_cas_hflow: int - self.free_cas_hfl_ow_pershare: int - self.foreign_currenc____yusdexc_hangerate: int - self.gross_profit: int - self.gross_margin: int - self.goodwill_an_dintangib_leassets: int - self.interest_expense: int - self.invested_capital: int - self.invested_capita_laverage: int - self.inventory: int - self.investments: int - self.investments_current: int - self.investments_no_ncurrent: int - self.total_liabilities: int - self.current_liabilities: int - self.liabilities_no_ncurrent: int - self.market_capitalization: int - self.net_cas_hflow: int - self.net_cas_hfl_owbusin_essacquisit_ionsdisposals: int - self.issuance_equit_yshares: int - self.issuance_deb_tsecurities: int - self.payment_dividend_soth_erc_ashdistributions: int - self.net_cas_hfl_owf_romfinancing: int - self.net_cas_hfl_owf_rominvesting: int - self.net_cas_hfl_owinvestm_entacquisit_ionsdisposals: int - self.net_cas_hfl_owf_romoperations: int - self.effect_o_fexchan_ger_atecha_n_gesoncash: int - self.net_income: int - self.net_incom_ecomm_onstock: int - self.net_incom_ecomm_onst___ockusd: int - self.net_los_sinco_mef_romdisconti_nuedoperations: int - self.net_incom_e_to_noncontrol_linginterests: int - self.profit_margin: int - self.operating_expenses: int - self.operating_income: int - self.trade_an_dn_ontr_adepayables: int - self.payout_ratio: int - self.price_t_obo_okvalue: int - self.price_earnings: int - self.price_t_oearnin_gsratio: int - self.property_plan_tequipme_ntnet: int - self.preferred_dividend_sinco_mestatem_entimpact: int - self.share_pric_eadjust_edclose: int - self.price_sales: int - self.price_t_osal_esratio: int - self.trade_an_dn_ontr_adereceivables: int - self.accumulated_retaine_dearnin_gsdeficit: int - self.revenues: int - self.revenues___usd: int - self.research_an_ddevelopme_ntexpense: int - self.return_o_navera_geassets: int - self.return_o_navera_geequity: int - self.return_o_ninvest_edcapital: int - self.return_o_nsales: int - self.share_base_dcompensation: int - self.selling_genera_la_ndadministrat_iveexpense: int - self.share_factor: int - self.shares: int - self.weighted_averag_eshares: int - self.weighted_averag_eshar_esdiluted: int - self.sales_pe_rshare: int - self.tangible_asse_tvalue: int - self.tax_assets: int - self.income_ta_xexpense: int - self.tax_liabilities: int - self.tangible_asset_sbo_okva_lu_epershare: int - self.working_capital: int - - -# noinspection SpellCheckingInspection -class Trade(Definition): - _swagger_name_to_python = { - "c1": "condition_1_of_this_trade", - "c2": "condition_2_of_this_trade", - "c3": "condition_3_of_this_trade", - "c4": "condition_4_of_this_trade", - "e": "the_exchange_this_trade_happened_on", - "p": "price_of_the_trade", - "s": "size_of_the_trade", - "t": "timestamp_of_this_trade", - - } - - _attribute_is_primitive = { - "condition_1_of_this_trade": True, - "condition_2_of_this_trade": True, - "condition_3_of_this_trade": True, - "condition_4_of_this_trade": True, - "the_exchange_this_trade_happened_on": True, - "price_of_the_trade": True, - "size_of_the_trade": True, - "timestamp_of_this_trade": True, - - } - - _attributes_to_types = { - "condition_1_of_this_trade": "int", - "condition_2_of_this_trade": "int", - "condition_3_of_this_trade": "int", - "condition_4_of_this_trade": "int", - "the_exchange_this_trade_happened_on": "str", - "price_of_the_trade": "int", - "size_of_the_trade": "int", - "timestamp_of_this_trade": "int", - - } - - def __init__(self): - self.condition_1_of_this_trade: int - self.condition_2_of_this_trade: int - self.condition_3_of_this_trade: int - self.condition_4_of_this_trade: int - self.the_exchange_this_trade_happened_on: str - self.price_of_the_trade: int - self.size_of_the_trade: int - self.timestamp_of_this_trade: int - - -# noinspection SpellCheckingInspection -class StocksSnapshotTicker(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "day": "day", - "lastTrade": "last_trade", - "lastQuote": "last_quote", - "min": "min", - "prevDay": "prev_day", - "todaysChange": "todays_change", - "todaysChangePerc": "todays_chang_eperc", - "updated": "updated", - - } - - _attribute_is_primitive = { - "ticker": True, - "day": False, - "last_trade": False, - "last_quote": False, - "min": False, - "prev_day": False, - "todays_change": True, - "todays_chang_eperc": True, - "updated": True, - - } - - _attributes_to_types = { - "ticker": "str", - "day": "StocksSnapshotAgg", - "last_trade": "Trade", - "last_quote": "StocksSnapshotQuote", - "min": "StocksSnapshotAgg", - "prev_day": "StocksSnapshotAgg", - "todays_change": "int", - "todays_chang_eperc": "int", - "updated": "int", - - } - - def __init__(self): - self.ticker: str - self.day: StocksSnapshotAgg - self.last_trade: Trade - self.last_quote: StocksSnapshotQuote - self.min: StocksSnapshotAgg - self.prev_day: StocksSnapshotAgg - self.todays_change: int - self.todays_chang_eperc: int - self.updated: int - - -# noinspection SpellCheckingInspection -class StocksSnapshotBookItem(Definition): - _swagger_name_to_python = { - "p": "price_of_this_book_level", - "x": "exchange_to_size_of_this_price_level", - - } - - _attribute_is_primitive = { - "price_of_this_book_level": True, - "exchange_to_size_of_this_price_level": True, - - } - - _attributes_to_types = { - "price_of_this_book_level": "int", - "exchange_to_size_of_this_price_level": "Dict[str, str]", - - } - - def __init__(self): - self.price_of_this_book_level: int - self.exchange_to_size_of_this_price_level: Dict[str, str] - - -# noinspection SpellCheckingInspection -class StocksSnapshotTickerBook(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "bids": "bids", - "asks": "asks", - "bidCount": "bid_count", - "askCount": "ask_count", - "spread": "spread", - "updated": "updated", - - } - - _attribute_is_primitive = { - "ticker": True, - "bids": False, - "asks": False, - "bid_count": True, - "ask_count": True, - "spread": True, - "updated": True, - - } - - _attributes_to_types = { - "ticker": "str", - "bids": "List[StocksSnapshotBookItem]", - "asks": "List[StocksSnapshotBookItem]", - "bid_count": "int", - "ask_count": "int", - "spread": "int", - "updated": "int", - - } - - def __init__(self): - self.ticker: str - self.bids: List[StocksSnapshotBookItem] - self.asks: List[StocksSnapshotBookItem] - self.bid_count: int - self.ask_count: int - self.spread: int - self.updated: int - - -# noinspection SpellCheckingInspection -class StocksV2Trade(Definition): - _swagger_name_to_python = { - "T": "ticker_of_the_object", - "t": "nanosecond_accuracy_s__ip_unix_timestamp", - "y": "nanosecond_accuracy_participant_exchange_unix_timestamp", - "f": "nanosecond_accuracy_t__rf", - "q": "sequence_number", - "i": "trade_i_d", - "x": "exchange_i_d", - "s": "size_volume_of_the_trade", - "c": "c", - "p": "price_of_the_trade", - "z": "tape_where_trade_occured", - - } - - _attribute_is_primitive = { - "ticker_of_the_object": True, - "nanosecond_accuracy_s__ip_unix_timestamp": True, - "nanosecond_accuracy_participant_exchange_unix_timestamp": True, - "nanosecond_accuracy_t__rf": True, - "sequence_number": True, - "trade_i_d": True, - "exchange_i_d": True, - "size_volume_of_the_trade": True, - "c": False, - "price_of_the_trade": True, - "tape_where_trade_occured": True, - - } - - _attributes_to_types = { - "ticker_of_the_object": "str", - "nanosecond_accuracy_s__ip_unix_timestamp": "int", - "nanosecond_accuracy_participant_exchange_unix_timestamp": "int", - "nanosecond_accuracy_t__rf": "int", - "sequence_number": "int", - "trade_i_d": "str", - "exchange_i_d": "int", - "size_volume_of_the_trade": "int", - "c": "List[int]", - "price_of_the_trade": "int", - "tape_where_trade_occured": "int", - - } - - def __init__(self): - self.ticker_of_the_object: str - self.nanosecond_accuracy_s__ip_unix_timestamp: int - self.nanosecond_accuracy_participant_exchange_unix_timestamp: int - self.nanosecond_accuracy_t__rf: int - self.sequence_number: int - self.trade_i_d: str - self.exchange_i_d: int - self.size_volume_of_the_trade: int - self.c: List[int] - self.price_of_the_trade: int - self.tape_where_trade_occured: int - - -# noinspection SpellCheckingInspection -class StocksV2NBBO(Definition): - _swagger_name_to_python = { - "T": "ticker_of_the_object", - "t": "nanosecond_accuracy_s__ip_unix_timestamp", - "y": "nanosecond_accuracy_participant_exchange_unix_timestamp", - "f": "nanosecond_accuracy_t__rf", - "q": "sequence_number", - "c": "c", - "i": "i", - "p": "b__id_price", - "x": "b__id_exchange__id", - "s": "b__id_size", - "P": "a__sk_price", - "X": "a__sk_exchange__id", - "S": "a__sk_size", - "z": "tape_where_trade_occured", - - } - - _attribute_is_primitive = { - "ticker_of_the_object": True, - "nanosecond_accuracy_s__ip_unix_timestamp": True, - "nanosecond_accuracy_participant_exchange_unix_timestamp": True, - "nanosecond_accuracy_t__rf": True, - "sequence_number": True, - "c": False, - "i": False, - "b__id_price": True, - "b__id_exchange__id": True, - "b__id_size": True, - "a__sk_price": True, - "a__sk_exchange__id": True, - "a__sk_size": True, - "tape_where_trade_occured": True, - - } - - _attributes_to_types = { - "ticker_of_the_object": "str", - "nanosecond_accuracy_s__ip_unix_timestamp": "int", - "nanosecond_accuracy_participant_exchange_unix_timestamp": "int", - "nanosecond_accuracy_t__rf": "int", - "sequence_number": "int", - "c": "List[int]", - "i": "List[int]", - "b__id_price": "int", - "b__id_exchange__id": "int", - "b__id_size": "int", - "a__sk_price": "int", - "a__sk_exchange__id": "int", - "a__sk_size": "int", - "tape_where_trade_occured": "int", - - } - - def __init__(self): - self.ticker_of_the_object: str - self.nanosecond_accuracy_s__ip_unix_timestamp: int - self.nanosecond_accuracy_participant_exchange_unix_timestamp: int - self.nanosecond_accuracy_t__rf: int - self.sequence_number: int - self.c: List[int] - self.i: List[int] - self.b__id_price: int - self.b__id_exchange__id: int - self.b__id_size: int - self.a__sk_price: int - self.a__sk_exchange__id: int - self.a__sk_size: int - self.tape_where_trade_occured: int - - -# noinspection SpellCheckingInspection -class StocksSnapshotAgg(Definition): - _swagger_name_to_python = { - "c": "close_price", - "h": "high_price", - "l": "low_price", - "o": "open_price", - "v": "volume", - - } - - _attribute_is_primitive = { - "close_price": True, - "high_price": True, - "low_price": True, - "open_price": True, - "volume": True, - - } - - _attributes_to_types = { - "close_price": "int", - "high_price": "int", - "low_price": "int", - "open_price": "int", - "volume": "int", - - } - - def __init__(self): - self.close_price: int - self.high_price: int - self.low_price: int - self.open_price: int - self.volume: int - - -# noinspection SpellCheckingInspection -class StocksSnapshotQuote(Definition): - _swagger_name_to_python = { - "p": "bid_price", - "s": "bid_size_in_lots", - "P": "ask_price", - "S": "ask_size_in_lots", - "t": "last_updated_timestamp", - - } - - _attribute_is_primitive = { - "bid_price": True, - "bid_size_in_lots": True, - "ask_price": True, - "ask_size_in_lots": True, - "last_updated_timestamp": True, - - } - - _attributes_to_types = { - "bid_price": "int", - "bid_size_in_lots": "int", - "ask_price": "int", - "ask_size_in_lots": "int", - "last_updated_timestamp": "int", - - } - - def __init__(self): - self.bid_price: int - self.bid_size_in_lots: int - self.ask_price: int - self.ask_size_in_lots: int - self.last_updated_timestamp: int - - -# noinspection SpellCheckingInspection -class Aggv2(Definition): - _swagger_name_to_python = { - "T": "ticker_symbol", - "v": "volume", - "o": "open", - "c": "close", - "h": "high", - "l": "low", - "t": "unix_msec_timestamp", - "n": "number_of_items_in_aggregate_window", - - } - - _attribute_is_primitive = { - "ticker_symbol": True, - "volume": True, - "open": True, - "close": True, - "high": True, - "low": True, - "unix_msec_timestamp": True, - "number_of_items_in_aggregate_window": True, - - } - - _attributes_to_types = { - "ticker_symbol": "str", - "volume": "int", - "open": "int", - "close": "int", - "high": "int", - "low": "int", - "unix_msec_timestamp": "float", - "number_of_items_in_aggregate_window": "float", - - } - - def __init__(self): - self.ticker_symbol: str - self.volume: int - self.open: int - self.close: int - self.high: int - self.low: int - self.unix_msec_timestamp: float - self.number_of_items_in_aggregate_window: float - - -# noinspection SpellCheckingInspection -class AggResponse(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "status": "status", - "adjusted": "adjusted", - "queryCount": "query_count", - "resultsCount": "results_count", - "results": "results", - - } - - _attribute_is_primitive = { - "ticker": True, - "status": True, - "adjusted": True, - "query_count": True, - "results_count": True, - "results": False, - - } - - _attributes_to_types = { - "ticker": "str", - "status": "str", - "adjusted": "bool", - "query_count": "float", - "results_count": "float", - "results": "List[Aggv2]", - - } - - def __init__(self): - self.ticker: str - self.status: str - self.adjusted: bool - self.query_count: float - self.results_count: float - self.results: List[Aggv2] - - -# noinspection SpellCheckingInspection -class ReferenceTickersApiResponse(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - - } - - _attribute_is_primitive = { - "symbol": False, - - } - - _attributes_to_types = { - "symbol": "List[Symbol]", - - } - - def __init__(self): - self.symbol: List[Symbol] - - -# noinspection SpellCheckingInspection -class ReferenceTickersV3ApiResponse(Definition): - _swagger_name_to_python = { - "results": "results", - "status": "status", - "count": "count", - "next_url": "next_url", - } - - _attribute_is_primitive = { - "results": False, - "status": True, - "count": True, - "next_url": True, - } - - _attributes_to_types = { - "results": "List[SymbolV3]", - "status": "str", - "count": "float", - "next_url": "str", - } - - def __init__(self): - self.results: List[SymbolV3] - self.status: str - self.count: float - self.next_url: str - - -# noinspection SpellCheckingInspection -class ReferenceTickerTypesApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "results": True, - - } - - _attributes_to_types = { - "status": "str", - "results": "Dict[str, str]", - - } - - def __init__(self): - self.status: str - self.results: Dict[str, str] - - -# noinspection SpellCheckingInspection -class ReferenceTickerDetailsApiResponse(Definition): - _swagger_name_to_python = { - "company": "company", - - } - - _attribute_is_primitive = { - "company": False, - - } - - _attributes_to_types = { - "company": "Company", - - } - - def __init__(self): - self.company: Company - - -# noinspection SpellCheckingInspection -class ReferenceTickerDetailsV3ApiResponse(Definition): - _swagger_name_to_python = { - "results": "results", - "status": "status", - "count": "count", - } - - _attribute_is_primitive = { - "results": False, - "status": True, - "count": True, - } - - _attributes_to_types = { - "results": "List[CompanyV3]", - "status": "str", - "count": "float", - } - - def __init__(self): - self.results: List[CompanyV3] - self.status: str - self.count: float - - -# noinspection SpellCheckingInspection -class ReferenceTickerNewsApiResponse(Definition): - _swagger_name_to_python = { - "news": "news", - - } - - _attribute_is_primitive = { - "news": False, - - } - - _attributes_to_types = { - "news": "List[News]", - - } - - def __init__(self): - self.news: List[News] - - -# noinspection SpellCheckingInspection -class ReferenceTickerNewsV2ApiResponse(Definition): - _swagger_name_to_python = { - "results": "results", - "next_url": "next_url", - "status": "status", - "count": "count", - } - - _attribute_is_primitive = { - "results": False, - "next_url": True, - "status": True, - "count": True, - } - - _attributes_to_types = { - "results": "List[NewsV2]", - "next_url": "str", - "status": "str", - "count": "float", - } - - def __init__(self): - self.results: List[NewsV2] - self.next_url: str - self.status: str - self.count: float - - -# noinspection SpellCheckingInspection -class ReferenceMarketsApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "results": False, - - } - - _attributes_to_types = { - "status": "str", - "results": "List[Dict[str, str]]", - - } - - def __init__(self): - self.status: str - self.results: List[Dict[str, str]] - - -# noinspection SpellCheckingInspection -class ReferenceLocalesApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "results": False, - - } - - _attributes_to_types = { - "status": "str", - "results": "List[Dict[str, str]]", - - } - - def __init__(self): - self.status: str - self.results: List[Dict[str, str]] - - -# noinspection SpellCheckingInspection -class ReferenceStockSplitsApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "count": "count", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "count": True, - "results": False, - - } - - _attributes_to_types = { - "status": "str", - "count": "float", - "results": "List[Split]", - - } - - def __init__(self): - self.status: str - self.count: float - self.results: List[Split] - - -# noinspection SpellCheckingInspection -class ReferenceStockDividendsApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "count": "count", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "count": True, - "results": False, - - } - - _attributes_to_types = { - "status": "str", - "count": "float", - "results": "List[Dividend]", - - } - - def __init__(self): - self.status: str - self.count: float - self.results: List[Dividend] - - -# noinspection SpellCheckingInspection -class ReferenceStockFinancialsApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "count": "count", - "results": "results", - - } - - _attribute_is_primitive = { - "status": True, - "count": True, - "results": False, - - } - - _attributes_to_types = { - "status": "str", - "count": "float", - "results": "List[Financials]", - - } - - def __init__(self): - self.status: str - self.count: float - self.results: List[Financials] - - -# noinspection SpellCheckingInspection -class ReferenceMarketStatusApiResponse(Definition): - _swagger_name_to_python = { - "marketstatus": "marketstatus", - - } - - _attribute_is_primitive = { - "marketstatus": False, - - } - - _attributes_to_types = { - "marketstatus": "MarketStatus", - - } - - def __init__(self): - self.marketstatus: MarketStatus - - -# noinspection SpellCheckingInspection -class ReferenceMarketHolidaysApiResponse(Definition): - _swagger_name_to_python = { - "marketholiday": "marketholiday", - - } - - _attribute_is_primitive = { - "marketholiday": False, - - } - - _attributes_to_types = { - "marketholiday": "List[MarketHoliday]", - - } - - def __init__(self): - self.marketholiday: List[MarketHoliday] - - -# noinspection SpellCheckingInspection -class StocksEquitiesExchangesApiResponse(Definition): - _swagger_name_to_python = { - "exchange": "exchange", - - } - - _attribute_is_primitive = { - "exchange": False, - - } - - _attributes_to_types = { - "exchange": "List[Exchange]", - - } - - def __init__(self): - self.exchange: List[Exchange] - - -# noinspection SpellCheckingInspection -class StocksEquitiesHistoricTradesApiResponse(Definition): - _swagger_name_to_python = { - "day": "day", - "map": "map", - "msLatency": "ms_latency", - "status": "status", - "symbol": "symbol", - "ticks": "ticks", - - } - - _attribute_is_primitive = { - "day": True, - "map": True, - "ms_latency": True, - "status": True, - "symbol": True, - "ticks": False, - - } - - _attributes_to_types = { - "day": "str", - "map": "Dict[str, str]", - "ms_latency": "int", - "status": "str", - "symbol": "str", - "ticks": "List[Trade]", - - } - - def __init__(self): - self.day: str - self.map: Dict[str, str] - self.ms_latency: int - self.status: str - self.symbol: str - self.ticks: List[Trade] - - -# noinspection SpellCheckingInspection -class HistoricTradesV2ApiResponse(Definition): - _swagger_name_to_python = { - "results_count": "results_count", - "db_latency": "db_latency", - "success": "success", - "ticker": "ticker", - "results": "results", - - } - - _attribute_is_primitive = { - "results_count": True, - "db_latency": True, - "success": True, - "ticker": True, - "results": False, - - } - - _attributes_to_types = { - "results_count": "int", - "db_latency": "int", - "success": "bool", - "ticker": "str", - "results": "List[StocksV2Trade]", - - } - - def __init__(self): - self.results_count: int - self.db_latency: int - self.success: bool - self.ticker: str - self.results: List[StocksV2Trade] - - -# noinspection SpellCheckingInspection -class StocksEquitiesHistoricQuotesApiResponse(Definition): - _swagger_name_to_python = { - "day": "day", - "map": "map", - "msLatency": "ms_latency", - "status": "status", - "symbol": "symbol", - "ticks": "ticks", - - } - - _attribute_is_primitive = { - "day": True, - "map": True, - "ms_latency": True, - "status": True, - "symbol": True, - "ticks": False, - - } - - _attributes_to_types = { - "day": "str", - "map": "Dict[str, str]", - "ms_latency": "int", - "status": "str", - "symbol": "str", - "ticks": "List[Quote]", - - } - - def __init__(self): - self.day: str - self.map: Dict[str, str] - self.ms_latency: int - self.status: str - self.symbol: str - self.ticks: List[Quote] - - -# noinspection SpellCheckingInspection -class HistoricNBboQuotesV2ApiResponse(Definition): - _swagger_name_to_python = { - "results_count": "results_count", - "db_latency": "db_latency", - "success": "success", - "ticker": "ticker", - "results": "results", - - } - - _attribute_is_primitive = { - "results_count": True, - "db_latency": True, - "success": True, - "ticker": True, - "results": False, - - } - - _attributes_to_types = { - "results_count": "int", - "db_latency": "int", - "success": "bool", - "ticker": "str", - "results": "List[StocksV2NBBO]", - - } - - def __init__(self): - self.results_count: int - self.db_latency: int - self.success: bool - self.ticker: str - self.results: List[StocksV2NBBO] - - -# noinspection SpellCheckingInspection -class StocksEquitiesLastTradeForASymbolApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "symbol": "symbol", - "last": "last", - - } - - _attribute_is_primitive = { - "status": True, - "symbol": True, - "last": False, - - } - - _attributes_to_types = { - "status": "str", - "symbol": "str", - "last": "LastTrade", - - } - - def __init__(self): - self.status: str - self.symbol: str - self.last: LastTrade - - -# noinspection SpellCheckingInspection -class StocksEquitiesLastQuoteForASymbolApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "symbol": "symbol", - "last": "last", - - } - - _attribute_is_primitive = { - "status": True, - "symbol": True, - "last": False, - - } - - _attributes_to_types = { - "status": "str", - "symbol": "str", - "last": "LastQuote", - - } - - def __init__(self): - self.status: str - self.symbol: str - self.last: LastQuote - - -# noinspection SpellCheckingInspection -class StocksEquitiesDailyOpenCloseApiResponse(Definition): - _swagger_name_to_python = { - "from": "from_", - "symbol": "symbol", - "open": "open", - "high": "high", - "low": "low", - "close": "close", - "volume": "volume", - "afterHours": "after_hours", - "preMarket": "pre_market", - } - - _attribute_is_primitive = { - "from_": True, - "symbol": True, - "open": True, - "high": True, - "low": True, - "close": True, - "volume": True, - "after_hours": True, - "pre_market": True, - } - - _attributes_to_types = { - "from_": "str", - "symbol": "str", - "open": "float", - "high": "float", - "low": "float", - "close": "float", - "volume": "float", - "after_hours": "float", - "pre_market": "float", - } - - def __init__(self): - self.from_: str - self.symbol: str - self.open: float - self.high: float - self.low: float - self.close: float - self.volume: float - self.after_hours: float - self.pre_market: float - - -# noinspection SpellCheckingInspection -class StocksEquitiesConditionMappingsApiResponse(Definition): - _swagger_name_to_python = { - "conditiontypemap": "conditiontypemap", - - } - - _attribute_is_primitive = { - "conditiontypemap": False, - - } - - _attributes_to_types = { - "conditiontypemap": "ConditionTypeMap", - - } - - def __init__(self): - self.conditiontypemap: ConditionTypeMap - - -# noinspection SpellCheckingInspection -class StocksEquitiesSnapshotAllTickersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[StocksSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[StocksSnapshotTicker] - - -# noinspection SpellCheckingInspection -class StocksEquitiesSnapshotSingleTickerApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "ticker": "ticker", - - } - - _attribute_is_primitive = { - "status": True, - "ticker": False, - - } - - _attributes_to_types = { - "status": "str", - "ticker": "StocksSnapshotTicker", - - } - - def __init__(self): - self.status: str - self.ticker: StocksSnapshotTicker - - -# noinspection SpellCheckingInspection -class StocksEquitiesSnapshotGainersLosersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[StocksSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[StocksSnapshotTicker] - - -# noinspection SpellCheckingInspection -class StocksEquitiesPreviousCloseApiResponse(Definition): - _swagger_name_to_python = { - "aggresponse": "aggresponse", - - } - - _attribute_is_primitive = { - "aggresponse": False, - - } - - _attributes_to_types = { - "aggresponse": "AggResponse", - - } - - def __init__(self): - self.aggresponse: AggResponse - - -# noinspection SpellCheckingInspection -class StocksEquitiesAggregatesApiResponse(Definition): - _swagger_name_to_python = { - "aggresponse": "aggresponse", - - } - - _attribute_is_primitive = { - "aggresponse": False, - - } - - _attributes_to_types = { - "aggresponse": "AggResponse", - - } - - def __init__(self): - self.aggresponse: AggResponse - - -# noinspection SpellCheckingInspection -class StocksEquitiesGroupedDailyApiResponse(Definition): - _swagger_name_to_python = { - "aggresponse": "aggresponse", - - } - - _attribute_is_primitive = { - "aggresponse": False, - - } - - _attributes_to_types = { - "aggresponse": "AggResponse", - - } - - def __init__(self): - self.aggresponse: AggResponse - - -# noinspection SpellCheckingInspection -class CurrenciesAggregatesApiResponse(Definition): - _swagger_name_to_python = { - "aggresponse": "aggresponse", - - } - - _attribute_is_primitive = { - "aggresponse": False, - - } - - _attributes_to_types = { - "aggresponse": "AggResponse", - - } - - def __init__(self): - self.aggresponse: AggResponse - -# noinspection SpellCheckingInspection -class ForexCurrenciesHistoricForexTicksApiResponse(Definition): - _swagger_name_to_python = { - "day": "day", - "map": "map", - "msLatency": "ms_latency", - "status": "status", - "pair": "pair", - "ticks": "ticks", - - } - - _attribute_is_primitive = { - "day": True, - "map": True, - "ms_latency": True, - "status": True, - "pair": True, - "ticks": False, - - } - - _attributes_to_types = { - "day": "str", - "map": "Dict[str, str]", - "ms_latency": "int", - "status": "str", - "pair": "str", - "ticks": "List[Forex]", - - } - - def __init__(self): - self.day: str - self.map: Dict[str, str] - self.ms_latency: int - self.status: str - self.pair: str - self.ticks: List[Forex] - - -# noinspection SpellCheckingInspection -class ForexCurrenciesRealTimeCurrencyConversionApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "from": "from_", - "to": "to_currency_symbol", - "initialAmount": "initial_amount", - "converted": "converted", - "lastTrade": "last_trade", - "symbol": "symbol", - - } - - _attribute_is_primitive = { - "status": True, - "from_": True, - "to_currency_symbol": True, - "initial_amount": True, - "converted": True, - "last_trade": False, - "symbol": True, - - } - - _attributes_to_types = { - "status": "str", - "from_": "str", - "to_currency_symbol": "str", - "initial_amount": "float", - "converted": "float", - "last_trade": "LastForexTrade", - "symbol": "str", - - } - - def __init__(self): - self.status: str - self.from_: str - self.to_currency_symbol: str - self.initial_amount: float - self.converted: float - self.last_trade: LastForexTrade - self.symbol: str - - -# noinspection SpellCheckingInspection -class ForexCurrenciesLastQuoteForACurrencyPairApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "symbol": "symbol", - "last": "last", - - } - - _attribute_is_primitive = { - "status": True, - "symbol": True, - "last": False, - - } - - _attributes_to_types = { - "status": "str", - "symbol": "str", - "last": "LastForexQuote", - - } - - def __init__(self): - self.status: str - self.symbol: str - self.last: LastForexQuote - - -# noinspection SpellCheckingInspection -class ForexCurrenciesGroupedDailyApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "adjusted": "adjusted", - "queryCount": "queryCount", - "resultsCount": "resultsCount", - "results": "results", - } - - _attribute_is_primitive = { - "status": True, - "adjusted": True, - "queryCount": True, - "resultsCount": True, - "results": False, - } - - _attributes_to_types = { - "status": "str", - "adjusted": "bool", - "queryCount": "int", - "resultsCount": "int", - "results": "List[Aggv2]" - } - - def __init__(self): - self.status: str - self.adjusted: bool - self.queryCount: int - self.resultsCount: int - self.results: List[Aggv2] - - -# noinspection SpellCheckingInspection -class ForexCurrenciesPreviousCloseApiResponse(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "status": "status", - "adjusted": "adjusted", - "queryCount": "queryCount", - "resultsCount": "resultsCount", - "results": "results", - } - - _attribute_is_primitive = { - "ticker": True, - "status": True, - "adjusted": True, - "queryCount": True, - "resultsCount": True, - "results": False, - } - - _attributes_to_types = { - "ticker": "str", - "status": "str", - "adjusted": "bool", - "queryCount": "int", - "resultsCount": "int", - "results": "List[Aggv2]" - } - - def __init__(self): - self.ticker: str - self.status: str - self.adjusted: bool - self.queryCount: int - self.resultsCount: int - self.results: List[Aggv2] - - -# noinspection SpellCheckingInspection -class ForexCurrenciesSnapshotAllTickersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[ForexSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[ForexSnapshotTicker] - - -# noinspection SpellCheckingInspection -class ForexCurrenciesSnapshotSingleTickerApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "ticker": "ticker", - } - - _attribute_is_primitive = { - "status": True, - "ticker": False, - } - - _attributes_to_types = { - "status": "str", - "ticker": "ForexSnapshotTicker", - } - - def __init__(self): - self.status: str - self.ticker: ForexSnapshotTicker - - -# noinspection SpellCheckingInspection -class ForexCurrenciesSnapshotGainersLosersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[ForexSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[ForexSnapshotTicker] - - -# noinspection SpellCheckingInspection -class CryptoCryptoExchangesApiResponse(Definition): - _swagger_name_to_python = { - "cryptoexchange": "cryptoexchange", - - } - - _attribute_is_primitive = { - "cryptoexchange": False, - - } - - _attributes_to_types = { - "cryptoexchange": "List[CryptoExchange]", - - } - - def __init__(self): - self.cryptoexchange: List[CryptoExchange] - - -# noinspection SpellCheckingInspection -class CryptoLastTradeForACryptoPairApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "symbol": "symbol", - "last": "last", - "lastAverage": "last_average", - - } - - _attribute_is_primitive = { - "status": True, - "symbol": True, - "last": False, - "last_average": True, - - } - - _attributes_to_types = { - "status": "str", - "symbol": "str", - "last": "CryptoTick", - "last_average": "Dict[str, str]", - - } - - def __init__(self): - self.status: str - self.symbol: str - self.last: CryptoTick - self.last_average: Dict[str, str] - - -# noinspection SpellCheckingInspection -class CryptoDailyOpenCloseApiResponse(Definition): - _swagger_name_to_python = { - "symbol": "symbol", - "isUTC": "is___utc", - "day": "day", - "open": "open", - "close": "close", - "openTrades": "open_trades", - "closingTrades": "closing_trades", - - } - - _attribute_is_primitive = { - "symbol": True, - "is___utc": True, - "day": True, - "open": True, - "close": True, - "open_trades": False, - "closing_trades": False, - - } - - _attributes_to_types = { - "symbol": "str", - "is___utc": "bool", - "day": "str", - "open": "int", - "close": "int", - "open_trades": "List[CryptoTickJson]", - "closing_trades": "List[CryptoTickJson]", - - } - - def __init__(self): - self.symbol: str - self.is___utc: bool - self.day: str - self.open: int - self.close: int - self.open_trades: List[CryptoTickJson] - self.closing_trades: List[CryptoTickJson] - - -# noinspection SpellCheckingInspection -class CryptoHistoricCryptoTradesApiResponse(Definition): - _swagger_name_to_python = { - "day": "day", - "map": "map", - "msLatency": "ms_latency", - "status": "status", - "symbol": "symbol", - "ticks": "ticks", - - } - - _attribute_is_primitive = { - "day": True, - "map": True, - "ms_latency": True, - "status": True, - "symbol": True, - "ticks": False, - - } - - _attributes_to_types = { - "day": "str", - "map": "Dict[str, str]", - "ms_latency": "int", - "status": "str", - "symbol": "str", - "ticks": "List[CryptoTickJson]", - - } - - def __init__(self): - self.day: str - self.map: Dict[str, str] - self.ms_latency: int - self.status: str - self.symbol: str - self.ticks: List[CryptoTickJson] - - -# noinspection SpellCheckingInspection -class CryptoGroupedDailyApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "adjusted": "adjusted", - "queryCount": "queryCount", - "resultsCount": "resultsCount", - "results": "results", - } - - _attribute_is_primitive = { - "status": True, - "adjusted": True, - "queryCount": True, - "resultsCount": True, - "results": False, - } - - _attributes_to_types = { - "status": "str", - "adjusted": "bool", - "queryCount": "int", - "resultsCount": "int", - "results": "List[Aggv2]" - } - - def __init__(self): - self.status: str - self.adjusted: bool - self.queryCount: int - self.resultsCount: int - self.results: List[Aggv2] - - -# noinspection SpellCheckingInspection -class CryptoPreviousCloseApiResponse(Definition): - _swagger_name_to_python = { - "ticker": "ticker", - "status": "status", - "adjusted": "adjusted", - "queryCount": "queryCount", - "resultsCount": "resultsCount", - "results": "results", - } - - _attribute_is_primitive = { - "ticker": True, - "status": True, - "adjusted": True, - "queryCount": True, - "resultsCount": True, - "results": False, - } - - _attributes_to_types = { - "ticker": "str", - "status": "str", - "adjusted": "bool", - "queryCount": "int", - "resultsCount": "int", - "results": "List[Aggv2]" - } - - def __init__(self): - self.ticker: str - self.status: str - self.adjusted: bool - self.queryCount: int - self.resultsCount: int - self.results: List[Aggv2] - -# noinspection SpellCheckingInspection -class CryptoSnapshotAllTickersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[CryptoSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[CryptoSnapshotTicker] - - -# noinspection SpellCheckingInspection -class CryptoSnapshotSingleTickerApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "ticker": "ticker", - - } - - _attribute_is_primitive = { - "status": True, - "ticker": False, - - } - - _attributes_to_types = { - "status": "str", - "ticker": "CryptoSnapshotTicker", - - } - - def __init__(self): - self.status: str - self.ticker: CryptoSnapshotTicker - - -# noinspection SpellCheckingInspection -class CryptoSnapshotSingleTickerFullBookApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "data": "data", - - } - - _attribute_is_primitive = { - "status": True, - "data": False, - - } - - _attributes_to_types = { - "status": "str", - "data": "CryptoSnapshotTickerBook", - - } - - def __init__(self): - self.status: str - self.data: CryptoSnapshotTickerBook - - -# noinspection SpellCheckingInspection -class CryptoSnapshotGainersLosersApiResponse(Definition): - _swagger_name_to_python = { - "status": "status", - "tickers": "tickers", - - } - - _attribute_is_primitive = { - "status": True, - "tickers": False, - - } - - _attributes_to_types = { - "status": "str", - "tickers": "List[CryptoSnapshotTicker]", - - } - - def __init__(self): - self.status: str - self.tickers: List[CryptoSnapshotTicker] - - -StockSymbol = str -ConditionTypeMap = Dict[str, str] -SymbolTypeMap = Dict[str, str] -TickerSymbol = str diff --git a/polygon/rest/models/trades.py b/polygon/rest/models/trades.py new file mode 100644 index 00000000..a68991e7 --- /dev/null +++ b/polygon/rest/models/trades.py @@ -0,0 +1,23 @@ +from typing import Optional, List +from dataclasses import dataclass + +@dataclass +class Trade: + "Trade contains trade data for a specified ticker symbol." + conditions: Optional[List[int]] = None + correction: Optional[int] = None + exchange: Optional[int] = None + id: Optional[str] = None + participant_timestamp: Optional[int] = None + price: Optional[float] = None + sequence_number: Optional[int] = None + sip_timestamp: Optional[int] = None + size: Optional[float] = None + tape: Optional[int] = None + trf_id: Optional[int] = None + trf_timestamp: Optional[int] = None + + @staticmethod + def from_dict(d): + return Trade(**d) + diff --git a/polygon/rest/models/unmarshal.py b/polygon/rest/models/unmarshal.py deleted file mode 100644 index 720fe7c0..00000000 --- a/polygon/rest/models/unmarshal.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Type - -from polygon.rest import models - - -def unmarshal_json(response_type, resp_json) -> Type[models.AnyDefinition]: - obj = models.name_to_class[response_type]() - obj.unmarshal_json(resp_json) - return obj diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py new file mode 100644 index 00000000..55a36b23 --- /dev/null +++ b/polygon/rest/trades.py @@ -0,0 +1,41 @@ +from .base import BaseClient +from typing import Optional, Any, Dict, Union +from .models import Trade, Sort, Order + +# https://polygon.io/docs/stocks +class TradesClient(BaseClient): + def list_trades(self, + ticker: str, + timestamp: Optional[str]=None, + timestamp_lt: Optional[str]=None, + timestamp_lte: Optional[str]=None, + timestamp_gt: Optional[str]=None, + timestamp_gte: Optional[str]=None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]]=None, + raw: bool=False + ): + """ + Get trades for a ticker symbol in a given time range. + + :param ticker: The ticker symbol. + :param timestamp: Either a date with the format YYYY-MM-DD or a nanosecond timestamp. + :param timestamp_lt: Timestamp less than + :param timestamp_lte: Timestamp less than or equal to + :param timestamp_gt: Timestamp greater than + :param timestamp_gte: Timestamp greater than or equal to + :param limit: Limits the number of base aggregates queried to create the aggregate results. Max 50000 and Default 5000. Read more about how limit is used to calculate aggregate results in our article on Aggregate Data API Improvements. + :param sort: Sort the results by timestamp. asc will return results in ascending order (oldest at the top), desc will return results in descending order (newest at the top).The end of the aggregate time window. + :param order: Order results based on the sort field + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of aggregates + :rtype: List[Agg] + """ + url = f"/v3/trades/{ticker}" + + return self._paginate(path=url, params=self._get_params(self.list_trades, locals()), raw=raw, deserializer=Trade.from_dict) + + diff --git a/rest-example.py b/rest-example.py index a517db12..9e96f222 100644 --- a/rest-example.py +++ b/rest-example.py @@ -1,28 +1,13 @@ -import datetime - from polygon import RESTClient +from polygon.rest.models import Sort +c = RESTClient() -def ts_to_datetime(ts) -> str: - return datetime.datetime.fromtimestamp(ts / 1000.0).strftime('%Y-%m-%d %H:%M') - - -def main(): - key = "your api key" - - # RESTClient can be used as a context manager to facilitate closing the underlying http session - # https://requests.readthedocs.io/en/master/user/advanced/#session-objects - with RESTClient(key) as client: - from_ = "2019-01-01" - to = "2019-02-01" - resp = client.stocks_equities_aggregates("AAPL", 1, "minute", from_, to, unadjusted=False) - - print(f"Minute aggregates for {resp.ticker} between {from_} and {to}.") - - for result in resp.results: - dt = ts_to_datetime(result["t"]) - print(f"{dt}\n\tO: {result['o']}\n\tH: {result['h']}\n\tL: {result['l']}\n\tC: {result['c']} ") +aggs = c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") +print(aggs) +trades = [] +for t in c.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): + trades.append(t) +print(trades) -if __name__ == '__main__': - main() \ No newline at end of file From 6b4ee83dae96ecd93724d611e0b9c1fd83a38cc2 Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Mon, 25 Apr 2022 15:05:26 -0400 Subject: [PATCH 02/41] Add CI (#115) * remove websocket, add linters and github actions for PRs for them * ci tweak * tweak ci (2) * vera feedback * add GH_TOKEN permisions --- .drone.yml | 38 ---- .github/workflows/lint.yml | 33 +++ poetry.lock | 290 ++++++++++++++++++++++++++ polygon/__init__.py | 1 - polygon/rest/__init__.py | 2 +- polygon/rest/aggs.py | 22 +- polygon/rest/base.py | 57 +++-- polygon/rest/models/__init__.py | 11 +- polygon/rest/models/aggs.py | 13 +- polygon/rest/models/trades.py | 2 +- polygon/rest/trades.py | 26 ++- polygon/websocket/__init__.py | 1 - polygon/websocket/websocket_client.py | 111 ---------- pyproject.toml | 34 +++ requirements.txt | 19 -- rest-example.py | 1 - setup.py | 39 ---- tox.ini | 7 - websocket_example/polygon.py | 32 --- 19 files changed, 431 insertions(+), 308 deletions(-) delete mode 100644 .drone.yml create mode 100644 .github/workflows/lint.yml create mode 100644 poetry.lock delete mode 100644 polygon/websocket/__init__.py delete mode 100644 polygon/websocket/websocket_client.py create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 setup.py delete mode 100644 tox.ini delete mode 100644 websocket_example/polygon.py diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 178de444..00000000 --- a/.drone.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -kind: pipeline -type: docker -name: release - -platform: - os: linux - arch: amd64 - -steps: - - name: build - image: python:3.7.5-alpine - commands: - - python setup.py sdist bdist_wheel - environment: - VERSION: ${DRONE_TAG##v} - - - name: release - image: python:3.7.5 - commands: - - pip install --user --upgrade twine - - ./upload - environment: - PASSWORD: - from_secret: pypi_token - USERNAME: __token__ - -trigger: - event: - - tag - ref: - - refs/tags/v* - ---- -kind: signature -hmac: c5572884fdd2183d7c63100530974a649f4607ee18c813570741d7a63f31cfae - -... diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..a6c5edfc --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,33 @@ +name: lint +on: + push: + tags: + - v* + branches: + - v1 + pull_request: +permissions: + contents: read +jobs: + lint: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.7', '3.8', '3.9', '3.10'] + name: Lint ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Poetry + uses: abatilo/actions-poetry@v2.0.0 + - name: Install pypi deps + run: poetry install + - name: Style lint + run: poetry run black --check polygon + - name: Static lint + run: poetry run mypy polygon + if: always() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..9a99c7f0 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,290 @@ +[[package]] +name = "black" +version = "22.3.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.2" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "importlib-metadata" +version = "4.11.3" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] + +[[package]] +name = "mypy" +version = "0.942" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = ">=1.1.0" +typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "platformdirs" +version = "2.5.2" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "typed-ast" +version = "1.5.3" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "types-urllib3" +version = "1.26.13" +description = "Typing stubs for urllib3" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "typing-extensions" +version = "4.2.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.9" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "zipp" +version = "3.8.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.7" +content-hash = "a62d0ece01b486b99384a3b2e21392ef28d135fd7646ab98cdcfe4cb83ea52a9" + +[metadata.files] +black = [ + {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, + {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, + {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, + {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, + {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, + {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, + {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, + {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, + {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, + {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, + {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, + {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, + {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, + {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, + {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, + {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, + {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, + {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, +] +click = [ + {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, + {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +importlib-metadata = [ + {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, + {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, +] +mypy = [ + {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, + {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, + {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"}, + {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"}, + {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"}, + {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"}, + {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"}, + {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"}, + {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"}, + {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"}, + {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"}, + {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"}, + {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"}, + {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"}, + {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"}, + {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"}, + {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"}, + {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"}, + {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +platformdirs = [ + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, +] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +typed-ast = [ + {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"}, + {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"}, + {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"}, + {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"}, + {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"}, + {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"}, + {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"}, + {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"}, +] +types-urllib3 = [ + {file = "types-urllib3-1.26.13.tar.gz", hash = "sha256:40f8fb5e8cd7d57e8aefdee3fdd5e930aa1a1bb4179cdadd55226cea588af790"}, + {file = "types_urllib3-1.26.13-py3-none-any.whl", hash = "sha256:ff7500641824f881b2c7bde4cc57e6c3abf03d1e005bae83aca752e77213a5da"}, +] +typing-extensions = [ + {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, + {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, +] +urllib3 = [ + {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, + {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, +] +zipp = [ + {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, + {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, +] diff --git a/polygon/__init__.py b/polygon/__init__.py index 9eb4d89a..f87495cd 100644 --- a/polygon/__init__.py +++ b/polygon/__init__.py @@ -1,2 +1 @@ -from .websocket import WebSocketClient, STOCKS_CLUSTER, FOREX_CLUSTER, CRYPTO_CLUSTER from .rest import RESTClient diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 89861e3a..8f15daae 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,6 +1,6 @@ from .aggs import AggsClient from .trades import TradesClient + class RESTClient(AggsClient, TradesClient): pass - diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index b345d0e1..2d8e87d5 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -4,18 +4,19 @@ # https://polygon.io/docs/stocks class AggsClient(BaseClient): - def get_aggs(self, + def get_aggs( + self, ticker: str, multiplier: int, timespan: str, # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp from_: str, to: str, - adjusted: Optional[bool]=None, - sort: Optional[Union[str, Sort]]=None, - limit: Optional[int]=None, - params: Optional[Dict[str, Any]]=None, - raw: bool=False + adjusted: Optional[bool] = None, + sort: Optional[Union[str, Sort]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, ) -> List[Agg]: """ Get aggregate bars for a ticker over a given date range in custom time window sizes. @@ -35,5 +36,10 @@ def get_aggs(self, """ url = f"/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" - return self._get(path=url, params=self._get_params(self.get_aggs, locals()), resultKey="results", deserializer=Agg.from_dict, raw=raw) - + return self._get( + path=url, + params=self._get_params(self.get_aggs, locals()), + resultKey="results", + deserializer=Agg.from_dict, + raw=raw, + ) diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 2cbd985d..9349b251 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -5,43 +5,54 @@ from enum import Enum from typing import Optional, Any -base = 'https://api.polygon.io' +base = "https://api.polygon.io" env_key = "POLYGON_API_KEY" # https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html class BaseClient: def __init__( - self, - api_key: Optional[str] = os.getenv(env_key), - connect_timeout: float = 10.0, - read_timeout: float = 10.0, - num_pools: int = 10, - retries = 3, - base: str = base - ): + self, + api_key: Optional[str] = os.getenv(env_key), + connect_timeout: float = 10.0, + read_timeout: float = 10.0, + num_pools: int = 10, + retries=3, + base: str = base, + ): if api_key is None: - raise Exception(f"Must specify env var {env_key} or pass api_key in constructor") + raise Exception( + f"Must specify env var {env_key} or pass api_key in constructor" + ) self.API_KEY = api_key self.BASE = base # https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool - self.client = urllib3.PoolManager(num_pools=num_pools, headers={ - 'Authorization': 'Bearer ' + self.API_KEY - }) - self.timeout=urllib3.Timeout(connect=connect_timeout, read=read_timeout) + self.client = urllib3.PoolManager( + num_pools=num_pools, headers={"Authorization": "Bearer " + self.API_KEY} + ) + self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout) self.retries = retries def _decode(self, resp): - return json.loads(resp.data.decode('utf-8')) + return json.loads(resp.data.decode("utf-8")) - def _get(self, path: str, params: Optional[dict] = None, resultKey: Optional[str] = None, deserializer = None, raw: bool = False) -> Any: + def _get( + self, + path: str, + params: Optional[dict] = None, + resultKey: Optional[str] = None, + deserializer=None, + raw: bool = False, + ) -> Any: if params is None: params = {} params = {str(k): str(v) for k, v in params.items() if v is not None} - resp = self.client.request('GET', self.BASE + path, fields=params, retries=self.retries) + resp = self.client.request( + "GET", self.BASE + path, fields=params, retries=self.retries + ) if resp.status != 200: - raise Exception(resp.data.decode('utf-8')) + raise Exception(resp.data.decode("utf-8")) if raw: return resp @@ -50,7 +61,7 @@ def _get(self, path: str, params: Optional[dict] = None, resultKey: Optional[str if resultKey: obj = obj[resultKey] - + if deserializer: obj = [deserializer(o) for o in obj] @@ -63,7 +74,7 @@ def _get_params(self, fn, caller_locals): # https://docs.python.org/3.7/library/inspect.html#inspect.Signature for argname, v in inspect.signature(fn).parameters.items(): # https://docs.python.org/3.7/library/inspect.html#inspect.Parameter - if argname in ['params', 'raw']: + if argname in ["params", "raw"]: continue if v.default != v.empty: # timestamp_lt -> timestamp.lt @@ -77,14 +88,16 @@ def _get_params(self, fn, caller_locals): def _paginate(self, path: str, params: dict, raw: bool, deserializer): while True: - resp = self._get(path=path, params=params, deserializer=deserializer, raw=True) + resp = self._get( + path=path, params=params, deserializer=deserializer, raw=True + ) if raw: return resp decoded = self._decode(resp) for t in decoded["results"]: yield deserializer(t) if "next_url" in decoded: - path = decoded["next_url"].replace(self.BASE, '') + path = decoded["next_url"].replace(self.BASE, "") params = {} else: return diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index a912d6cc..90f8d0bc 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -2,11 +2,12 @@ from .trades import * from enum import Enum + class Sort(Enum): - ASC = 'asc' - DESC = 'desc' + ASC = "asc" + DESC = "desc" -class Order(Enum): - ASC = 'asc' - DESC = 'desc' +class Order(Enum): + ASC = "asc" + DESC = "desc" diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py index b303c21d..da48ee53 100644 --- a/polygon/rest/models/aggs.py +++ b/polygon/rest/models/aggs.py @@ -1,5 +1,6 @@ from dataclasses import dataclass + @dataclass class Agg: open: float @@ -13,14 +14,4 @@ class Agg: @staticmethod def from_dict(d): - return Agg( - d['o'], - d['h'], - d['l'], - d['c'], - d['v'], - d['vw'], - d['t'], - d['n'] - ) - + return Agg(d["o"], d["h"], d["l"], d["c"], d["v"], d["vw"], d["t"], d["n"]) diff --git a/polygon/rest/models/trades.py b/polygon/rest/models/trades.py index a68991e7..5fc7a1d5 100644 --- a/polygon/rest/models/trades.py +++ b/polygon/rest/models/trades.py @@ -1,6 +1,7 @@ from typing import Optional, List from dataclasses import dataclass + @dataclass class Trade: "Trade contains trade data for a specified ticker symbol." @@ -20,4 +21,3 @@ class Trade: @staticmethod def from_dict(d): return Trade(**d) - diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py index 55a36b23..2dc43da3 100644 --- a/polygon/rest/trades.py +++ b/polygon/rest/trades.py @@ -4,18 +4,19 @@ # https://polygon.io/docs/stocks class TradesClient(BaseClient): - def list_trades(self, + def list_trades( + self, ticker: str, - timestamp: Optional[str]=None, - timestamp_lt: Optional[str]=None, - timestamp_lte: Optional[str]=None, - timestamp_gt: Optional[str]=None, - timestamp_gte: Optional[str]=None, + timestamp: Optional[str] = None, + timestamp_lt: Optional[str] = None, + timestamp_lte: Optional[str] = None, + timestamp_gt: Optional[str] = None, + timestamp_gte: Optional[str] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, - params: Optional[Dict[str, Any]]=None, - raw: bool=False + params: Optional[Dict[str, Any]] = None, + raw: bool = False, ): """ Get trades for a ticker symbol in a given time range. @@ -36,6 +37,9 @@ def list_trades(self, """ url = f"/v3/trades/{ticker}" - return self._paginate(path=url, params=self._get_params(self.list_trades, locals()), raw=raw, deserializer=Trade.from_dict) - - + return self._paginate( + path=url, + params=self._get_params(self.list_trades, locals()), + raw=raw, + deserializer=Trade.from_dict, + ) diff --git a/polygon/websocket/__init__.py b/polygon/websocket/__init__.py deleted file mode 100644 index a0f9603a..00000000 --- a/polygon/websocket/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .websocket_client import WebSocketClient, STOCKS_CLUSTER, FOREX_CLUSTER, CRYPTO_CLUSTER diff --git a/polygon/websocket/websocket_client.py b/polygon/websocket/websocket_client.py deleted file mode 100644 index 3c046485..00000000 --- a/polygon/websocket/websocket_client.py +++ /dev/null @@ -1,111 +0,0 @@ -import signal -import threading -from typing import Optional, Callable - -import websocket - -STOCKS_CLUSTER = "stocks" -FOREX_CLUSTER = "forex" -CRYPTO_CLUSTER = "crypto" - - -class WebSocketClient: - DEFAULT_HOST = "socket.polygon.io" - - # TODO: Either an instance of the client couples 1:1 with the cluster or an instance of the Client couples 1:3 with - # the 3 possible clusters (I think I like client per, but then a problem is the user can make multiple clients for - # the same cluster and that's not desirable behavior, - # somehow keeping track with multiple Client instances will be the difficulty) - def __init__(self, cluster: str, auth_key: str, process_message: Optional[Callable[[str], None]] = None, - on_close: Optional[Callable[[websocket.WebSocketApp], None]] = None, - on_error: Optional[Callable[[websocket.WebSocketApp, str], None]] = None): - self._host = self.DEFAULT_HOST - self.url = f"wss://{self._host}/{cluster}" - self.ws: websocket.WebSocketApp = websocket.WebSocketApp(self.url, on_open=self._default_on_open(), - on_close=self._default_on_close, - on_error=self._default_on_error, - on_message=self._default_on_message()) - self.auth_key = auth_key - - self.process_message = process_message - self.ws.on_close = on_close - self.ws.on_error = on_error - - # being authenticated is an event that must occur before any other action is sent to the server - self._authenticated = threading.Event() - # self._run_thread is only set if the client is run asynchronously - self._run_thread: Optional[threading.Thread] = None - - # TODO: this probably isn't great design. - # If the user defines their own signal handler then this will gets overwritten. - # We still need to make sure that killing, terminating, interrupting the program closes the connection - signal.signal(signal.SIGINT, self._cleanup_signal_handler()) - signal.signal(signal.SIGTERM, self._cleanup_signal_handler()) - - def run(self): - self.ws.run_forever() - - def run_async(self): - self._run_thread = threading.Thread(target=self.run) - self._run_thread.start() - - def close_connection(self): - self.ws.close() - if self._run_thread: - self._run_thread.join() - - def subscribe(self, *params): - # TODO: make this a decorator or context manager - self._authenticated.wait() - - sub_message = '{"action":"subscribe","params":"%s"}' % self._format_params(params) - self.ws.send(sub_message) - - def unsubscribe(self, *params): - # TODO: make this a decorator or context manager - self._authenticated.wait() - - sub_message = '{"action":"unsubscribe","params":"%s"}' % self._format_params(params) - self.ws.send(sub_message) - - def _cleanup_signal_handler(self): - return lambda signalnum, frame: self.close_connection() - - def _authenticate(self, ws): - ws.send('{"action":"auth","params":"%s"}' % self.auth_key) - self._authenticated.set() - - @staticmethod - def _format_params(params): - return ",".join(params) - - @property - def process_message(self): - return self.__process_message - - @process_message.setter - def process_message(self, pm): - if pm: - self.__process_message = pm - self.ws.on_message = lambda ws, message: self.__process_message(message) - - def _default_on_message(self): - return lambda ws, message: self._default_process_message(message) - - @staticmethod - def _default_process_message(message): - print(message) - - def _default_on_open(self): - def f(ws): - self._authenticate(ws) - - return f - - @staticmethod - def _default_on_error(ws, error): - print("error:", error) - - @staticmethod - def _default_on_close(ws): - print("### closed ###") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..c351c6c2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,34 @@ +[tool.poetry] +name = "client-python" +version = "0.3.0" +description = "Official Polygon.io REST and Websocket client." +authors = ["polygon.io"] +license = "MIT" +homepage = "https://polygon.io" +repository = "https://github.com/polygon-io/client-python" +documentation = "https://polygon.io/docs" +keywords = [ + "polygon", + "free", + "rest", + "stock", + "market", + "data", + "api", + "polygon.io", + "websocket", + "client" +] + +[tool.poetry.dependencies] +python = "^3.7" +urllib3 = "^1.26.9" + +[tool.poetry.dev-dependencies] +black = "^22.3.0" +mypy = "^0.942" +types-urllib3 = "^1.26.13" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a62a3359..00000000 --- a/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -atomicwrites>=1.3.0 -attrs>=19.3.0 -certifi>=2019.9.11 -chardet>=3.0.4 -idna>=2.8 -importlib-metadata>=0.23 -more-itertools>=7.2.0 -packaging>=19.2 -pluggy>=0.13.0 -py>=1.8.0 -pyparsing>=2.4.4 -pytest>=5.2.2 -requests>=2.22.0 -six>=1.13.0 -urllib3>=1.25.6 -wcwidth>=0.1.7 -websocket-client>=0.56.0 -websockets>=8.0.2 -zipp>=0.6.0 diff --git a/rest-example.py b/rest-example.py index 9e96f222..96586835 100644 --- a/rest-example.py +++ b/rest-example.py @@ -10,4 +10,3 @@ for t in c.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): trades.append(t) print(trades) - diff --git a/setup.py b/setup.py deleted file mode 100644 index 45095315..00000000 --- a/setup.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -from setuptools import setup, find_packages - -import os -import sys - -version = os.getenv("VERSION") -if not version: - print("no version supplied") - sys.exit(1) - -def get_readme_md_contents(): - """read the contents of your README file""" - with open("README.md", encoding='utf-8') as f: - long_description = f.read() - return long_description - -setup( - name="polygon-api-client", - version=version, - description="Polygon API client", - long_description=get_readme_md_contents(), - long_description_content_type="text/markdown", - author_email="support@polygon.io", - url="https://github.com/polygon-io/client-python", - packages=find_packages(), - classifiers=[ - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Operating System :: OS Independent", - "Topic :: Office/Business :: Financial :: Investment" - ], - install_requires=[ - "websocket-client>=0.56.0", - "websockets>=8.0.2", - "requests>=2.22.0" - ] -) diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 8fa455ad..00000000 --- a/tox.ini +++ /dev/null @@ -1,7 +0,0 @@ -[tox] -envlist = py3 - -[testenv] -deps = -r requirements.txt -commands = pytest -passenv = API_KEY diff --git a/websocket_example/polygon.py b/websocket_example/polygon.py deleted file mode 100644 index 760a27c0..00000000 --- a/websocket_example/polygon.py +++ /dev/null @@ -1,32 +0,0 @@ -# Be sure to pip install polygon-api-client - -import time - -from polygon import WebSocketClient, STOCKS_CLUSTER - - -def my_custom_process_message(message): - print("this is my custom message processing", message) - - -def my_custom_error_handler(ws, error): - print("this is my custom error handler", error) - - -def my_custom_close_handler(ws): - print("this is my custom close handler") - - -def main(): - key = 'your api key' - my_client = WebSocketClient(STOCKS_CLUSTER, key, my_custom_process_message) - my_client.run_async() - - my_client.subscribe("T.MSFT", "T.AAPL", "T.AMD", "T.NVDA") - time.sleep(1) - - my_client.close_connection() - - -if __name__ == "__main__": - main() From 406549d8f55ab49bedb499fb3b12ab338b6a5d8c Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Tue, 26 Apr 2022 10:29:53 -0400 Subject: [PATCH 03/41] Add unittest (#116) * test harness * add httpretty * add poetry run to Makefile * add empty key * add comments * pass empty api key --- .github/workflows/lint.yml | 4 ++-- .github/workflows/test.yml | 30 ++++++++++++++++++++++++++++++ Makefile | 37 +++++++++++++++++++++++++++++++++++++ poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + tests/mocks.py | 22 ++++++++++++++++++++++ tests/test_aggs.py | 11 +++++++++++ 7 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 Makefile create mode 100644 tests/mocks.py create mode 100644 tests/test_aggs.py diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a6c5edfc..c9fc2fc4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,7 +27,7 @@ jobs: - name: Install pypi deps run: poetry install - name: Style lint - run: poetry run black --check polygon + run: make style - name: Static lint - run: poetry run mypy polygon + run: make static if: always() diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..a1afc865 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: unittest +on: + push: + tags: + - v* + branches: + - v1 + pull_request: +permissions: + contents: read +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.7', '3.8', '3.9', '3.10'] + name: Lint ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Poetry + uses: abatilo/actions-poetry@v2.0.0 + - name: Install pypi deps + run: poetry install + - name: Unit tests + run: make test diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..f6751664 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +.DEFAULT_GOAL := help +TARGET_MAX_CHAR_NUM := 20 + +GREEN := $(shell tput -Txterm setaf 2) +YELLOW := $(shell tput -Txterm setaf 3) +WHITE := $(shell tput -Txterm setaf 7) +RESET := $(shell tput -Txterm sgr0) + +.PHONY: help lint style static test + +## Show help +help: + @awk '/^[a-zA-Z\-_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf " ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + +## Check code style +style: + poetry run black polygon + +## Check static types +static: + poetry run mypy polygon + +## Check code style and static types +lint: style static + +## Run unit tests +test: + poetry run python -m unittest discover -s tests + diff --git a/poetry.lock b/poetry.lock index 9a99c7f0..7a9b6760 100644 --- a/poetry.lock +++ b/poetry.lock @@ -41,6 +41,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "httpretty" +version = "1.1.4" +description = "HTTP client mock for Python" +category = "dev" +optional = false +python-versions = ">=3" + [[package]] name = "importlib-metadata" version = "4.11.3" @@ -165,7 +173,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "a62d0ece01b486b99384a3b2e21392ef28d135fd7646ab98cdcfe4cb83ea52a9" +content-hash = "992b579a470d1662ac4e64e78155506ec2f8c31013124a4cbb43cf0625a2931c" [metadata.files] black = [ @@ -201,6 +209,9 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +httpretty = [ + {file = "httpretty-1.1.4.tar.gz", hash = "sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68"}, +] importlib-metadata = [ {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, diff --git a/pyproject.toml b/pyproject.toml index c351c6c2..98d3228f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ urllib3 = "^1.26.9" black = "^22.3.0" mypy = "^0.942" types-urllib3 = "^1.26.13" +httpretty = "^1.1.4" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/mocks.py b/tests/mocks.py new file mode 100644 index 00000000..ce35c718 --- /dev/null +++ b/tests/mocks.py @@ -0,0 +1,22 @@ +from polygon import RESTClient +import unittest +import httpretty + +mocks = [ + ( + "/v2/aggs/ticker/AAPL/range/1/day/2005-04-01/2005-04-04", + '{"ticker":"AAPL","queryCount":2,"resultsCount":2,"adjusted":true,"results":[{"v":6.42646396e+08,"vw":1.469,"o":1.5032,"c":1.4604,"h":1.5064,"l":1.4489,"t":1112331600000,"n":82132},{"v":5.78172308e+08,"vw":1.4589,"o":1.4639,"c":1.4675,"h":1.4754,"l":1.4343,"t":1112587200000,"n":65543}],"status":"OK","request_id":"12afda77aab3b1936c5fb6ef4241ae42","count":2}' + ) +] + +class BaseTest(unittest.TestCase): + setup = False + def setUp(self): + if self.setup: + return + httpretty.enable(verbose=True, allow_net_connect=False) + c = RESTClient("") + for m in mocks: + httpretty.register_uri(httpretty.GET, c.BASE + m[0], m[1]) + self.setup = True + diff --git a/tests/test_aggs.py b/tests/test_aggs.py new file mode 100644 index 00000000..f8c88cca --- /dev/null +++ b/tests/test_aggs.py @@ -0,0 +1,11 @@ +from polygon import RESTClient +from polygon.rest.models import Agg +from mocks import BaseTest + +class AggsTest(BaseTest): + def test_get_aggs(self): + c = RESTClient("") + aggs = c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") + expected = [Agg(open=1.5032, high=1.5064, low=1.4489, close=1.4604, volume=642646396.0, vwap=1.469, timestamp=1112331600000, transactions=82132), Agg(open=1.4639, high=1.4754, low=1.4343, close=1.4675, volume=578172308.0, vwap=1.4589, timestamp=1112587200000, transactions=65543)] + self.assertEqual(aggs, expected) + From 19926a97bc5b8fdf9e81a7b3ccf98517553da76a Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Tue, 26 Apr 2022 12:10:18 -0400 Subject: [PATCH 04/41] add better types (#118) --- polygon/rest/aggs.py | 3 ++- polygon/rest/models/aggs.py | 19 ++++++++++++++----- polygon/rest/trades.py | 5 +++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index 2d8e87d5..ccaa5187 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -1,6 +1,7 @@ from .base import BaseClient from typing import Optional, Any, Dict, List, Union from .models import Agg, Sort +from urllib3 import HTTPResponse # https://polygon.io/docs/stocks class AggsClient(BaseClient): @@ -17,7 +18,7 @@ def get_aggs( limit: Optional[int] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, - ) -> List[Agg]: + ) -> Union[List[Agg], HTTPResponse]: """ Get aggregate bars for a ticker over a given date range in custom time window sizes. diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py index da48ee53..bdaa311c 100644 --- a/polygon/rest/models/aggs.py +++ b/polygon/rest/models/aggs.py @@ -1,17 +1,26 @@ from dataclasses import dataclass - +from typing import Optional @dataclass class Agg: + timestamp: int open: float high: float low: float close: float volume: float - vwap: float - timestamp: int - transactions: int + vwap: Optional[float] + transactions: Optional[int] @staticmethod def from_dict(d): - return Agg(d["o"], d["h"], d["l"], d["c"], d["v"], d["vw"], d["t"], d["n"]) + return Agg( + timestamp=d["t"], + open=d["o"], + high=d["h"], + low=d["l"], + close=d["c"], + volume=d["v"], + vwap=d.get("vw", None), + transactions=d.get("n", None) + ) diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py index 2dc43da3..3d22476b 100644 --- a/polygon/rest/trades.py +++ b/polygon/rest/trades.py @@ -1,6 +1,7 @@ from .base import BaseClient -from typing import Optional, Any, Dict, Union +from typing import Optional, Any, Dict, Union, Iterator from .models import Trade, Sort, Order +from urllib3 import HTTPResponse # https://polygon.io/docs/stocks class TradesClient(BaseClient): @@ -17,7 +18,7 @@ def list_trades( order: Optional[Union[str, Order]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, - ): + ) -> Union[Iterator[Trade], HTTPResponse]: """ Get trades for a ticker symbol in a given time range. From c2c40be1866ded753af9727af29103dc6c869e43 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Tue, 26 Apr 2022 12:14:19 -0400 Subject: [PATCH 05/41] Quotes (#117) --- polygon/rest/__init__.py | 3 +- polygon/rest/models/__init__.py | 1 + polygon/rest/models/quotes.py | 61 ++++++++++++++++++++++++++++++ polygon/rest/quotes.py | 67 +++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 polygon/rest/models/quotes.py create mode 100644 polygon/rest/quotes.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 8f15daae..389c6c77 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,6 +1,7 @@ from .aggs import AggsClient from .trades import TradesClient +from .quotes import QuotesClient -class RESTClient(AggsClient, TradesClient): +class RESTClient(AggsClient, TradesClient, QuotesClient): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 90f8d0bc..41891552 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -1,5 +1,6 @@ from .aggs import * from .trades import * +from .quotes import * from enum import Enum diff --git a/polygon/rest/models/quotes.py b/polygon/rest/models/quotes.py new file mode 100644 index 00000000..fa2b4503 --- /dev/null +++ b/polygon/rest/models/quotes.py @@ -0,0 +1,61 @@ +from typing import Optional, List +from dataclasses import dataclass + + +@dataclass +class Quote: + "Quote contains quote data for a specified ticker symbol." + ask_exchange: Optional[int] = None + ask_price: Optional[float] = None + ask_size: Optional[float] = None + bid_exchange: Optional[int] = None + bid_price: Optional[float] = None + bid_size: Optional[float] = None + conditions: Optional[List[int]] = None + indicators: Optional[List[int]] = None + participant_timestamp: Optional[int] = None + sequence_number: Optional[int] = None + sip_timestamp: Optional[int] = None + tape: Optional[int] = None + trf_timestamp: Optional[int] = None + + @staticmethod + def from_dict(d): + return Quote(**d) + +@dataclass +class LastQuote: + "LastQuote contains data for the most recent NBBO (Quote) tick for a given stock." + ticker: Optional[str] = None + trf_timestamp: Optional[int] = None + sequence_number: Optional[int] = None + sip_timestamp: Optional[int] = None + participant_timestamp: Optional[int] = None + ask_price: Optional[float] = None + ask_size: Optional[int] = None + ask_exchange: Optional[int] = None + conditions: Optional[List[int]] = None + indicators: Optional[List[int]] = None + bid_price: Optional[float] = None + bid_size: Optional[int] = None + bid_exchange: Optional[int] = None + tape: Optional[int] = None + + @staticmethod + def from_dict(d): + return LastQuote( + ticker=d.get("T", None), + trf_timestamp=d.get("f", None), + sequence_number=d.get("q", None), + sip_timestamp=d.get("t", None), + participant_timestamp=d.get("y", None), + ask_price=d.get("P", None), + ask_size=d.get("S", None), + ask_exchange=d.get("X", None), + conditions=d.get("c", None), + indicators=d.get("i", None), + bid_price=d.get("p", None), + bid_size=d.get("s", None), + bid_exchange=d.get("x", None), + tape=d.get("z", None) + ) \ No newline at end of file diff --git a/polygon/rest/quotes.py b/polygon/rest/quotes.py new file mode 100644 index 00000000..1555f635 --- /dev/null +++ b/polygon/rest/quotes.py @@ -0,0 +1,67 @@ +from .base import BaseClient +from typing import Optional, Any, Dict, List, Union +from .models import Quote, LastQuote, Sort, Order +from urllib3 import HTTPResponse + +# https://polygon.io/docs/stocks +class QuotesClient(BaseClient): + def list_quotes( + self, + ticker: str, + timestamp: Optional[str] = None, + timestamp_lt: Optional[str] = None, + timestamp_lte: Optional[str] = None, + timestamp_gt: Optional[str] = None, + timestamp_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False + ) -> Union[List[Quote], HTTPResponse]: + """ + Get quotes for a ticker symbol in a given time range. + + :param ticker: The ticker symbol to get quotes for. + :param timestamp: Query by timestamp. Either a date with the format YYYY-MM-DD or a nanosecond timestamp. + :param timestamp_lt: Timestamp less than + :param timestamp_lte: Timestamp less than or equal to + :param timestamp_gt: Timestamp greater than + :param timestamp_gte: Timestamp greater than or equal to + :param limit: Limit the number of results returned, default is 10 and max is 50000. + :param sort: Sort field used for ordering. + :param order: Order results based on the sort field. + :param params: Any additional query params + :param raw: Return HTTPResponse object instead of results object + :return: List of quotes + :rtype: List[Quote] + """ + url = f"/v3/quotes/{ticker}" + + return self._paginate( + path=url, + params=self._get_params(self.list_quotes, locals()), + raw=raw, + deserializer=Quote.from_dict, + ) + + def get_last_quote( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False + ): + """ + Get the most recent NBBO (Quote) tick for a given stock. + + :param ticker: The ticker symbol of the stock/equity. + :param params: Any additional query params + :param raw: Return HTTPResponse object instead of results object + :return: Last Quote + :rtype: LastQuote + """ + url = f"/v2/last/nbbo/{ticker}" + + return self._get(path=url, params=params, deserializer=LastQuote.from_dict, raw=raw) + + \ No newline at end of file From b724ad3e9df939cec9c1677584e7ea22bbb21716 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Tue, 26 Apr 2022 12:16:45 -0400 Subject: [PATCH 06/41] Darcy quotes (#119) From 9ef7862acf502591a31f8741d9854893a0cf2889 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Tue, 26 Apr 2022 12:31:43 -0400 Subject: [PATCH 07/41] add httpResponse to get_last_quote (#120) Co-authored-by: Darcy Linde <{47221647+Darcy-Linde@users.noreply.github.com}> --- polygon/rest/quotes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polygon/rest/quotes.py b/polygon/rest/quotes.py index 1555f635..c8710958 100644 --- a/polygon/rest/quotes.py +++ b/polygon/rest/quotes.py @@ -50,7 +50,7 @@ def get_last_quote( ticker: str, params: Optional[Dict[str, Any]] = None, raw: bool = False - ): + ) -> Union[LastQuote, HTTPResponse]: """ Get the most recent NBBO (Quote) tick for a given stock. From 2a65a1a1161db78185df99edd176f410756c9446 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Tue, 26 Apr 2022 14:06:07 -0400 Subject: [PATCH 08/41] Markets (#121) --- polygon/rest/__init__.py | 3 ++- polygon/rest/models/__init__.py | 2 ++ polygon/rest/models/markets.py | 31 +++++++++++++++++++++++++ polygon/rest/reference.py | 40 +++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 polygon/rest/models/markets.py create mode 100644 polygon/rest/reference.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 389c6c77..3bc193dd 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,7 +1,8 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient +from .reference import MarketsClient -class RESTClient(AggsClient, TradesClient, QuotesClient): +class RESTClient(AggsClient, TradesClient, QuotesClient, MarketsClient): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 41891552..c86fb398 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -1,6 +1,8 @@ from .aggs import * from .trades import * from .quotes import * +from .markets import * + from enum import Enum diff --git a/polygon/rest/models/markets.py b/polygon/rest/models/markets.py new file mode 100644 index 00000000..561dbeef --- /dev/null +++ b/polygon/rest/models/markets.py @@ -0,0 +1,31 @@ +from typing import Optional, Dict +from dataclasses import dataclass + + +@dataclass +class MarketHoliday: + "MarketHoliday contains data for upcoming market holidays and their open/close times." + close: Optional[str] = None + date: Optional[str] = None + exchange: Optional[str] = None + name: Optional[str] = None + open: Optional[str] = None + status: Optional[str] = None + + @staticmethod + def from_dict(d): + return MarketHoliday(**d) + +@dataclass +class MarketStatus: + "MarketStatus contains data for the current trading status of the exchanges and overall financial markets." + after_hours: Optional[bool] = None + currencies: Optional[Dict[str, str]] = None + early_hours: Optional[bool] = None + exchanges: Optional[Dict[str, str]] = None + market: Optional[str] = None + server_time: Optional[str] = None + + @staticmethod + def from_dict(d): + return MarketStatus(**d) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py new file mode 100644 index 00000000..10a6702f --- /dev/null +++ b/polygon/rest/reference.py @@ -0,0 +1,40 @@ +from .base import BaseClient +from typing import Optional, Any, Dict, List, Union +from .models import MarketHoliday, MarketStatus +from urllib3 import HTTPResponse + +# https://polygon.io/docs/stocks +class MarketsClient(BaseClient): + def list_market_holidays( + self, + params: Optional[Dict[str, Any]] = None, + raw: bool = False + ) -> Union[List[MarketHoliday], HTTPResponse]: + """ + Get upcoming market holidays and their open/close times. + + :param params: Any additional query params + :param raw: Return HTTPResponse object instead of results object + :return: List of quotes + :rtype: List[Quote] + """ + url = "/v1/marketstatus/upcoming" + + return self._get(path=url, params=params, deserializer=MarketHoliday.from_dict, raw=raw) + + def get_market_status( + self, + params: Optional[Dict[str, Any]] = None, + raw: bool = False + ) -> Union[MarketStatus, HTTPResponse]: + """ + Get the current trading status of the exchanges and overall financial markets. + + :param params: Any additional query params + :param raw: Return HTTPResponse object instead of results object + :return: List of quotes + :rtype: List[Quote] + """ + url = "/v1/marketstatus/now" + + return self._get(path=url, params=params, deserializer=MarketStatus.from_dict, raw=raw) \ No newline at end of file From 6c054951bcdb43fdc88bbf3a039834ff5bc6457d Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:50:39 -0400 Subject: [PATCH 09/41] Tickers (#122) --- polygon/rest/__init__.py | 4 +- polygon/rest/models/__init__.py | 2 +- polygon/rest/models/tickers.py | 121 ++++++++++++++++++++++++++++ polygon/rest/reference.py | 135 +++++++++++++++++++++++++++++++- 4 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 polygon/rest/models/tickers.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 3bc193dd..849443f1 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,8 +1,8 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient -from .reference import MarketsClient +from .reference import MarketsClient, TickersClient -class RESTClient(AggsClient, TradesClient, QuotesClient, MarketsClient): +class RESTClient(AggsClient, TradesClient, QuotesClient, MarketsClient, TickersClient): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index c86fb398..13bc71ea 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -2,6 +2,7 @@ from .trades import * from .quotes import * from .markets import * +from .tickers import * from enum import Enum @@ -10,7 +11,6 @@ class Sort(Enum): ASC = "asc" DESC = "desc" - class Order(Enum): ASC = "asc" DESC = "desc" diff --git a/polygon/rest/models/tickers.py b/polygon/rest/models/tickers.py new file mode 100644 index 00000000..105a8a30 --- /dev/null +++ b/polygon/rest/models/tickers.py @@ -0,0 +1,121 @@ +from typing import Optional, List +from enum import Enum +from dataclasses import dataclass + +class Locale(Enum): + US = "us" + GLOBAL = "global" + +class Market(Enum): + STOCKS = "stocks" + CRYPTO = "crypto" + FX = "fx" + +class AssetClass(Enum): + STOCKS = "stocks" + OPTIONS = "options" + CRYPTO = "crypto" + FX = "fx" + +@dataclass +class Address: + address1: Optional[str] = None + city: Optional[str] = None + state: Optional[str] = None + +@dataclass +class Branding: + icon_url: Optional[str] = None + logo_url: Optional[str] = None + +@dataclass +class Publisher: + favicon_url: Optional[str] = None + homepage_url: Optional[str] = None + logo_url: Optional[str] = None + name: Optional[str] = None + + +@dataclass +class Ticker: + "Ticker contains data for a specified ticker symbol." + active: Optional[bool] = None + cik: Optional[str] = None + composite_figi: Optional[str] = None + currency_name: Optional[str] = None + delisted_utc: Optional[str] = None + last_updated_utc: Optional[str] = None + locale: Optional[Locale] = None + market: Optional[Market] = None + name: Optional[str] = None + primary_exchange: Optional[str] = None + share_class_figi: Optional[str] = None + ticker: Optional[str] = None + type: Optional[str] = None + + @staticmethod + def from_dict(d): + return Ticker(**d) + +@dataclass +class TickerDetails: + "TickerDetails contains data for a specified ticker symbol." + active: Optional[bool] = None + address: Optional[Address] = None + branding: Optional[Branding] = None + cik: Optional[str] = None + composite_figi: Optional[str] = None + currency_name: Optional[str] = None + delisted_utc: Optional[str] = None + description: Optional[str] = None + homepage_url: Optional[str] = None + list_date: Optional[str] = None + locale: Optional[Locale] = None + market: Optional[Market] = None + market_cap: Optional[float] = None + name: Optional[str] = None + phone_number: Optional[str] = None + primary_exchange: Optional[str] = None + share_class_figi: Optional[str] = None + share_class_shares_outstanding: Optional[int] = None + sic_code: Optional[str] = None + sic_description: Optional[str] = None + ticker: Optional[str] = None + total_employees: Optional[int] = None + type: Optional[str] = None + weighted_shares_outstanding: Optional[int] = None + + @staticmethod + def from_dict(d): + return TickerDetails(**d) + +@dataclass +class TickerNews: + "TickerDetails contains data for news articles relating to a stock ticker symbol." + amp_url: Optional[str] = None + article_url: Optional[str] = None + author: Optional[str] = None + description: Optional[str] = None + id: Optional[str] = None + image_url: Optional[str] = None + keywords: Optional[List[str]] = None + published_utc: Optional[str] = None + publisher: Optional[Publisher] = None + tickers: Optional[List[str]] = None + title: Optional[str] = None + + @staticmethod + def from_dict(d): + return TickerNews(**d) + +@dataclass +class TickerTypes: + "TickerTypes contains data for ticker types." + asset_class: Optional[AssetClass] = None + code: Optional[str] = None + description: Optional[str] = None + locale: Optional[Locale] = None + + @staticmethod + def from_dict(d): + return TickerNews(**d) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 10a6702f..bfe5899f 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -1,6 +1,6 @@ from .base import BaseClient -from typing import Optional, Any, Dict, List, Union -from .models import MarketHoliday, MarketStatus +from typing import Optional, Any, Dict, List, Union, Iterator +from .models import MarketHoliday, MarketStatus, Ticker, TickerDetails, TickerNews, TickerTypes, Sort, Order, AssetClass, Locale from urllib3 import HTTPResponse # https://polygon.io/docs/stocks @@ -37,4 +37,133 @@ def get_market_status( """ url = "/v1/marketstatus/now" - return self._get(path=url, params=params, deserializer=MarketStatus.from_dict, raw=raw) \ No newline at end of file + return self._get(path=url, params=params, deserializer=MarketStatus.from_dict, raw=raw) + +class TickersClient(BaseClient): + def list_tickers( + self, + ticker: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + type: Optional[str] = None, + market: Optional[str] = None, + exchange: Optional[str] = None, + cusip: Optional[int] = None, + cik: Optional[int] = None, + date: Optional[str] = None, + active: Optional[bool] = None, + search: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Iterator[Ticker], HTTPResponse]: + """ + Query all ticker symbols which are supported by Polygon.io. This API currently includes Stocks/Equities, Crypto, and Forex. + + :param ticker: Specify a ticker symbol. Defaults to empty string which queries all tickers. + :param ticker_lt: Timestamp less than + :param ticker_lte: Ticker less than or equal to + :param ticker_gt: Ticker greater than + :param ticker_gte: Ticker greater than or equal to + :param type: Specify the type of the tickers. Find the types that we support via our Ticker Types API. Defaults to empty string which queries all types. + :param market: Filter by market type. By default all markets are included. + :param exchange: Specify the primary exchange of the asset in the ISO code format. Find more information about the ISO codes at the ISO org website. Defaults to empty string which queries all exchanges. + :param cusip: Specify the CUSIP code of the asset you want to search for. Find more information about CUSIP codes at their website. Defaults to empty string which queries all CUSIPs. + :param cik: Specify the CIK of the asset you want to search for. Find more information about CIK codes at their website. Defaults to empty string which queries all CIKs. + :param date: Specify a point in time to retrieve tickers available on that date. Defaults to the most recent available date. + :param search: Search for terms within the ticker and/or company name. + :param active: Specify if the tickers returned should be actively traded on the queried date. Default is true. + :param limit: Limit the size of the response, default is 100 and max is 1000. + :param sort: The field to sort the results on. Default is ticker. If the search query parameter is present, sort is ignored and results are ordered by relevance. + :param order: The order to sort the results on. Default is asc (ascending). + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of tickers + :rtype: List[Ticker] + """ + url = "/v3/reference/tickers" + + return self._paginate( + path=url, + params=self._get_params(self.list_tickers, locals()), + raw=raw, + deserializer=Ticker.from_dict, + ) + + def get_ticker_details( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[TickerDetails, HTTPResponse]: + """ + Get a single ticker supported by Polygon.io. This response will have detailed information about the ticker and the company behind it. + + :param ticker: The ticker symbol of the asset. + :param date: Specify a point in time to get information about the ticker available on that date. When retrieving information from SEC filings, we compare this date with the period of report date on the SEC filing. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Ticker Details V3 + :rtype: TickerDetail + """ + url = f"/v3/reference/tickers/{ticker}" + + return self._get(path=url, params=params, deserializer=TickerDetails.from_dict, raw=raw) + + def get_ticker_news( + self, + ticker: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + published_utc: Optional[str] = None, + published_utc_lt: Optional[str] = None, + published_utc_lte: Optional[str] = None, + published_utc_gt: Optional[str] = None, + published_utc_gte: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[TickerDetails, HTTPResponse]: + """ + Get the most recent news articles relating to a stock ticker symbol, including a summary of the article and a link to the original source. + + :param ticker: Return results that contain this ticker. + :param published_utc: Return results published on, before, or after this date. + :param limit: Limit the number of results returned, default is 10 and max is 1000. + :param sort: Sort field used for ordering. + :param order: Order results based on the sort field. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Ticker News + :rtype: TickerNews + """ + url = "/v2/reference/news" + + return self._get(path=url, params=params, deserializer=TickerNews.from_dict, raw=raw) + + def get_ticker_types( + self, + asset_class: Optional[AssetClass] = None, + locale: Optional[Locale] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[TickerTypes, HTTPResponse]: + """ + List all ticker types that Polygon.io has. + + :param asset_class: Filter by asset class. + :param locale: Filter by locale. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Ticker Types + :rtype: TickerTypes + """ + url = "/v3/reference/tickers/types" + + return self._get(path=url, params=params, deserializer=TickerTypes.from_dict, raw=raw) \ No newline at end of file From 6c4e7dcdc50f283f63ecf3e16714126188b7dba8 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Wed, 27 Apr 2022 11:37:22 -0400 Subject: [PATCH 10/41] Splits (#124) --- polygon/rest/__init__.py | 6 +- polygon/rest/models/__init__.py | 2 + polygon/rest/models/aggs.py | 17 +++--- polygon/rest/models/markets.py | 1 + polygon/rest/models/quotes.py | 5 +- polygon/rest/models/splits.py | 15 +++++ polygon/rest/models/tickers.py | 9 +++ polygon/rest/quotes.py | 17 ++---- polygon/rest/reference.py | 102 ++++++++++++++++++++++++++------ 9 files changed, 132 insertions(+), 42 deletions(-) create mode 100644 polygon/rest/models/splits.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 849443f1..a04cf1d0 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,8 +1,10 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient -from .reference import MarketsClient, TickersClient +from .reference import MarketsClient, TickersClient, SplitsClient -class RESTClient(AggsClient, TradesClient, QuotesClient, MarketsClient, TickersClient): +class RESTClient( + AggsClient, TradesClient, QuotesClient, MarketsClient, TickersClient, SplitsClient +): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 13bc71ea..914cc3a6 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -3,6 +3,7 @@ from .quotes import * from .markets import * from .tickers import * +from .splits import * from enum import Enum @@ -11,6 +12,7 @@ class Sort(Enum): ASC = "asc" DESC = "desc" + class Order(Enum): ASC = "asc" DESC = "desc" diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py index bdaa311c..7b3548a5 100644 --- a/polygon/rest/models/aggs.py +++ b/polygon/rest/models/aggs.py @@ -1,6 +1,7 @@ from dataclasses import dataclass from typing import Optional + @dataclass class Agg: timestamp: int @@ -15,12 +16,12 @@ class Agg: @staticmethod def from_dict(d): return Agg( - timestamp=d["t"], - open=d["o"], - high=d["h"], - low=d["l"], - close=d["c"], - volume=d["v"], - vwap=d.get("vw", None), - transactions=d.get("n", None) + timestamp=d["t"], + open=d["o"], + high=d["h"], + low=d["l"], + close=d["c"], + volume=d["v"], + vwap=d.get("vw", None), + transactions=d.get("n", None), ) diff --git a/polygon/rest/models/markets.py b/polygon/rest/models/markets.py index 561dbeef..b2b3078f 100644 --- a/polygon/rest/models/markets.py +++ b/polygon/rest/models/markets.py @@ -16,6 +16,7 @@ class MarketHoliday: def from_dict(d): return MarketHoliday(**d) + @dataclass class MarketStatus: "MarketStatus contains data for the current trading status of the exchanges and overall financial markets." diff --git a/polygon/rest/models/quotes.py b/polygon/rest/models/quotes.py index fa2b4503..a83f0a36 100644 --- a/polygon/rest/models/quotes.py +++ b/polygon/rest/models/quotes.py @@ -23,6 +23,7 @@ class Quote: def from_dict(d): return Quote(**d) + @dataclass class LastQuote: "LastQuote contains data for the most recent NBBO (Quote) tick for a given stock." @@ -57,5 +58,5 @@ def from_dict(d): bid_price=d.get("p", None), bid_size=d.get("s", None), bid_exchange=d.get("x", None), - tape=d.get("z", None) - ) \ No newline at end of file + tape=d.get("z", None), + ) diff --git a/polygon/rest/models/splits.py b/polygon/rest/models/splits.py new file mode 100644 index 00000000..037a3e1e --- /dev/null +++ b/polygon/rest/models/splits.py @@ -0,0 +1,15 @@ +from typing import Optional +from dataclasses import dataclass + + +@dataclass +class Split: + "Split contains data for a historical stock split, including the ticker symbol, the execution date, and the factors of the split ratio." + execution_date: Optional[str] = None + split_from: Optional[int] = None + split_to: Optional[int] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return Split(**d) diff --git a/polygon/rest/models/tickers.py b/polygon/rest/models/tickers.py index 105a8a30..d5382a8a 100644 --- a/polygon/rest/models/tickers.py +++ b/polygon/rest/models/tickers.py @@ -2,32 +2,38 @@ from enum import Enum from dataclasses import dataclass + class Locale(Enum): US = "us" GLOBAL = "global" + class Market(Enum): STOCKS = "stocks" CRYPTO = "crypto" FX = "fx" + class AssetClass(Enum): STOCKS = "stocks" OPTIONS = "options" CRYPTO = "crypto" FX = "fx" + @dataclass class Address: address1: Optional[str] = None city: Optional[str] = None state: Optional[str] = None + @dataclass class Branding: icon_url: Optional[str] = None logo_url: Optional[str] = None + @dataclass class Publisher: favicon_url: Optional[str] = None @@ -57,6 +63,7 @@ class Ticker: def from_dict(d): return Ticker(**d) + @dataclass class TickerDetails: "TickerDetails contains data for a specified ticker symbol." @@ -89,6 +96,7 @@ class TickerDetails: def from_dict(d): return TickerDetails(**d) + @dataclass class TickerNews: "TickerDetails contains data for news articles relating to a stock ticker symbol." @@ -108,6 +116,7 @@ class TickerNews: def from_dict(d): return TickerNews(**d) + @dataclass class TickerTypes: "TickerTypes contains data for ticker types." diff --git a/polygon/rest/quotes.py b/polygon/rest/quotes.py index c8710958..198e3adf 100644 --- a/polygon/rest/quotes.py +++ b/polygon/rest/quotes.py @@ -17,7 +17,7 @@ def list_quotes( sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False + raw: bool = False, ) -> Union[List[Quote], HTTPResponse]: """ Get quotes for a ticker symbol in a given time range. @@ -34,7 +34,6 @@ def list_quotes( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object :return: List of quotes - :rtype: List[Quote] """ url = f"/v3/quotes/{ticker}" @@ -44,12 +43,9 @@ def list_quotes( raw=raw, deserializer=Quote.from_dict, ) - + def get_last_quote( - self, - ticker: str, - params: Optional[Dict[str, Any]] = None, - raw: bool = False + self, ticker: str, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[LastQuote, HTTPResponse]: """ Get the most recent NBBO (Quote) tick for a given stock. @@ -58,10 +54,9 @@ def get_last_quote( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object :return: Last Quote - :rtype: LastQuote """ url = f"/v2/last/nbbo/{ticker}" - return self._get(path=url, params=params, deserializer=LastQuote.from_dict, raw=raw) - - \ No newline at end of file + return self._get( + path=url, params=params, deserializer=LastQuote.from_dict, raw=raw + ) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index bfe5899f..d2c83b3d 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -1,14 +1,24 @@ from .base import BaseClient from typing import Optional, Any, Dict, List, Union, Iterator -from .models import MarketHoliday, MarketStatus, Ticker, TickerDetails, TickerNews, TickerTypes, Sort, Order, AssetClass, Locale +from .models import ( + MarketHoliday, + MarketStatus, + Ticker, + TickerDetails, + TickerNews, + TickerTypes, + Sort, + Order, + AssetClass, + Locale, + Split, +) from urllib3 import HTTPResponse # https://polygon.io/docs/stocks class MarketsClient(BaseClient): def list_market_holidays( - self, - params: Optional[Dict[str, Any]] = None, - raw: bool = False + self, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[List[MarketHoliday], HTTPResponse]: """ Get upcoming market holidays and their open/close times. @@ -16,16 +26,15 @@ def list_market_holidays( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object :return: List of quotes - :rtype: List[Quote] """ url = "/v1/marketstatus/upcoming" - return self._get(path=url, params=params, deserializer=MarketHoliday.from_dict, raw=raw) + return self._get( + path=url, params=params, deserializer=MarketHoliday.from_dict, raw=raw + ) def get_market_status( - self, - params: Optional[Dict[str, Any]] = None, - raw: bool = False + self, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[MarketStatus, HTTPResponse]: """ Get the current trading status of the exchanges and overall financial markets. @@ -33,11 +42,13 @@ def get_market_status( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object :return: List of quotes - :rtype: List[Quote] """ url = "/v1/marketstatus/now" - return self._get(path=url, params=params, deserializer=MarketStatus.from_dict, raw=raw) + return self._get( + path=url, params=params, deserializer=MarketStatus.from_dict, raw=raw + ) + class TickersClient(BaseClient): def list_tickers( @@ -65,7 +76,7 @@ def list_tickers( Query all ticker symbols which are supported by Polygon.io. This API currently includes Stocks/Equities, Crypto, and Forex. :param ticker: Specify a ticker symbol. Defaults to empty string which queries all tickers. - :param ticker_lt: Timestamp less than + :param ticker_lt: Ticker less than :param ticker_lte: Ticker less than or equal to :param ticker_gt: Ticker greater than :param ticker_gte: Ticker greater than or equal to @@ -83,7 +94,6 @@ def list_tickers( :param params: Any additional query params :param raw: Return raw object instead of results object :return: List of tickers - :rtype: List[Ticker] """ url = "/v3/reference/tickers" @@ -109,11 +119,12 @@ def get_ticker_details( :param params: Any additional query params :param raw: Return raw object instead of results object :return: Ticker Details V3 - :rtype: TickerDetail """ url = f"/v3/reference/tickers/{ticker}" - return self._get(path=url, params=params, deserializer=TickerDetails.from_dict, raw=raw) + return self._get( + path=url, params=params, deserializer=TickerDetails.from_dict, raw=raw + ) def get_ticker_news( self, @@ -141,11 +152,12 @@ def get_ticker_news( :param params: Any additional query params :param raw: Return raw object instead of results object :return: Ticker News - :rtype: TickerNews """ url = "/v2/reference/news" - return self._get(path=url, params=params, deserializer=TickerNews.from_dict, raw=raw) + return self._get( + path=url, params=params, deserializer=TickerNews.from_dict, raw=raw + ) def get_ticker_types( self, @@ -162,8 +174,60 @@ def get_ticker_types( :param params: Any additional query params :param raw: Return raw object instead of results object :return: Ticker Types - :rtype: TickerTypes """ url = "/v3/reference/tickers/types" - return self._get(path=url, params=params, deserializer=TickerTypes.from_dict, raw=raw) \ No newline at end of file + return self._get( + path=url, params=params, deserializer=TickerTypes.from_dict, raw=raw + ) + + +class SplitsClient(BaseClient): + def list_splits( + self, + ticker: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + execution_date: Optional[str] = None, + execution_lt: Optional[str] = None, + execution_lte: Optional[str] = None, + execution_gt: Optional[str] = None, + execution_gte: Optional[str] = None, + reverse_split: Optional[bool] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Iterator[Split], HTTPResponse]: + """ + Get a list of historical stock splits, including the ticker symbol, the execution date, and the factors of the split ratio. + + :param ticker: Return the stock splits that contain this ticker. + :param ticker_lt: Ticker less than + :param ticker_lte: Ticker less than or equal to + :param ticker_gt: Ticker greater than + :param ticker_gte: Ticker greater than or equal to + :param execution_date: Query by execution date with the format YYYY-MM-DD. + :param execution_date_lt: Execution date less than + :param execution_date_lte: Execution date less than or equal to + :param execution_date_gt: Execution date greater than + :param execution_date_gte: Execution date greater than or equal to + :param reverse_split: Query for reverse stock splits. A split ratio where split_from is greater than split_to represents a reverse split. By default this filter is not used. + :param limit: Limit the number of results returned, default is 10 and max is 1000. + :param sort: Sort field used for ordering. + :param order: Order results based on the sort field. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of splits + """ + url = "/v3/reference/splits" + + return self._paginate( + path=url, + params=self._get_params(self.list_splits, locals()), + raw=raw, + deserializer=Split.from_dict, + ) From c28320ca75b0aaab824d326ff17138a1882ad46c Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Wed, 27 Apr 2022 11:41:38 -0400 Subject: [PATCH 11/41] allow datetime or int for aggs, lint tests (#123) * allow datetime or int for aggs, lint tests * run --check in CI --- Makefile | 4 ++-- polygon/rest/aggs.py | 14 ++++++++++---- polygon/rest/reference.py | 4 ---- tests/mocks.py | 7 ++++--- tests/test_aggs.py | 25 +++++++++++++++++++++++-- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index f6751664..af69d83e 100644 --- a/Makefile +++ b/Makefile @@ -22,11 +22,11 @@ help: ## Check code style style: - poetry run black polygon + poetry run black $(if $(CI),--check,) polygon tests ## Check static types static: - poetry run mypy polygon + poetry run mypy polygon tests ## Check code style and static types lint: style static diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index ccaa5187..a648327f 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -2,6 +2,7 @@ from typing import Optional, Any, Dict, List, Union from .models import Agg, Sort from urllib3 import HTTPResponse +from datetime import datetime # https://polygon.io/docs/stocks class AggsClient(BaseClient): @@ -11,8 +12,8 @@ def get_aggs( multiplier: int, timespan: str, # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp - from_: str, - to: str, + from_: Union[str, int, datetime], + to: Union[str, int, datetime], adjusted: Optional[bool] = None, sort: Optional[Union[str, Sort]] = None, limit: Optional[int] = None, @@ -25,8 +26,8 @@ def get_aggs( :param ticker: The ticker symbol. :param multiplier: The size of the timespan multiplier. :param timespan: The size of the time window. - :param _from: The start of the aggregate time window. - :param to: The end of the aggregate time window. + :param _from: The start of the aggregate time window as YYYY-MM-DD, Unix MS Timestamps, or a datetime. + :param to: The end of the aggregate time window as YYYY-MM-DD, Unix MS Timestamps, or a datetime. :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. :param sort: Sort the results by timestamp. asc will return results in ascending order (oldest at the top), desc will return results in descending order (newest at the top).The end of the aggregate time window. :param limit: Limits the number of base aggregates queried to create the aggregate results. Max 50000 and Default 5000. Read more about how limit is used to calculate aggregate results in our article on Aggregate Data API Improvements. @@ -35,6 +36,11 @@ def get_aggs( :return: List of aggregates :rtype: List[Agg] """ + if isinstance(from_, datetime): + from_ = int(from_.timestamp() * 1000) + + if isinstance(to, datetime): + to = int(to.timestamp() * 1000) url = f"/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" return self._get( diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index d2c83b3d..40c915f2 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -74,7 +74,6 @@ def list_tickers( ) -> Union[Iterator[Ticker], HTTPResponse]: """ Query all ticker symbols which are supported by Polygon.io. This API currently includes Stocks/Equities, Crypto, and Forex. - :param ticker: Specify a ticker symbol. Defaults to empty string which queries all tickers. :param ticker_lt: Ticker less than :param ticker_lte: Ticker less than or equal to @@ -113,7 +112,6 @@ def get_ticker_details( ) -> Union[TickerDetails, HTTPResponse]: """ Get a single ticker supported by Polygon.io. This response will have detailed information about the ticker and the company behind it. - :param ticker: The ticker symbol of the asset. :param date: Specify a point in time to get information about the ticker available on that date. When retrieving information from SEC filings, we compare this date with the period of report date on the SEC filing. :param params: Any additional query params @@ -143,7 +141,6 @@ def get_ticker_news( ) -> Union[TickerDetails, HTTPResponse]: """ Get the most recent news articles relating to a stock ticker symbol, including a summary of the article and a link to the original source. - :param ticker: Return results that contain this ticker. :param published_utc: Return results published on, before, or after this date. :param limit: Limit the number of results returned, default is 10 and max is 1000. @@ -168,7 +165,6 @@ def get_ticker_types( ) -> Union[TickerTypes, HTTPResponse]: """ List all ticker types that Polygon.io has. - :param asset_class: Filter by asset class. :param locale: Filter by locale. :param params: Any additional query params diff --git a/tests/mocks.py b/tests/mocks.py index ce35c718..896bf5c7 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -1,16 +1,18 @@ from polygon import RESTClient import unittest -import httpretty +import httpretty # type: ignore mocks = [ ( "/v2/aggs/ticker/AAPL/range/1/day/2005-04-01/2005-04-04", - '{"ticker":"AAPL","queryCount":2,"resultsCount":2,"adjusted":true,"results":[{"v":6.42646396e+08,"vw":1.469,"o":1.5032,"c":1.4604,"h":1.5064,"l":1.4489,"t":1112331600000,"n":82132},{"v":5.78172308e+08,"vw":1.4589,"o":1.4639,"c":1.4675,"h":1.4754,"l":1.4343,"t":1112587200000,"n":65543}],"status":"OK","request_id":"12afda77aab3b1936c5fb6ef4241ae42","count":2}' + '{"ticker":"AAPL","queryCount":2,"resultsCount":2,"adjusted":true,"results":[{"v":6.42646396e+08,"vw":1.469,"o":1.5032,"c":1.4604,"h":1.5064,"l":1.4489,"t":1112331600000,"n":82132},{"v":5.78172308e+08,"vw":1.4589,"o":1.4639,"c":1.4675,"h":1.4754,"l":1.4343,"t":1112587200000,"n":65543}],"status":"OK","request_id":"12afda77aab3b1936c5fb6ef4241ae42","count":2}', ) ] + class BaseTest(unittest.TestCase): setup = False + def setUp(self): if self.setup: return @@ -19,4 +21,3 @@ def setUp(self): for m in mocks: httpretty.register_uri(httpretty.GET, c.BASE + m[0], m[1]) self.setup = True - diff --git a/tests/test_aggs.py b/tests/test_aggs.py index f8c88cca..3a068ce1 100644 --- a/tests/test_aggs.py +++ b/tests/test_aggs.py @@ -2,10 +2,31 @@ from polygon.rest.models import Agg from mocks import BaseTest + class AggsTest(BaseTest): def test_get_aggs(self): c = RESTClient("") aggs = c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") - expected = [Agg(open=1.5032, high=1.5064, low=1.4489, close=1.4604, volume=642646396.0, vwap=1.469, timestamp=1112331600000, transactions=82132), Agg(open=1.4639, high=1.4754, low=1.4343, close=1.4675, volume=578172308.0, vwap=1.4589, timestamp=1112587200000, transactions=65543)] + expected = [ + Agg( + open=1.5032, + high=1.5064, + low=1.4489, + close=1.4604, + volume=642646396.0, + vwap=1.469, + timestamp=1112331600000, + transactions=82132, + ), + Agg( + open=1.4639, + high=1.4754, + low=1.4343, + close=1.4675, + volume=578172308.0, + vwap=1.4589, + timestamp=1112587200000, + transactions=65543, + ), + ] self.assertEqual(aggs, expected) - From 2e48c25b4969a3ff7361bf793fcf48294f5e67e0 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:22:35 -0400 Subject: [PATCH 12/41] Dividends (#125) --- polygon/rest/__init__.py | 10 +++- polygon/rest/models/__init__.py | 1 + polygon/rest/models/dividends.py | 35 +++++++++++ polygon/rest/reference.py | 100 +++++++++++++++++++++++++++++-- 4 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 polygon/rest/models/dividends.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index a04cf1d0..a101edf1 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,10 +1,16 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient -from .reference import MarketsClient, TickersClient, SplitsClient +from .reference import MarketsClient, TickersClient, SplitsClient, DividendsClient class RESTClient( - AggsClient, TradesClient, QuotesClient, MarketsClient, TickersClient, SplitsClient + AggsClient, + TradesClient, + QuotesClient, + MarketsClient, + TickersClient, + SplitsClient, + DividendsClient, ): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 914cc3a6..a6a9c916 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -4,6 +4,7 @@ from .markets import * from .tickers import * from .splits import * +from .dividends import * from enum import Enum diff --git a/polygon/rest/models/dividends.py b/polygon/rest/models/dividends.py new file mode 100644 index 00000000..b691812a --- /dev/null +++ b/polygon/rest/models/dividends.py @@ -0,0 +1,35 @@ +from typing import Optional +from enum import Enum +from dataclasses import dataclass + + +class DividendType(Enum): + CD = "CD" + SC = "SC" + LT = "LT" + ST = "ST" + + +class Frequency(Enum): + OneTime = 0 + Anually = 1 + BiAnually = 2 + Quarterly = 4 + Monthly = 12 + + +@dataclass +class Dividend: + "Dividend contains data for a historical cash dividend, including the ticker symbol, declaration date, ex-dividend date, record date, pay date, frequency, and amount." + cash_amount: Optional[float] = None + declaration_date: Optional[str] = None + dividend_type: Optional[DividendType] = None + ex_dividend_date: Optional[str] = None + frequency: Optional[Frequency] = None + pay_date: Optional[str] = None + record_date: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return Dividend(**d) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 40c915f2..bcf0a8ac 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -1,3 +1,4 @@ +from polygon.rest.models.dividends import DividendType from .base import BaseClient from typing import Optional, Any, Dict, List, Union, Iterator from .models import ( @@ -12,6 +13,8 @@ AssetClass, Locale, Split, + Dividend, + Frequency, ) from urllib3 import HTTPResponse @@ -187,10 +190,10 @@ def list_splits( ticker_gt: Optional[str] = None, ticker_gte: Optional[str] = None, execution_date: Optional[str] = None, - execution_lt: Optional[str] = None, - execution_lte: Optional[str] = None, - execution_gt: Optional[str] = None, - execution_gte: Optional[str] = None, + execution_date_lt: Optional[str] = None, + execution_date_lte: Optional[str] = None, + execution_date_gt: Optional[str] = None, + execution_date_gte: Optional[str] = None, reverse_split: Optional[bool] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, @@ -227,3 +230,92 @@ def list_splits( raw=raw, deserializer=Split.from_dict, ) + + +class DividendsClient(BaseClient): + def list_dividends( + self, + ticker: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ex_dividend_date: Optional[str] = None, + ex_dividend_date_lt: Optional[str] = None, + ex_dividend_date_lte: Optional[str] = None, + ex_dividend_date_gt: Optional[str] = None, + ex_dividend_date_gte: Optional[str] = None, + record_date: Optional[str] = None, + record_date_lt: Optional[str] = None, + record_date_lte: Optional[str] = None, + record_date_gt: Optional[str] = None, + record_date_gte: Optional[str] = None, + declaration_date: Optional[str] = None, + declaration_date_lt: Optional[str] = None, + declaration_date_lte: Optional[str] = None, + declaration_date_gt: Optional[str] = None, + declaration_date_gte: Optional[str] = None, + pay_date: Optional[str] = None, + pay_date_lt: Optional[str] = None, + pay_date_lte: Optional[str] = None, + pay_date_gt: Optional[str] = None, + pay_date_gte: Optional[str] = None, + frequency: Optional[Frequency] = None, + cash_amount: Optional[float] = None, + cash_amount_lt: Optional[float] = None, + cash_amount_lte: Optional[float] = None, + cash_amount_gt: Optional[float] = None, + cash_amount_gte: Optional[float] = None, + dividend_type: Optional[DividendType] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Iterator[Dividend], HTTPResponse]: + """ + Get a list of historical cash dividends, including the ticker symbol, declaration date, ex-dividend date, record date, pay date, frequency, and amount. + + :param ticker: Return the dividends that contain this ticker. + :param ticker_lt: Ticker less than + :param ticker_lte: Ticker less than or equal to + :param ticker_gt: Ticker greater than + :param ticker_gte: Ticker greater than or equal to + :param ex_dividend_date: Query by ex-dividend date with the format YYYY-MM-DD. + :param ex_dividend_date_lt: Ex-dividend date less than + :param ex_dividend_date_lte: Ex-dividend date less than or equal to + :param ex_dividend_date_gt: Ex-dividend date greater than + :param ex_dividend_date_gte: Ex-dividend date greater than or equal to + :param record_date: Query by record date with the format YYYY-MM-DD. + :param record_date_lt: Record date less than + :param record_date_lte: Record date less than or equal to + :param record_date_gt: Record date greater than + :param record_date_gte: Record date greater than or equal to + :param declaration_date: Query by declaration date with the format YYYY-MM-DD. + :param declaration_date_lt: Declaration date less than + :param declaration_date_lte: Declaration date less than or equal to + :param declaration_date_gt: Declaration date greater than + :param declaration_date_gte: Declaration date greater than or equal to + :param pay_date: Query by pay date with the format YYYY-MM-DD. + :param pay_date_lt: Pay date less than + :param pay_date_lte: Pay date less than or equal to + :param pay_date_gt: Pay date greater than + :param pay_date_gte: Pay date greater than or equal to + :param frequency: Query by the number of times per year the dividend is paid out. Possible values are 0 (one-time), 1 (annually), 2 (bi-annually), 4 (quarterly), and 12 (monthly). + :param cash_amount: Query by the cash amount of the dividend. + :param dividend_type: Query by the type of dividend. Dividends that have been paid and/or are expected to be paid on consistent schedules are denoted as CD. Special Cash dividends that have been paid that are infrequent or unusual, and/or can not be expected to occur in the future are denoted as SC. + :param limit: Limit the number of results returned, default is 10 and max is 1000. + :param sort: Sort field used for ordering. + :param order: Order results based on the sort field. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of dividends + """ + url = "/v3/reference/dividends" + + return self._paginate( + path=url, + params=self._get_params(self.list_dividends, locals()), + raw=raw, + deserializer=Dividend.from_dict, + ) From 02d15ea4a007afd07d15594db8e768bc69d773a9 Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Thu, 28 Apr 2022 10:29:04 -0400 Subject: [PATCH 13/41] add sphinx docs (#126) * add sphinx docs * cleanup * fix some reference pydoc * fix code formatting * typos * fix lint --- .gitignore | 2 +- docs/Makefile | 20 ++ docs/source/Getting-Started.rst | 176 ++++++++++++++ docs/source/Quotes.rst | 15 ++ docs/source/Reference.rst | 40 +++ docs/source/Trades.rst | 9 + docs/source/conf.py | 59 +++++ docs/source/index.rst | 21 ++ poetry.lock | 417 +++++++++++++++++++++++++++++++- polygon/rest/aggs.py | 2 +- polygon/rest/base.py | 46 +++- polygon/rest/reference.py | 6 +- polygon/rest/trades.py | 3 +- pyproject.toml | 3 + rest-example.py | 8 +- 15 files changed, 810 insertions(+), 17 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/source/Getting-Started.rst create mode 100644 docs/source/Quotes.rst create mode 100644 docs/source/Reference.rst create mode 100644 docs/source/Trades.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst diff --git a/.gitignore b/.gitignore index a655050c..300a17c1 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,7 @@ venv/ *.log # Sphinx documentation -docs/_build/ +docs/build/ # PyBuilder target/ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..7f823a57 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + POLYGON_API_KEY="POLYGON_API_KEY" $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/Getting-Started.rst b/docs/source/Getting-Started.rst new file mode 100644 index 00000000..e7ad27c0 --- /dev/null +++ b/docs/source/Getting-Started.rst @@ -0,0 +1,176 @@ +Getting Started +=============== + +Requirements: + - `Polygon.io API key `_ + - `Python >= 3.7 `_ + - `This package `_ + +.. code-block:: shell + + pip install polygon-api-client + +HTTP client usage +----------------- + +.. automethod:: polygon.RESTClient.__init__ + +You can pass your API key via the environment variable :code:`POLYGON_API_KEY` or as the first parameter to the :code:`RESTClient` constructor: + +.. code-block:: python + + from polygon import RESTClient + + client = RESTClient() # POLYGON_API_KEY is used + client = RESTClient("api_key") # api_key is used + +For non-paginated endpoints call :code:`get_*`: + +.. code-block:: python + + aggs = client.get_aggs("AAPL", 1, "day", "2022-04-01", "2022-04-04") + print(aggs) + +For paginated endpoints call :code:`list_*` and use the provided iterator: + +.. code-block:: python + + trades = [] + for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC) + trades.append(t) + print(trades) + +For endpoints that have a set of parameters you can use the provided enums: + +.. code-block:: python + + from polygon.rest.models import Sort + + client.list_trades(..., sort=Sort.ASC) + +To handle the raw `urllib3 response `_ yourself pass :code:`raw=True`: + +.. code-block:: python + + aggs = client.get_aggs("AAPL", 1, "day", "2022-04-01", "2022-04-04", raw=True) + print(aggs.geturl()) + # https://api.polygon.io/v2/aggs/ticker/AAPL/range/1/day/2022-04-01/2022-04-04 + print(aggs.status) + # 200 + print(aggs.data) + # b'{ + # "ticker": "AAPL", + # "queryCount": 2, + # "resultsCount": 2, + # "adjusted": true, + # "results": [ + # { + # "v": 78251328, + # "vw": 173.4143, + # "o": 174.03, + # "c": 174.31, + # "h": 174.88, + # "l": 171.94, + # "t": 1648785600000, + # "n": 661160 + # }, + # { + # "v": 76545983, + # "vw": 177.4855, + # "o": 174.57, + # "c": 178.44, + # "h": 178.49, + # "l": 174.44, + # "t": 1649044800000, + # "n": 630374 + # } + # ], + # "status": "OK", + # "request_id": "d8882a9d5194978819777f49c44b09c6", + # "count": 2 + # }' + +If it is a paginated :code:`list_*` response it's up to you to handle the "next_url" iteration: + +.. code-block:: python + + trades = client.list_trades("AAA", timestamp="2022-04-20", limit=5) + print(aggs.data) + # b'{ + # "results": [ + # { + # "conditions": [ + # 15 + # ], + # "exchange": 11, + # "id": "52983575627601", + # "participant_timestamp": 1650499200029279200, + # "price": 24.875, + # "sequence_number": 1591291, + # "sip_timestamp": 1650499200029316600, + # "size": 100, + # "tape": 1 + # }, + # { + # "conditions": [ + # 38, + # 41 + # ], + # "exchange": 11, + # "id": "52983575627600", + # "participant_timestamp": 1650499200029279200, + # "price": 24.875, + # "sequence_number": 1591290, + # "sip_timestamp": 1650499200029316600, + # "tape": 1 + # }, + # { + # "conditions": [ + # 15 + # ], + # "exchange": 11, + # "id": "52983575622470", + # "participant_timestamp": 1650493800003024000, + # "price": 24.875, + # "sequence_number": 1571279, + # "sip_timestamp": 1650493800003645400, + # "size": 100, + # "tape": 1 + # }, + # { + # "conditions": [ + # 38, + # 41 + # ], + # "exchange": 11, + # "id": "52983575622469", + # "participant_timestamp": 1650493800003024000, + # "price": 24.875, + # "sequence_number": 1571276, + # "sip_timestamp": 1650493800003635500, + # "tape": 1 + # }, + # { + # "conditions": [ + # 15 + # ], + # "exchange": 11, + # "id": "52983575556178", + # "participant_timestamp": 1650485400002987800, + # "price": 24.875, + # "sequence_number": 1536223, + # "sip_timestamp": 1650485400003870000, + # "size": 100, + # "tape": 1 + # } + # ], + # "status": "OK", + # "request_id": "618bb99e7a632ed9f55454a541404b44", + # "next_url": "https://api.polygon.io/v3/trades/AAA?cursor=YXA9NSZhcz0mbGltaXQ9NSZvcmRlcj1kZXNjJnNvcnQ9dGltZXN0YW1wJnRpbWVzdGFtcC5ndGU9MjAyMi0wNC0yMFQwNCUzQTAwJTNBMDBaJnRpbWVzdGFtcC5sdGU9MjAyMi0wNC0yMFQyMCUzQTEwJTNBMDAuMDAzODY5OTUyWg" + # }' + + +Websocket client usage +---------------------- + +Coming soon. diff --git a/docs/source/Quotes.rst b/docs/source/Quotes.rst new file mode 100644 index 00000000..4c379455 --- /dev/null +++ b/docs/source/Quotes.rst @@ -0,0 +1,15 @@ +.. _quotes_header: + +Quotes +========== + +=========== +List quotes +=========== + +.. automethod:: polygon.RESTClient.list_quotes + +============== +Get last quote +============== +.. automethod:: polygon.RESTClient.get_last_quote diff --git a/docs/source/Reference.rst b/docs/source/Reference.rst new file mode 100644 index 00000000..2f4210ef --- /dev/null +++ b/docs/source/Reference.rst @@ -0,0 +1,40 @@ +.. _reference_header: + +Reference +=============== + +==================== +List market holidays +==================== +.. automethod:: polygon.RESTClient.list_market_holidays + +==================== +List tickers +==================== +.. automethod:: polygon.RESTClient.list_tickers + +==================== +List ticker details +==================== +.. automethod:: polygon.RESTClient.get_ticker_details + +==================== +Get ticker news +==================== +.. automethod:: polygon.RESTClient.get_ticker_news + +==================== +Get ticker types +==================== +.. automethod:: polygon.RESTClient.get_ticker_types + +==================== +List splits +==================== +.. automethod:: polygon.RESTClient.list_splits + +==================== +List dividends +==================== +.. automethod:: polygon.RESTClient.list_dividends + diff --git a/docs/source/Trades.rst b/docs/source/Trades.rst new file mode 100644 index 00000000..50e628c4 --- /dev/null +++ b/docs/source/Trades.rst @@ -0,0 +1,9 @@ +.. _trades_header: + +Trades +============= + +=========== +List trades +=========== +.. automethod:: polygon.RESTClient.list_trades diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..cef0ef75 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,59 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) +print('docs path', sys.path[0]) + + +# -- Project information ----------------------------------------------------- + +project = 'polygon-api-client' +copyright = '2022, Polygon.io' +author = 'Polygon.io' + +# The full version, including alpha/beta/rc tags +release = '0.3.0' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx_autodoc_typehints', + 'sphinx_rtd_theme', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..6cc7d51d --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,21 @@ +Welcome to polygon-api-client's documentation! +============================================== + +This documentation is for the Python client only. For details about the responses see `the official docs `_. + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + Getting-Started + Quotes + Reference + Trades + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/poetry.lock b/poetry.lock index 7a9b6760..6c2f429a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,22 @@ +[[package]] +name = "alabaster" +version = "0.7.12" +description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "babel" +version = "2.10.1" +description = "Internationalization utilities" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pytz = ">=2015.7" + [[package]] name = "black" version = "22.3.0" @@ -21,6 +40,25 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.12" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" version = "8.1.2" @@ -41,6 +79,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "docutils" +version = "0.17.1" +description = "Docutils -- Python Documentation Utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "httpretty" version = "1.1.4" @@ -49,6 +95,22 @@ category = "dev" optional = false python-versions = ">=3" +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "imagesize" +version = "1.3.0" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "importlib-metadata" version = "4.11.3" @@ -66,6 +128,28 @@ docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +[[package]] +name = "jinja2" +version = "3.1.1" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "mypy" version = "0.942" @@ -93,6 +177,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + [[package]] name = "pathspec" version = "0.9.0" @@ -113,6 +208,192 @@ python-versions = ">=3.7" docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +[[package]] +name = "pygments" +version = "2.12.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pyparsing" +version = "3.0.8" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "dev" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + +[[package]] +name = "pytz" +version = "2022.1" +description = "World timezone definitions, modern and historical" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "requests" +version = "2.27.1" +description = "Python HTTP for Humans." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "sphinx" +version = "4.5.0" +description = "Python documentation generator" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=1.3" +colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.14,<0.18" +imagesize = "*" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} +Jinja2 = ">=2.3" +packaging = "*" +Pygments = ">=2.0" +requests = ">=2.5.0" +snowballstemmer = ">=1.1" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"] +test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] + +[[package]] +name = "sphinx-autodoc-typehints" +version = "1.18.1" +description = "Type hints (PEP 484) support for the Sphinx autodoc extension" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +Sphinx = ">=4.5" + +[package.extras] +testing = ["covdefaults (>=2.2)", "coverage (>=6.3)", "diff-cover (>=6.4)", "nptyping (>=2)", "pytest (>=7.1)", "pytest-cov (>=3)", "sphobjinv (>=2)", "typing-extensions (>=4.1)"] +type_comments = ["typed-ast (>=1.5.2)"] + +[[package]] +name = "sphinx-rtd-theme" +version = "1.0.0" +description = "Read the Docs theme for Sphinx" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +docutils = "<0.18" +sphinx = ">=1.6" + +[package.extras] +dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + [[package]] name = "tomli" version = "2.0.1" @@ -173,9 +454,17 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "992b579a470d1662ac4e64e78155506ec2f8c31013124a4cbb43cf0625a2931c" +content-hash = "8ea6c39c95fde83519380774c4bff55aacb6249c9a0b61437fadd4946cb2aaef" [metadata.files] +alabaster = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] +babel = [ + {file = "Babel-2.10.1-py3-none-any.whl", hash = "sha256:3f349e85ad3154559ac4930c3918247d319f21910d5ce4b25d439ed8693b98d2"}, + {file = "Babel-2.10.1.tar.gz", hash = "sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13"}, +] black = [ {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, @@ -201,6 +490,14 @@ black = [ {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, ] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, +] click = [ {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, @@ -209,13 +506,71 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +docutils = [ + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, +] httpretty = [ {file = "httpretty-1.1.4.tar.gz", hash = "sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68"}, ] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +imagesize = [ + {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, + {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, +] importlib-metadata = [ {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, ] +jinja2 = [ + {file = "Jinja2-3.1.1-py3-none-any.whl", hash = "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119"}, + {file = "Jinja2-3.1.1.tar.gz", hash = "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9"}, +] +markupsafe = [ + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, +] mypy = [ {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, @@ -245,6 +600,10 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, @@ -253,6 +612,62 @@ platformdirs = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] +pygments = [ + {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, + {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, +] +pyparsing = [ + {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, + {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, +] +pytz = [ + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, +] +requests = [ + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] +sphinx = [ + {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, + {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, +] +sphinx-autodoc-typehints = [ + {file = "sphinx_autodoc_typehints-1.18.1-py3-none-any.whl", hash = "sha256:f8f5bb7c13a9a71537dc2be2eb3b9e28a9711e2454df63587005eacf6fbac453"}, + {file = "sphinx_autodoc_typehints-1.18.1.tar.gz", hash = "sha256:07631c5f0c6641e5ba27143494aefc657e029bed3982138d659250e617f6f929"}, +] +sphinx-rtd-theme = [ + {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, + {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, +] +sphinxcontrib-applehelp = [ + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, +] +sphinxcontrib-devhelp = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] +sphinxcontrib-htmlhelp = [ + {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, + {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, +] +sphinxcontrib-jsmath = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] +sphinxcontrib-qthelp = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] +sphinxcontrib-serializinghtml = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index a648327f..7c90e0ca 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -46,7 +46,7 @@ def get_aggs( return self._get( path=url, params=self._get_params(self.get_aggs, locals()), - resultKey="results", + result_key="results", deserializer=Agg.from_dict, raw=raw, ) diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 9349b251..0fed618d 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -40,7 +40,7 @@ def _get( self, path: str, params: Optional[dict] = None, - resultKey: Optional[str] = None, + result_key: Optional[str] = None, deserializer=None, raw: bool = False, ) -> Any: @@ -59,8 +59,8 @@ def _get( obj = self._decode(resp) - if resultKey: - obj = obj[resultKey] + if result_key: + obj = obj[result_key] if deserializer: obj = [deserializer(o) for o in obj] @@ -86,18 +86,48 @@ def _get_params(self, fn, caller_locals): return params - def _paginate(self, path: str, params: dict, raw: bool, deserializer): + def _paginate_iter( + self, + path: str, + params: dict, + raw: bool, + deserializer, + result_key: str = "results", + ): while True: resp = self._get( - path=path, params=params, deserializer=deserializer, raw=True + path=path, + params=params, + deserializer=deserializer, + result_key=result_key, + raw=True, ) - if raw: - return resp decoded = self._decode(resp) - for t in decoded["results"]: + for t in decoded[result_key]: yield deserializer(t) if "next_url" in decoded: path = decoded["next_url"].replace(self.BASE, "") params = {} else: return + + def _paginate( + self, + path: str, + params: dict, + raw: bool, + deserializer, + result_key: str = "results", + ): + if raw: + return self._get( + path=path, params=params, deserializer=deserializer, raw=True + ) + + return self._paginate_iter( + path=path, + params=params, + deserializer=deserializer, + result_key=result_key, + raw=True, + ) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index bcf0a8ac..63c96402 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -1,4 +1,3 @@ -from polygon.rest.models.dividends import DividendType from .base import BaseClient from typing import Optional, Any, Dict, List, Union, Iterator from .models import ( @@ -14,6 +13,7 @@ Locale, Split, Dividend, + DividendType, Frequency, ) from urllib3 import HTTPResponse @@ -77,6 +77,7 @@ def list_tickers( ) -> Union[Iterator[Ticker], HTTPResponse]: """ Query all ticker symbols which are supported by Polygon.io. This API currently includes Stocks/Equities, Crypto, and Forex. + :param ticker: Specify a ticker symbol. Defaults to empty string which queries all tickers. :param ticker_lt: Ticker less than :param ticker_lte: Ticker less than or equal to @@ -115,6 +116,7 @@ def get_ticker_details( ) -> Union[TickerDetails, HTTPResponse]: """ Get a single ticker supported by Polygon.io. This response will have detailed information about the ticker and the company behind it. + :param ticker: The ticker symbol of the asset. :param date: Specify a point in time to get information about the ticker available on that date. When retrieving information from SEC filings, we compare this date with the period of report date on the SEC filing. :param params: Any additional query params @@ -144,6 +146,7 @@ def get_ticker_news( ) -> Union[TickerDetails, HTTPResponse]: """ Get the most recent news articles relating to a stock ticker symbol, including a summary of the article and a link to the original source. + :param ticker: Return results that contain this ticker. :param published_utc: Return results published on, before, or after this date. :param limit: Limit the number of results returned, default is 10 and max is 1000. @@ -168,6 +171,7 @@ def get_ticker_types( ) -> Union[TickerTypes, HTTPResponse]: """ List all ticker types that Polygon.io has. + :param asset_class: Filter by asset class. :param locale: Filter by locale. :param params: Any additional query params diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py index 3d22476b..85cac40a 100644 --- a/polygon/rest/trades.py +++ b/polygon/rest/trades.py @@ -33,8 +33,7 @@ def list_trades( :param order: Order results based on the sort field :param params: Any additional query params :param raw: Return raw object instead of results object - :return: List of aggregates - :rtype: List[Agg] + :return: Iterator of trades """ url = f"/v3/trades/{ticker}" diff --git a/pyproject.toml b/pyproject.toml index 98d3228f..1722a69e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,9 @@ black = "^22.3.0" mypy = "^0.942" types-urllib3 = "^1.26.13" httpretty = "^1.1.4" +Sphinx = "^4.5.0" +sphinx-rtd-theme = "^1.0.0" +sphinx-autodoc-typehints = "^1.18.1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/rest-example.py b/rest-example.py index 96586835..e60ebd54 100644 --- a/rest-example.py +++ b/rest-example.py @@ -1,12 +1,14 @@ from polygon import RESTClient from polygon.rest.models import Sort -c = RESTClient() +client = RESTClient() -aggs = c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") +aggs = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") print(aggs) trades = [] -for t in c.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): +for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): trades.append(t) print(trades) + +print(client.list_trades("AAA", timestamp="2022-04-20", limit=5, raw=True)) From b98052c9e5c28583c03d736144ce2ed04b9da75c Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Thu, 28 Apr 2022 10:36:09 -0400 Subject: [PATCH 14/41] Conditions And Exchanges (#127) --- polygon/rest/__init__.py | 11 +++- polygon/rest/models/__init__.py | 15 ++---- polygon/rest/models/conditions.py | 52 +++++++++++++++++++ polygon/rest/models/dividends.py | 17 +------ polygon/rest/models/exchanges.py | 22 ++++++++ polygon/rest/models/markets.py | 19 +++++-- polygon/rest/models/shared.py | 62 +++++++++++++++++++++++ polygon/rest/models/tickers.py | 20 +------- polygon/rest/reference.py | 84 ++++++++++++++++++++++++++++--- 9 files changed, 243 insertions(+), 59 deletions(-) create mode 100644 polygon/rest/models/conditions.py create mode 100644 polygon/rest/models/exchanges.py create mode 100644 polygon/rest/models/shared.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index a101edf1..31f100f1 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,7 +1,14 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient -from .reference import MarketsClient, TickersClient, SplitsClient, DividendsClient +from .reference import ( + MarketsClient, + TickersClient, + SplitsClient, + DividendsClient, + ConditionsClient, + ExchangesClient, +) class RESTClient( @@ -12,5 +19,7 @@ class RESTClient( TickersClient, SplitsClient, DividendsClient, + ConditionsClient, + ExchangesClient, ): pass diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index a6a9c916..85139477 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -5,15 +5,6 @@ from .tickers import * from .splits import * from .dividends import * - -from enum import Enum - - -class Sort(Enum): - ASC = "asc" - DESC = "desc" - - -class Order(Enum): - ASC = "asc" - DESC = "desc" +from .conditions import * +from .exchanges import * +from .shared import * diff --git a/polygon/rest/models/conditions.py b/polygon/rest/models/conditions.py new file mode 100644 index 00000000..52b1e6aa --- /dev/null +++ b/polygon/rest/models/conditions.py @@ -0,0 +1,52 @@ +from typing import Optional +from .shared import AssetClass, DataType +from dataclasses import dataclass + + +@dataclass +class SipMapping: + CTA: Optional[str] = None + OPRA: Optional[str] = None + UTP: Optional[str] = None + + +@dataclass +class Consolidated: + updates_high_low: Optional[bool] = None + updates_open_close: Optional[bool] = None + updates_volume: Optional[bool] = None + + +@dataclass +class MarketCenter: + updates_high_low: Optional[bool] = None + updates_open_close: Optional[bool] = None + updates_volume: Optional[bool] = None + + +@dataclass +class UpdateRules: + consolidated: Optional[Consolidated] = None + market_center: Optional[MarketCenter] = None + + +@dataclass +class Condition: + "Condition contains data for a condition that Polygon.io uses." + abbreviation: Optional[str] = None + asset_class: Optional[AssetClass] = None + data_types: Optional[DataType] = None + description: Optional[str] = None + exchange: Optional[int] = None + id: Optional[int] = None + legacy: Optional[bool] = None + name: Optional[str] = None + sip_mapping: Optional[SipMapping] = None + Type: Optional[ + str + ] = None # todo: 'type' is a keyword so here I capitalized. Should we capital case all dataclasses? + update_rules: Optional[UpdateRules] = None + + @staticmethod + def from_dict(d): + return Condition(**d) diff --git a/polygon/rest/models/dividends.py b/polygon/rest/models/dividends.py index b691812a..f70adf9f 100644 --- a/polygon/rest/models/dividends.py +++ b/polygon/rest/models/dividends.py @@ -1,23 +1,8 @@ from typing import Optional -from enum import Enum +from .shared import DividendType, Frequency from dataclasses import dataclass -class DividendType(Enum): - CD = "CD" - SC = "SC" - LT = "LT" - ST = "ST" - - -class Frequency(Enum): - OneTime = 0 - Anually = 1 - BiAnually = 2 - Quarterly = 4 - Monthly = 12 - - @dataclass class Dividend: "Dividend contains data for a historical cash dividend, including the ticker symbol, declaration date, ex-dividend date, record date, pay date, frequency, and amount." diff --git a/polygon/rest/models/exchanges.py b/polygon/rest/models/exchanges.py new file mode 100644 index 00000000..64527710 --- /dev/null +++ b/polygon/rest/models/exchanges.py @@ -0,0 +1,22 @@ +from typing import Optional +from .shared import AssetClass, Locale, ExchangeType +from dataclasses import dataclass + + +@dataclass +class Exchange: + "Exchange contains data for a condition that Polygon.io uses." + acronym: Optional[str] = None + asset_class: Optional[AssetClass] = None + id: Optional[int] = None + locale: Optional[Locale] = None + mic: Optional[str] = None + name: Optional[str] = None + operating_mic: Optional[str] = None + participant_id: Optional[str] = None + type: Optional[ExchangeType] = None + url: Optional[str] = None + + @staticmethod + def from_dict(d): + return Exchange(**d) diff --git a/polygon/rest/models/markets.py b/polygon/rest/models/markets.py index b2b3078f..efa5b2ff 100644 --- a/polygon/rest/models/markets.py +++ b/polygon/rest/models/markets.py @@ -1,7 +1,20 @@ -from typing import Optional, Dict +from typing import Optional from dataclasses import dataclass +@dataclass +class Currencies: + crypto: Optional[str] = None + fx: Optional[str] = None + + +@dataclass +class Exchanges: + nasdaq: Optional[str] = None + nyse: Optional[str] = None + otc: Optional[str] = None + + @dataclass class MarketHoliday: "MarketHoliday contains data for upcoming market holidays and their open/close times." @@ -21,9 +34,9 @@ def from_dict(d): class MarketStatus: "MarketStatus contains data for the current trading status of the exchanges and overall financial markets." after_hours: Optional[bool] = None - currencies: Optional[Dict[str, str]] = None + currencies: Optional[Currencies] = None early_hours: Optional[bool] = None - exchanges: Optional[Dict[str, str]] = None + exchanges: Optional[Exchanges] = None market: Optional[str] = None server_time: Optional[str] = None diff --git a/polygon/rest/models/shared.py b/polygon/rest/models/shared.py new file mode 100644 index 00000000..c8af7626 --- /dev/null +++ b/polygon/rest/models/shared.py @@ -0,0 +1,62 @@ +from enum import Enum + + +class Sort(Enum): + ASC = "asc" + DESC = "desc" + + +class Order(Enum): + ASC = "asc" + DESC = "desc" + + +class Locale(Enum): + US = "us" + GLOBAL = "global" + + +class Market(Enum): + STOCKS = "stocks" + CRYPTO = "crypto" + FX = "fx" + + +class AssetClass(Enum): + STOCKS = "stocks" + OPTIONS = "options" + CRYPTO = "crypto" + FX = "fx" + + +class DividendType(Enum): + CD = "CD" + SC = "SC" + LT = "LT" + ST = "ST" + + +class Frequency(Enum): + OneTime = 0 + Anually = 1 + BiAnually = 2 + Quarterly = 4 + Monthly = 12 + + +class DataType(Enum): + DataTrade = "trade" + DataBBO = "bbo" + DataNBBO = "nbbo" + + +class SIP(Enum): + CTA = "CTA" + UTP = "UTP" + OPRA = "OPRA" + + +class ExchangeType(Enum): + exchange = "exchange" + TRF = "TRF" + SIP = "SIP" diff --git a/polygon/rest/models/tickers.py b/polygon/rest/models/tickers.py index d5382a8a..681fd669 100644 --- a/polygon/rest/models/tickers.py +++ b/polygon/rest/models/tickers.py @@ -1,26 +1,8 @@ from typing import Optional, List -from enum import Enum +from .shared import Locale, Market, AssetClass from dataclasses import dataclass -class Locale(Enum): - US = "us" - GLOBAL = "global" - - -class Market(Enum): - STOCKS = "stocks" - CRYPTO = "crypto" - FX = "fx" - - -class AssetClass(Enum): - STOCKS = "stocks" - OPTIONS = "options" - CRYPTO = "crypto" - FX = "fx" - - @dataclass class Address: address1: Optional[str] = None diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 63c96402..bc0c7487 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -15,6 +15,10 @@ Dividend, DividendType, Frequency, + Condition, + DataType, + SIP, + Exchange, ) from urllib3 import HTTPResponse @@ -129,7 +133,7 @@ def get_ticker_details( path=url, params=params, deserializer=TickerDetails.from_dict, raw=raw ) - def get_ticker_news( + def list_ticker_news( self, ticker: Optional[str] = None, ticker_lt: Optional[str] = None, @@ -143,7 +147,7 @@ def get_ticker_news( published_utc_gte: Optional[str] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, - ) -> Union[TickerDetails, HTTPResponse]: + ) -> Union[Iterator[TickerNews], HTTPResponse]: """ Get the most recent news articles relating to a stock ticker symbol, including a summary of the article and a link to the original source. @@ -158,14 +162,17 @@ def get_ticker_news( """ url = "/v2/reference/news" - return self._get( - path=url, params=params, deserializer=TickerNews.from_dict, raw=raw + return self._paginate( + path=url, + params=self._get_params(self.list_ticker_news, locals()), + raw=raw, + deserializer=TickerNews.from_dict, ) def get_ticker_types( self, - asset_class: Optional[AssetClass] = None, - locale: Optional[Locale] = None, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, ) -> Union[TickerTypes, HTTPResponse]: @@ -264,13 +271,13 @@ def list_dividends( pay_date_lte: Optional[str] = None, pay_date_gt: Optional[str] = None, pay_date_gte: Optional[str] = None, - frequency: Optional[Frequency] = None, + frequency: Optional[Union[int, Frequency]] = None, cash_amount: Optional[float] = None, cash_amount_lt: Optional[float] = None, cash_amount_lte: Optional[float] = None, cash_amount_gt: Optional[float] = None, cash_amount_gte: Optional[float] = None, - dividend_type: Optional[DividendType] = None, + dividend_type: Optional[Union[str, DividendType]] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, @@ -323,3 +330,64 @@ def list_dividends( raw=raw, deserializer=Dividend.from_dict, ) + + +class ConditionsClient(BaseClient): + def list_conditions( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + data_type: Optional[Union[str, DataType]] = None, + id: Optional[int] = None, + sip: Optional[Union[str, SIP]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Iterator[Condition], HTTPResponse]: + """ + List all conditions that Polygon.io uses. + + :param asset_class: Filter for conditions within a given asset class. + :param data_type: Data types that this condition applies to. + :param id: Filter for conditions with a given ID. + :param sip: Filter by SIP. If the condition contains a mapping for that SIP, the condition will be returned. + :param limit: Limit the number of results returned, default is 10 and max is 1000. + :param sort: Sort field used for ordering. + :param order: Order results based on the sort field. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of conditions + """ + url = "/v3/reference/conditions" + + return self._paginate( + path=url, + params=self._get_params(self.list_conditions, locals()), + raw=raw, + deserializer=Condition.from_dict, + ) + + +class ExchangesClient(BaseClient): + def get_exchanges( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Exchange, HTTPResponse]: + """ + List all exchanges that Polygon.io knows about. + + :param asset_class: Filter by asset class. + :param locale: Filter by locale. + :param params: Any additional query params + :param raw: Return HTTPResponse object instead of results object + :return: List of quotes + """ + url = "/v3/reference/exchanges" + + return self._get( + path=url, params=params, deserializer=Exchange.from_dict, raw=raw + ) From a6411de37833e93091809cb6c72766a241f84616 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:28:35 -0400 Subject: [PATCH 15/41] try fix readthedocs build --- .readthedocs.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..37ce2e3c --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,15 @@ +# https://docs.readthedocs.io/en/latest/config-file/index.html#configuration-file +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +python: + version: 3.10 + install: + - method: pip + path: . + extra_requirements: + - sphinx-autodoc-typehints~=1.18.1 + From bbe54518ca5e315c3f53e5d5881c2312193fb8ea Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:31:57 -0400 Subject: [PATCH 16/41] try fix readthedocs build (2) --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 37ce2e3c..01308621 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,7 +6,7 @@ sphinx: configuration: docs/source/conf.py python: - version: 3.10 + version: 3.8 install: - method: pip path: . From 71a5e4c2ae28df1edaf281457b94664d449a4829 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:37:43 -0400 Subject: [PATCH 17/41] try fix readthedocs build (3) --- .readthedocs.yml | 15 ++++++++------- docs/source/Reference.rst | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 01308621..4ab7ba85 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,11 +5,12 @@ version: 2 sphinx: configuration: docs/source/conf.py -python: - version: 3.8 - install: - - method: pip - path: . - extra_requirements: - - sphinx-autodoc-typehints~=1.18.1 +build: + os: ubuntu-20.04 + tools: + python: "3.10" + jobs: + pre_create_environment: + - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + - poetry install diff --git a/docs/source/Reference.rst b/docs/source/Reference.rst index 2f4210ef..074fa3e7 100644 --- a/docs/source/Reference.rst +++ b/docs/source/Reference.rst @@ -21,7 +21,7 @@ List ticker details ==================== Get ticker news ==================== -.. automethod:: polygon.RESTClient.get_ticker_news +.. automethod:: polygon.RESTClient.list_ticker_news ==================== Get ticker types From 601ac5e27bb494aae393ca9835c0c5de9c1d16e0 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:38:43 -0400 Subject: [PATCH 18/41] try fix readthedocs build (4) --- .readthedocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index 4ab7ba85..005215ab 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -12,5 +12,6 @@ build: jobs: pre_create_environment: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + - source $HOME/.poetry/env - poetry install From a473264ee10dec73b5dd469264e5986460c0a9c1 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:41:53 -0400 Subject: [PATCH 19/41] Rst update and quick fixes (#129) --- docs/source/Reference.rst | 22 ++++++++++++++++++---- polygon/rest/models/conditions.py | 4 +--- polygon/rest/models/shared.py | 18 +++++++++--------- polygon/rest/reference.py | 2 +- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/docs/source/Reference.rst b/docs/source/Reference.rst index 074fa3e7..a74caf64 100644 --- a/docs/source/Reference.rst +++ b/docs/source/Reference.rst @@ -4,9 +4,14 @@ Reference =============== ==================== -List market holidays +Get market holidays ==================== -.. automethod:: polygon.RESTClient.list_market_holidays +.. automethod:: polygon.RESTClient.get_market_holidays + +==================== +Get market status +==================== +.. automethod:: polygon.RESTClient.get_market_status ==================== List tickers @@ -14,12 +19,12 @@ List tickers .. automethod:: polygon.RESTClient.list_tickers ==================== -List ticker details +Get ticker details ==================== .. automethod:: polygon.RESTClient.get_ticker_details ==================== -Get ticker news +List ticker news ==================== .. automethod:: polygon.RESTClient.list_ticker_news @@ -38,3 +43,12 @@ List dividends ==================== .. automethod:: polygon.RESTClient.list_dividends +==================== +List conditions +==================== +.. automethod:: polygon.RESTClient.list_conditions + +==================== +Get exchanges +==================== +.. automethod:: polygon.RESTClient.get_exchanges diff --git a/polygon/rest/models/conditions.py b/polygon/rest/models/conditions.py index 52b1e6aa..81949353 100644 --- a/polygon/rest/models/conditions.py +++ b/polygon/rest/models/conditions.py @@ -42,9 +42,7 @@ class Condition: legacy: Optional[bool] = None name: Optional[str] = None sip_mapping: Optional[SipMapping] = None - Type: Optional[ - str - ] = None # todo: 'type' is a keyword so here I capitalized. Should we capital case all dataclasses? + type: Optional[str] = None update_rules: Optional[UpdateRules] = None @staticmethod diff --git a/polygon/rest/models/shared.py b/polygon/rest/models/shared.py index c8af7626..3b7b3d4a 100644 --- a/polygon/rest/models/shared.py +++ b/polygon/rest/models/shared.py @@ -37,17 +37,17 @@ class DividendType(Enum): class Frequency(Enum): - OneTime = 0 - Anually = 1 - BiAnually = 2 - Quarterly = 4 - Monthly = 12 + ONE_TIME = 0 + ANUALLY = 1 + BIANUALLY = 2 + QUARTERLY = 4 + MONTHLY = 12 class DataType(Enum): - DataTrade = "trade" - DataBBO = "bbo" - DataNBBO = "nbbo" + DATA_TRADE = "trade" + DATA_BBO = "bbo" + DATA_NBBO = "nbbo" class SIP(Enum): @@ -57,6 +57,6 @@ class SIP(Enum): class ExchangeType(Enum): - exchange = "exchange" + EXCHANGE = "exchange" TRF = "TRF" SIP = "SIP" diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index bc0c7487..67bf2647 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -24,7 +24,7 @@ # https://polygon.io/docs/stocks class MarketsClient(BaseClient): - def list_market_holidays( + def get_market_holidays( self, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[List[MarketHoliday], HTTPResponse]: """ From 1b42f260c705e0639790e40cf67e462e0fb4e076 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:43:41 -0400 Subject: [PATCH 20/41] try fix readthedocs build (5) --- .readthedocs.yml | 12 +++--------- docs/requirements.txt | 1 + 2 files changed, 4 insertions(+), 9 deletions(-) create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml index 005215ab..7e83cd34 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,13 +5,7 @@ version: 2 sphinx: configuration: docs/source/conf.py -build: - os: ubuntu-20.04 - tools: - python: "3.10" - jobs: - pre_create_environment: - - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - - - source $HOME/.poetry/env - - poetry install +python: + install: + - requirements: docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..5977ad6f --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +sphinx-autodoc-typehints~=1.18.1 From 6aaa58e85a575dda380cb1fc4bd4de8d5da513ea Mon Sep 17 00:00:00 2001 From: Miles Dayoub <38268139+mcdayoub@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:45:09 -0400 Subject: [PATCH 21/41] aggs endpoints (#128) * aggs endpoints * aggs endpoints * aggs models optional * aggs models optional * fixed result_keys --- polygon/rest/aggs.py | 84 +++++++++++++++++++++++++++++-- polygon/rest/base.py | 3 ++ polygon/rest/models/aggs.py | 99 +++++++++++++++++++++++++++++++++---- tests/mocks.py | 14 +++++- tests/test_aggs.py | 61 ++++++++++++++++++++++- 5 files changed, 247 insertions(+), 14 deletions(-) diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index 7c90e0ca..9643711a 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -1,6 +1,7 @@ +from email.headerregistry import Group from .base import BaseClient from typing import Optional, Any, Dict, List, Union -from .models import Agg, Sort +from .models import Agg, GroupedDailyAgg, DailyOpenCloseAgg, PreviousCloseAgg, Sort from urllib3 import HTTPResponse from datetime import datetime @@ -22,7 +23,6 @@ def get_aggs( ) -> Union[List[Agg], HTTPResponse]: """ Get aggregate bars for a ticker over a given date range in custom time window sizes. - :param ticker: The ticker symbol. :param multiplier: The size of the timespan multiplier. :param timespan: The size of the time window. @@ -34,7 +34,6 @@ def get_aggs( :param params: Any additional query params :param raw: Return raw object instead of results object :return: List of aggregates - :rtype: List[Agg] """ if isinstance(from_, datetime): from_ = int(from_.timestamp() * 1000) @@ -50,3 +49,82 @@ def get_aggs( deserializer=Agg.from_dict, raw=raw, ) + + def get_grouped_daily_aggs( + self, + date: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[List[GroupedDailyAgg], HTTPResponse]: + """ + Get the daily open, high, low, and close (OHLC) for the entire market. + + :param date: The beginning date for the aggregate window. + :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: List of grouped daily aggregates + """ + url = f"/v2/aggs/grouped/locale/us/market/stocks/{date}" + + return self._get( + path=url, + params=self._get_params(self.get_grouped_daily_aggs, locals()), + result_key="results", + deserializer=GroupedDailyAgg.from_dict, + raw=raw, + ) + + def get_daily_open_close_agg( + self, + ticker: str, + date: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[DailyOpenCloseAgg, HTTPResponse]: + """ + Get the open, close and afterhours prices of a stock symbol on a certain date. + + :param ticker: The exchange symbol that this item is traded under. + :param date: The beginning date for the aggregate window. + :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Daily open close aggregate + """ + url = f"/v1/open-close/{ticker}/{date}" + + return self._get( + path=url, + params=self._get_params(self.get_daily_open_close_agg, locals()), + deserializer=DailyOpenCloseAgg.from_dict, + raw=raw, + ) + + def get_previous_close_agg( + self, + ticker: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[PreviousCloseAgg, HTTPResponse]: + """ + Get the previous day's open, high, low, and close (OHLC) for the specified stock ticker. + + :param ticker: The ticker symbol of the stock/equity. + :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Previous close aggregate + """ + url = f"/v2/aggs/ticker/{ticker}/prev" + + return self._get( + path=url, + params=self._get_params(self.get_previous_close_agg, locals()), + result_key="results", + deserializer=PreviousCloseAgg.from_dict, + raw=raw, + ) diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 0fed618d..fcad62c4 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -61,6 +61,9 @@ def _get( if result_key: obj = obj[result_key] + else: + # If the result_key does not exist, still need to put the results in a list + obj = [obj] if deserializer: obj = [deserializer(o) for o in obj] diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py index 7b3548a5..5b947523 100644 --- a/polygon/rest/models/aggs.py +++ b/polygon/rest/models/aggs.py @@ -4,24 +4,105 @@ @dataclass class Agg: - timestamp: int open: float high: float low: float close: float volume: float vwap: Optional[float] + timestamp: Optional[int] transactions: Optional[int] @staticmethod def from_dict(d): return Agg( - timestamp=d["t"], - open=d["o"], - high=d["h"], - low=d["l"], - close=d["c"], - volume=d["v"], - vwap=d.get("vw", None), - transactions=d.get("n", None), + d.get("o", None), + d.get("h", None), + d.get("l", None), + d.get("c", None), + d.get("v", None), + d.get("vw", None), + d.get("t", None), + d.get("n", None), + ) + + +@dataclass +class GroupedDailyAgg: + ticker: str + open: float + high: float + low: float + close: float + volume: float + vwap: Optional[float] + timestamp: Optional[int] + transactions: Optional[int] + + @staticmethod + def from_dict(d): + return GroupedDailyAgg( + d.get("T", None), + d.get("o", None), + d.get("h", None), + d.get("l", None), + d.get("c", None), + d.get("v", None), + d.get("vw", None), + d.get("t", None), + d.get("n", None), + ) + + +@dataclass +class DailyOpenCloseAgg: + after_hours: Optional[float] + close: float + from_: str + high: float + low: float + open: float + pre_market: Optional[float] + status: Optional[str] + symbol: str + volume: float + + @staticmethod + def from_dict(d): + return DailyOpenCloseAgg( + d.get("afterHours", None), + d.get("close", None), + d.get("from", None), + d.get("high", None), + d.get("low", None), + d.get("open", None), + d.get("preMarket", None), + d.get("status", None), + d.get("symbol", None), + d.get("volume", None), + ) + + +@dataclass +class PreviousCloseAgg: + ticker: str + close: float + high: float + low: float + open: float + timestamp: Optional[float] + volume: float + vwap: Optional[float] + + @staticmethod + def from_dict(d): + return PreviousCloseAgg( + d.get("T", None), + d.get("c", None), + d.get("h", None), + d.get("l", None), + d.get("o", None), + d.get("t", None), + d.get("v", None), + d.get("vw", None), ) diff --git a/tests/mocks.py b/tests/mocks.py index 896bf5c7..a00bae89 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -6,7 +6,19 @@ ( "/v2/aggs/ticker/AAPL/range/1/day/2005-04-01/2005-04-04", '{"ticker":"AAPL","queryCount":2,"resultsCount":2,"adjusted":true,"results":[{"v":6.42646396e+08,"vw":1.469,"o":1.5032,"c":1.4604,"h":1.5064,"l":1.4489,"t":1112331600000,"n":82132},{"v":5.78172308e+08,"vw":1.4589,"o":1.4639,"c":1.4675,"h":1.4754,"l":1.4343,"t":1112587200000,"n":65543}],"status":"OK","request_id":"12afda77aab3b1936c5fb6ef4241ae42","count":2}', - ) + ), + ( + "/v2/aggs/grouped/locale/us/market/stocks/2005-04-04", + '{"queryCount":1,"resultsCount":1,"adjusted": true,"results": [{"T":"GIK","v":895345,"vw":9.9979,"o":9.99,"c":10.02,"h":10.02,"l":9.9,"t":1602705600000,"n":96}],"status":"OK","request_id":"eae3ded2d6d43f978125b7a8a609fad9","count":1}', + ), + ( + "/v1/open-close/AAPL/2005-04-01", + '{"status": "OK","from": "2021-04-01","symbol": "AAPL","open": 123.66,"high": 124.18,"low": 122.49,"close": 123,"volume": 75089134,"afterHours": 123,"preMarket": 123.45}', + ), + ( + "/v2/aggs/ticker/AAPL/prev", + '{"ticker":"AAPL","queryCount":1,"resultsCount":1,"adjusted":true,"results":[{"T":"AAPL","v":9.5595226e+07,"vw":158.6074,"o":162.25,"c":156.8,"h":162.34,"l":156.72,"t":1651003200000,"n":899965}],"status":"OK","request_id":"5e5378d5ecaf3df794bb52e45d015d2e","count":1}', + ), ] diff --git a/tests/test_aggs.py b/tests/test_aggs.py index 3a068ce1..961df02b 100644 --- a/tests/test_aggs.py +++ b/tests/test_aggs.py @@ -1,5 +1,10 @@ from polygon import RESTClient -from polygon.rest.models import Agg +from polygon.rest.models import ( + Agg, + GroupedDailyAgg, + DailyOpenCloseAgg, + PreviousCloseAgg, +) from mocks import BaseTest @@ -30,3 +35,57 @@ def test_get_aggs(self): ), ] self.assertEqual(aggs, expected) + + def test_get_grouped_daily_aggs(self): + c = RESTClient("") + aggs = c.get_grouped_daily_aggs("2005-04-04", True) + expected = [ + GroupedDailyAgg( + ticker="GIK", + open=9.99, + high=10.02, + low=9.9, + close=10.02, + volume=895345, + vwap=9.9979, + timestamp=1602705600000, + transactions=96, + ) + ] + self.assertEqual(aggs, expected) + + def test_get_daily_open_close_agg(self): + c = RESTClient("") + aggs = c.get_daily_open_close_agg("AAPL", "2005-04-01", True) + expected = [ + DailyOpenCloseAgg( + after_hours=123, + close=123, + from_="2021-04-01", + high=124.18, + low=122.49, + open=123.66, + pre_market=123.45, + status="OK", + symbol="AAPL", + volume=75089134, + ) + ] + self.assertEqual(aggs, expected) + + def test_get_previous_close_agg(self): + c = RESTClient("") + aggs = c.get_previous_close_agg("AAPL") + expected = [ + PreviousCloseAgg( + ticker="AAPL", + close=156.8, + high=162.34, + low=156.72, + open=162.25, + timestamp=1651003200000, + volume=95595226.0, + vwap=158.6074, + ) + ] + self.assertEqual(aggs, expected) From db03e5bd7181e42373287c006a522e6a25b979b7 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:59:16 -0400 Subject: [PATCH 22/41] update readme --- README.md | 108 ++++++++----------------------------------------- pyproject.toml | 1 + 2 files changed, 18 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 6a1636e1..f3f63577 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -[![Build Status](https://drone.polygon.io/api/badges/polygon-io/client-python/status.svg)](https://drone.polygon.io/polygon-io/client-python) +[![Build Status](https://github.com/polygon-io/client-python/actions/workflows/test/badge.svg)]() [![PyPI version](https://badge.fury.io/py/polygon-api-client.svg)](https://badge.fury.io/py/polygon-api-client) +[![Docs](https://readthedocs.org/projects/polygon-api-client/badge/?version=latest)](https://polygon-api-client.readthedocs.io/en/latest/) # Polygon Python Client - WebSocket & RESTful APIs @@ -11,105 +12,30 @@ For a basic product overview, check out our [setup and use documentation](https: ### Install -`pip install polygon-api-client` - -`polygon-api-client` supports python version >= 3.6 - -## Simple WebSocket Demo -```python -import time - -from polygon import WebSocketClient, STOCKS_CLUSTER - - -def my_custom_process_message(message): - print("this is my custom message processing", message) - - -def my_custom_error_handler(ws, error): - print("this is my custom error handler", error) - +Requires python version >= 3.7 -def my_custom_close_handler(ws): - print("this is my custom close handler") - - -def main(): - key = 'your api key' - my_client = WebSocketClient(STOCKS_CLUSTER, key, my_custom_process_message) - my_client.run_async() - - my_client.subscribe("T.MSFT", "T.AAPL", "T.AMD", "T.NVDA") - time.sleep(1) - - my_client.close_connection() - - -if __name__ == "__main__": - main() -``` +`pip install polygon-api-client` -## Simple REST Demo +## REST Demos +### Getting aggs ```python from polygon import RESTClient - -def main(): - key = "your api key" - - # RESTClient can be used as a context manager to facilitate closing the underlying http session - # https://requests.readthedocs.io/en/master/user/advanced/#session-objects - with RESTClient(key) as client: - resp = client.stocks_equities_daily_open_close("AAPL", "2021-06-11") - print(f"On: {resp.from_} Apple opened at {resp.open} and closed at {resp.close}") - - -if __name__ == '__main__': - main() - +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. +aggs = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") ``` -### Query parameters for REST calls - -Every function call under our RESTClient has the `query_params` kwargs. These kwargs are passed along and mapped 1:1 -as query parameters to the underling HTTP call. For more information on the different query parameters please reference -our [API Docs](https://polygon.io/docs/). - -#### Example with query parameters - +### Getting trades ```python -import datetime - from polygon import RESTClient +from polygon.rest.models import Sort +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. -def ts_to_datetime(ts) -> str: - return datetime.datetime.fromtimestamp(ts / 1000.0).strftime('%Y-%m-%d %H:%M') - - -def main(): - key = "your api key" - - # RESTClient can be used as a context manager to facilitate closing the underlying http session - # https://requests.readthedocs.io/en/master/user/advanced/#session-objects - with RESTClient(key) as client: - from_ = "2021-01-01" - to = "2021-02-01" - resp = client.stocks_equities_aggregates("AAPL", 1, "minute", from_, to, unadjusted=False) - - print(f"Minute aggregates for {resp.ticker} between {from_} and {to}.") - - for result in resp.results: - dt = ts_to_datetime(result["t"]) - print(f"{dt}\n\tO: {result['o']}\n\tH: {result['h']}\n\tL: {result['l']}\n\tC: {result['c']} ") - - -if __name__ == '__main__': - main() -``` - -## Notes about the REST Client - -We use swagger as our API spec and we used this swagger to generate most of the code that defines the REST client. -We made this decision due to the size of our API, many endpoints and object definitions, and to accommodate future changes. +trades = [] +for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): + trades.append(t) +``` +### Getting raw response +To handle the raw [urllib3 response](https://urllib3.readthedocs.io/en/stable/reference/urllib3.response.html?highlight=response#response) yourself, pass `raw=True`. diff --git a/pyproject.toml b/pyproject.toml index 1722a69e..26207f9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ types-urllib3 = "^1.26.13" httpretty = "^1.1.4" Sphinx = "^4.5.0" sphinx-rtd-theme = "^1.0.0" +# keep this in sync with docs/requirements.txt for readthedocs.org sphinx-autodoc-typehints = "^1.18.1" [build-system] From 11661eb53f2a769867a34ff21a4e60f2bb32453c Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 12:00:06 -0400 Subject: [PATCH 23/41] remove build badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f3f63577..ee6cf1a2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -[![Build Status](https://github.com/polygon-io/client-python/actions/workflows/test/badge.svg)]() [![PyPI version](https://badge.fury.io/py/polygon-api-client.svg)](https://badge.fury.io/py/polygon-api-client) [![Docs](https://readthedocs.org/projects/polygon-api-client/badge/?version=latest)](https://polygon-api-client.readthedocs.io/en/latest/) From 0aa8bc5bf561754f737824701991af39c8e64e00 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 12:02:07 -0400 Subject: [PATCH 24/41] clean readme --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ee6cf1a2..fd5e3bac 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,15 @@ # Polygon Python Client - WebSocket & RESTful APIs -Python client for the Polygon.io [Stocks API](https://polygon.io) - -## Getting Started - -For a basic product overview, check out our [setup and use documentation](https://polygon.io/sockets) +Python client for the [Polygon.io API](https://polygon.io). +## Getting started ### Install -Requires python version >= 3.7 - `pip install polygon-api-client` -## REST Demos +Requires python version >= 3.7 + ### Getting aggs ```python from polygon import RESTClient From e4065d74c8e145aec83bcb0f3a0177aa20035cc3 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 12:03:00 -0400 Subject: [PATCH 25/41] readme raw response example --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd5e3bac..ec8867e8 100644 --- a/README.md +++ b/README.md @@ -33,4 +33,11 @@ for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.AS ``` ### Getting raw response -To handle the raw [urllib3 response](https://urllib3.readthedocs.io/en/stable/reference/urllib3.response.html?highlight=response#response) yourself, pass `raw=True`. +To handle the raw [urllib3 response](https://urllib3.readthedocs.io/en/stable/reference/urllib3.response.html?highlight=response#response) yourself, pass `raw=True`: + +```python +from polygon import RESTClient + +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. +response = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04", raw=True) +``` From 300cc99aceec4b8144ce6d7debec65f5959be7f9 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 12:03:46 -0400 Subject: [PATCH 26/41] fit on half 1440p screen --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ec8867e8..6fbf6ded 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Requires python version >= 3.7 ```python from polygon import RESTClient -client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key. aggs = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") ``` @@ -25,7 +25,7 @@ aggs = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") from polygon import RESTClient from polygon.rest.models import Sort -client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key. trades = [] for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): @@ -38,6 +38,6 @@ To handle the raw [urllib3 response](https://urllib3.readthedocs.io/en/stable/re ```python from polygon import RESTClient -client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key as first parameter. +client = RESTClient() # Uses POLYGON_API_KEY env var. Can optionally supply your key. response = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04", raw=True) ``` From e047ea957258ab45f1e522c81641522343216552 Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Thu, 28 Apr 2022 13:14:56 -0400 Subject: [PATCH 27/41] use setupclass (#130) --- tests/mocks.py | 12 ++++-------- tests/test_aggs.py | 15 +++++---------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/tests/mocks.py b/tests/mocks.py index a00bae89..02e2b15c 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -23,13 +23,9 @@ class BaseTest(unittest.TestCase): - setup = False - - def setUp(self): - if self.setup: - return + @classmethod + def setUpClass(cls): + cls.c = RESTClient("") httpretty.enable(verbose=True, allow_net_connect=False) - c = RESTClient("") for m in mocks: - httpretty.register_uri(httpretty.GET, c.BASE + m[0], m[1]) - self.setup = True + httpretty.register_uri(httpretty.GET, cls.c.BASE + m[0], m[1]) diff --git a/tests/test_aggs.py b/tests/test_aggs.py index 961df02b..5e651786 100644 --- a/tests/test_aggs.py +++ b/tests/test_aggs.py @@ -1,17 +1,15 @@ -from polygon import RESTClient +from mocks import BaseTest from polygon.rest.models import ( Agg, GroupedDailyAgg, DailyOpenCloseAgg, PreviousCloseAgg, ) -from mocks import BaseTest class AggsTest(BaseTest): def test_get_aggs(self): - c = RESTClient("") - aggs = c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") + aggs = self.c.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") expected = [ Agg( open=1.5032, @@ -37,8 +35,7 @@ def test_get_aggs(self): self.assertEqual(aggs, expected) def test_get_grouped_daily_aggs(self): - c = RESTClient("") - aggs = c.get_grouped_daily_aggs("2005-04-04", True) + aggs = self.c.get_grouped_daily_aggs("2005-04-04", True) expected = [ GroupedDailyAgg( ticker="GIK", @@ -55,8 +52,7 @@ def test_get_grouped_daily_aggs(self): self.assertEqual(aggs, expected) def test_get_daily_open_close_agg(self): - c = RESTClient("") - aggs = c.get_daily_open_close_agg("AAPL", "2005-04-01", True) + aggs = self.c.get_daily_open_close_agg("AAPL", "2005-04-01", True) expected = [ DailyOpenCloseAgg( after_hours=123, @@ -74,8 +70,7 @@ def test_get_daily_open_close_agg(self): self.assertEqual(aggs, expected) def test_get_previous_close_agg(self): - c = RESTClient("") - aggs = c.get_previous_close_agg("AAPL") + aggs = self.c.get_previous_close_agg("AAPL") expected = [ PreviousCloseAgg( ticker="AAPL", From 82dfa1d62dfe34b7f162c762b8ad7c64d8bb15b8 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 13:20:20 -0400 Subject: [PATCH 28/41] remove module index --- docs/source/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 6cc7d51d..10a3a0cd 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,5 +17,4 @@ Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` * :ref:`search` From 94881d6c4fada669e8abd18383912cb7cc62a1f8 Mon Sep 17 00:00:00 2001 From: zack <43246297+clickingbuttons@users.noreply.github.com> Date: Thu, 28 Apr 2022 13:26:54 -0400 Subject: [PATCH 29/41] set docs env var in conf.py --- docs/Makefile | 2 +- docs/source/conf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 7f823a57..bed4efb2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - POLYGON_API_KEY="POLYGON_API_KEY" $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/conf.py b/docs/source/conf.py index cef0ef75..235ee004 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,7 +14,7 @@ import sys sys.path.insert(0, os.path.abspath('../..')) print('docs path', sys.path[0]) - +os.environ['POLYGON_API_KEY'] = 'POLYGON_API_KEY' # -- Project information ----------------------------------------------------- From 53ab30e4b232b4356caeaeb56fb28d2d275d9f3b Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Thu, 28 Apr 2022 15:01:24 -0400 Subject: [PATCH 30/41] Date param support (#131) * add time mult * add example --- polygon/rest/aggs.py | 16 ++++++------ polygon/rest/base.py | 27 ++++++++++++++++++--- polygon/rest/quotes.py | 11 +++++---- polygon/rest/reference.py | 51 ++++++++++++++++++++------------------- polygon/rest/trades.py | 13 +++++----- rest-example.py | 7 ++++-- 6 files changed, 76 insertions(+), 49 deletions(-) diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index 9643711a..1822471e 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -1,9 +1,8 @@ -from email.headerregistry import Group from .base import BaseClient from typing import Optional, Any, Dict, List, Union from .models import Agg, GroupedDailyAgg, DailyOpenCloseAgg, PreviousCloseAgg, Sort from urllib3 import HTTPResponse -from datetime import datetime +from datetime import datetime, date # https://polygon.io/docs/stocks class AggsClient(BaseClient): @@ -13,8 +12,8 @@ def get_aggs( multiplier: int, timespan: str, # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp - from_: Union[str, int, datetime], - to: Union[str, int, datetime], + from_: Union[str, int, datetime, date], + to: Union[str, int, datetime, date], adjusted: Optional[bool] = None, sort: Optional[Union[str, Sort]] = None, limit: Optional[int] = None, @@ -23,11 +22,12 @@ def get_aggs( ) -> Union[List[Agg], HTTPResponse]: """ Get aggregate bars for a ticker over a given date range in custom time window sizes. + :param ticker: The ticker symbol. :param multiplier: The size of the timespan multiplier. :param timespan: The size of the time window. - :param _from: The start of the aggregate time window as YYYY-MM-DD, Unix MS Timestamps, or a datetime. - :param to: The end of the aggregate time window as YYYY-MM-DD, Unix MS Timestamps, or a datetime. + :param _from: The start of the aggregate time window as YYYY-MM-DD, a date, Unix MS Timestamp, or a datetime. + :param to: The end of the aggregate time window as YYYY-MM-DD, a date, Unix MS Timestamp, or a datetime. :param adjusted: Whether or not the results are adjusted for splits. By default, results are adjusted. Set this to false to get results that are NOT adjusted for splits. :param sort: Sort the results by timestamp. asc will return results in ascending order (oldest at the top), desc will return results in descending order (newest at the top).The end of the aggregate time window. :param limit: Limits the number of base aggregates queried to create the aggregate results. Max 50000 and Default 5000. Read more about how limit is used to calculate aggregate results in our article on Aggregate Data API Improvements. @@ -36,10 +36,10 @@ def get_aggs( :return: List of aggregates """ if isinstance(from_, datetime): - from_ = int(from_.timestamp() * 1000) + from_ = int(from_.timestamp() * self.time_mult("millis")) if isinstance(to, datetime): - to = int(to.timestamp() * 1000) + to = int(to.timestamp() * self.time_mult("millis")) url = f"/v2/aggs/ticker/{ticker}/range/{multiplier}/{timespan}/{from_}/{to}" return self._get( diff --git a/polygon/rest/base.py b/polygon/rest/base.py index fcad62c4..19b5efd2 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -3,12 +3,13 @@ import urllib3 import inspect from enum import Enum -from typing import Optional, Any +from typing import Optional, Any, Dict +from datetime import datetime base = "https://api.polygon.io" env_key = "POLYGON_API_KEY" -# https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html + class BaseClient: def __init__( self, @@ -18,6 +19,7 @@ def __init__( num_pools: int = 10, retries=3, base: str = base, + verbose: bool = False, ): if api_key is None: raise Exception( @@ -26,12 +28,14 @@ def __init__( self.API_KEY = api_key self.BASE = base + # https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html # https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool self.client = urllib3.PoolManager( num_pools=num_pools, headers={"Authorization": "Bearer " + self.API_KEY} ) self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout) self.retries = retries + self.verbose = verbose def _decode(self, resp): return json.loads(resp.data.decode("utf-8")) @@ -47,6 +51,8 @@ def _get( if params is None: params = {} params = {str(k): str(v) for k, v in params.items() if v is not None} + if self.verbose: + print("_get", path, params) resp = self.client.request( "GET", self.BASE + path, fields=params, retries=self.retries ) @@ -70,7 +76,20 @@ def _get( return obj - def _get_params(self, fn, caller_locals): + @staticmethod + def time_mult(timestamp_res: str) -> int: + if timestamp_res == "nanos": + return 1000000000 + elif timestamp_res == "micros": + return 1000000 + elif timestamp_res == "millis": + return 1000 + + return 1 + + def _get_params( + self, fn, caller_locals: Dict[str, Any], datetime_res: str = "nanos" + ): params = caller_locals["params"] if params is None: params = {} @@ -84,6 +103,8 @@ def _get_params(self, fn, caller_locals): val = caller_locals.get(argname, v.default) if isinstance(val, Enum): val = val.value + elif isinstance(val, datetime): + val = int(val.timestamp() * self.time_mult(datetime_res)) if val is not None: params[argname.replace("_", ".")] = val diff --git a/polygon/rest/quotes.py b/polygon/rest/quotes.py index 198e3adf..e602e61f 100644 --- a/polygon/rest/quotes.py +++ b/polygon/rest/quotes.py @@ -2,17 +2,18 @@ from typing import Optional, Any, Dict, List, Union from .models import Quote, LastQuote, Sort, Order from urllib3 import HTTPResponse +from datetime import datetime, date # https://polygon.io/docs/stocks class QuotesClient(BaseClient): def list_quotes( self, ticker: str, - timestamp: Optional[str] = None, - timestamp_lt: Optional[str] = None, - timestamp_lte: Optional[str] = None, - timestamp_gt: Optional[str] = None, - timestamp_gte: Optional[str] = None, + timestamp: Optional[Union[str, int, datetime, date]] = None, + timestamp_lt: Optional[Union[str, int, datetime, date]] = None, + timestamp_lte: Optional[Union[str, int, datetime, date]] = None, + timestamp_gt: Optional[Union[str, int, datetime, date]] = None, + timestamp_gte: Optional[Union[str, int, datetime, date]] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 67bf2647..592632a2 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -21,6 +21,7 @@ Exchange, ) from urllib3 import HTTPResponse +from datetime import date # https://polygon.io/docs/stocks class MarketsClient(BaseClient): @@ -200,11 +201,11 @@ def list_splits( ticker_lte: Optional[str] = None, ticker_gt: Optional[str] = None, ticker_gte: Optional[str] = None, - execution_date: Optional[str] = None, - execution_date_lt: Optional[str] = None, - execution_date_lte: Optional[str] = None, - execution_date_gt: Optional[str] = None, - execution_date_gte: Optional[str] = None, + execution_date: Optional[Union[str, date]] = None, + execution_date_lt: Optional[Union[str, date]] = None, + execution_date_lte: Optional[Union[str, date]] = None, + execution_date_gt: Optional[Union[str, date]] = None, + execution_date_gte: Optional[Union[str, date]] = None, reverse_split: Optional[bool] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, @@ -251,26 +252,26 @@ def list_dividends( ticker_lte: Optional[str] = None, ticker_gt: Optional[str] = None, ticker_gte: Optional[str] = None, - ex_dividend_date: Optional[str] = None, - ex_dividend_date_lt: Optional[str] = None, - ex_dividend_date_lte: Optional[str] = None, - ex_dividend_date_gt: Optional[str] = None, - ex_dividend_date_gte: Optional[str] = None, - record_date: Optional[str] = None, - record_date_lt: Optional[str] = None, - record_date_lte: Optional[str] = None, - record_date_gt: Optional[str] = None, - record_date_gte: Optional[str] = None, - declaration_date: Optional[str] = None, - declaration_date_lt: Optional[str] = None, - declaration_date_lte: Optional[str] = None, - declaration_date_gt: Optional[str] = None, - declaration_date_gte: Optional[str] = None, - pay_date: Optional[str] = None, - pay_date_lt: Optional[str] = None, - pay_date_lte: Optional[str] = None, - pay_date_gt: Optional[str] = None, - pay_date_gte: Optional[str] = None, + ex_dividend_date: Optional[Union[str, date]] = None, + ex_dividend_date_lt: Optional[Union[str, date]] = None, + ex_dividend_date_lte: Optional[Union[str, date]] = None, + ex_dividend_date_gt: Optional[Union[str, date]] = None, + ex_dividend_date_gte: Optional[Union[str, date]] = None, + record_date: Optional[Union[str, date]] = None, + record_date_lt: Optional[Union[str, date]] = None, + record_date_lte: Optional[Union[str, date]] = None, + record_date_gt: Optional[Union[str, date]] = None, + record_date_gte: Optional[Union[str, date]] = None, + declaration_date: Optional[Union[str, date]] = None, + declaration_date_lt: Optional[Union[str, date]] = None, + declaration_date_lte: Optional[Union[str, date]] = None, + declaration_date_gt: Optional[Union[str, date]] = None, + declaration_date_gte: Optional[Union[str, date]] = None, + pay_date: Optional[Union[str, date]] = None, + pay_date_lt: Optional[Union[str, date]] = None, + pay_date_lte: Optional[Union[str, date]] = None, + pay_date_gt: Optional[Union[str, date]] = None, + pay_date_gte: Optional[Union[str, date]] = None, frequency: Optional[Union[int, Frequency]] = None, cash_amount: Optional[float] = None, cash_amount_lt: Optional[float] = None, diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py index 85cac40a..c652493b 100644 --- a/polygon/rest/trades.py +++ b/polygon/rest/trades.py @@ -2,17 +2,18 @@ from typing import Optional, Any, Dict, Union, Iterator from .models import Trade, Sort, Order from urllib3 import HTTPResponse +from datetime import datetime, date + -# https://polygon.io/docs/stocks class TradesClient(BaseClient): def list_trades( self, ticker: str, - timestamp: Optional[str] = None, - timestamp_lt: Optional[str] = None, - timestamp_lte: Optional[str] = None, - timestamp_gt: Optional[str] = None, - timestamp_gte: Optional[str] = None, + timestamp: Optional[Union[str, int, datetime, date]] = None, + timestamp_lt: Optional[Union[str, int, datetime, date]] = None, + timestamp_lte: Optional[Union[str, int, datetime, date]] = None, + timestamp_gt: Optional[Union[str, int, datetime, date]] = None, + timestamp_gte: Optional[Union[str, int, datetime, date]] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, diff --git a/rest-example.py b/rest-example.py index e60ebd54..b16f12e7 100644 --- a/rest-example.py +++ b/rest-example.py @@ -1,9 +1,12 @@ from polygon import RESTClient from polygon.rest.models import Sort +from datetime import date, datetime -client = RESTClient() +client = RESTClient(verbose=True) -aggs = client.get_aggs("AAPL", 1, "day", "2005-04-01", "2005-04-04") +aggs = client.get_aggs("AAPL", 1, "day", "2005-04-04", "2005-04-04") +print(aggs) +aggs = client.get_aggs("AAPL", 1, "day", date(2005, 4, 4), datetime(2005, 4, 4)) print(aggs) trades = [] From eecd477a28ccd7d284a4223d170ee76a6cd959aa Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Thu, 28 Apr 2022 15:48:00 -0400 Subject: [PATCH 31/41] Tickers tests (#133) --- polygon/rest/models/tickers.py | 6 +- polygon/rest/reference.py | 8 +- tests/mocks.py | 21 ++++ tests/test_tickers.py | 196 +++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 tests/test_tickers.py diff --git a/polygon/rest/models/tickers.py b/polygon/rest/models/tickers.py index 681fd669..a7c2b0ca 100644 --- a/polygon/rest/models/tickers.py +++ b/polygon/rest/models/tickers.py @@ -31,6 +31,9 @@ class Ticker: cik: Optional[str] = None composite_figi: Optional[str] = None currency_name: Optional[str] = None + currency_symbol: Optional[str] = None + base_currency_symbol: Optional[str] = None + base_currency_name: Optional[str] = None delisted_utc: Optional[str] = None last_updated_utc: Optional[str] = None locale: Optional[Locale] = None @@ -57,6 +60,7 @@ class TickerDetails: currency_name: Optional[str] = None delisted_utc: Optional[str] = None description: Optional[str] = None + ticker_root: Optional[str] = None homepage_url: Optional[str] = None list_date: Optional[str] = None locale: Optional[Locale] = None @@ -109,4 +113,4 @@ class TickerTypes: @staticmethod def from_dict(d): - return TickerNews(**d) + return TickerTypes(**d) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 592632a2..9fd848ff 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -176,7 +176,7 @@ def get_ticker_types( locale: Optional[Union[str, Locale]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, - ) -> Union[TickerTypes, HTTPResponse]: + ) -> Union[List[TickerTypes], HTTPResponse]: """ List all ticker types that Polygon.io has. @@ -189,7 +189,11 @@ def get_ticker_types( url = "/v3/reference/tickers/types" return self._get( - path=url, params=params, deserializer=TickerTypes.from_dict, raw=raw + path=url, + params=params, + deserializer=TickerTypes.from_dict, + raw=raw, + result_key="results", ) diff --git a/tests/mocks.py b/tests/mocks.py index 02e2b15c..e0b62bc4 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -19,12 +19,33 @@ "/v2/aggs/ticker/AAPL/prev", '{"ticker":"AAPL","queryCount":1,"resultsCount":1,"adjusted":true,"results":[{"T":"AAPL","v":9.5595226e+07,"vw":158.6074,"o":162.25,"c":156.8,"h":162.34,"l":156.72,"t":1651003200000,"n":899965}],"status":"OK","request_id":"5e5378d5ecaf3df794bb52e45d015d2e","count":1}', ), + ( + "/v3/reference/tickers", + '{"results":[{"ticker":"A","name":"Agilent Technologies Inc.","market":"stocks","locale":"us","primary_exchange":"XNYS","type":"CS","active":true,"currency_name":"usd","cik":"0001090872","composite_figi":"BBG000C2V3D6","share_class_figi":"BBG001SCTQY4","last_updated_utc":"2022-04-27T00:00:00Z"},{"ticker":"AA","name":"Alcoa Corporation","market":"stocks","locale":"us","primary_exchange":"XNYS","type":"CS","active":true,"currency_name":"usd","cik":"0001675149","composite_figi":"BBG00B3T3HD3","share_class_figi":"BBG00B3T3HF1","last_updated_utc":"2022-04-27T00:00:00Z"}],"status":"OK","request_id":"37089bb3b4ef99a796cdc82ff971e447","count":2,"next_url":"https://api.polygon.io/v3/reference/tickers?cursor=YWN0aXZlPXRydWUmZGF0ZT0yMDIyLTA0LTI3JmxpbWl0PTImb3JkZXI9YXNjJnBhZ2VfbWFya2VyPUFBJTdDZjEyMmJjYmY4YWQwNzRmZmJlMTZmNjkxOWQ0ZDc3NjZlMzA3MWNmNmU1Nzg3OGE0OGU1NjQ1YzQyM2U3NzJhOSZzb3J0PXRpY2tlcg"}', + ), + ( + "/v3/reference/tickers?cursor=YWN0aXZlPXRydWUmZGF0ZT0yMDIyLTA0LTI3JmxpbWl0PTImb3JkZXI9YXNjJnBhZ2VfbWFya2VyPUFBJTdDZjEyMmJjYmY4YWQwNzRmZmJlMTZmNjkxOWQ0ZDc3NjZlMzA3MWNmNmU1Nzg3OGE0OGU1NjQ1YzQyM2U3NzJhOSZzb3J0PXRpY2tlcg", + '{"results":[{"ticker":"AAA","name":"AAF First Priority CLO Bond ETF","market":"stocks","locale":"us","primary_exchange":"ARCX","type":"ETF","active":true,"currency_name":"usd","composite_figi":"BBG00X5FSP48","share_class_figi":"BBG00X5FSPZ4","last_updated_utc":"2022-04-27T00:00:00Z"},{"ticker":"AAAU","name":"Goldman Sachs Physical Gold ETF Shares","market":"stocks","locale":"us","primary_exchange":"BATS","type":"ETF","active":true,"currency_name":"usd","cik":"0001708646","composite_figi":"BBG00LPXX872","share_class_figi":"BBG00LPXX8Z1","last_updated_utc":"2022-04-27T00:00:00Z"}],"status":"OK","request_id":"40d60d83fa0628503b4d13387b7bde2a","count":2}', + ), + ( + "/v3/reference/tickers/AAPL", + '{"ticker":"AAPL","name":"Apple Inc.","market":"stocks","locale":"us","primary_exchange":"XNAS","type":"CS","active":true,"currency_name":"usd","cik":"0000320193","composite_figi":"BBG000B9XRY4","share_class_figi":"BBG001S5N8V8","market_cap":2.6714924917e+12,"phone_number":"(408) 996-1010","address":{"address1":"ONE APPLE PARK WAY","city":"CUPERTINO","state":"CA","postal_code":"95014"},"description":"Apple designs a wide variety of consumer electronic devices, including smartphones (iPhone), tablets (iPad), PCs (Mac), smartwatches (Apple Watch), AirPods, and TV boxes (Apple TV), among others. The iPhone makes up the majority of Apples total revenue. In addition, Apple offers its customers a variety of services such as Apple Music, iCloud, Apple Care, Apple TV+, Apple Arcade, Apple Card, and Apple Pay, among others. Apples products run internally developed software and semiconductors, and the firm is well known for its integration of hardware, software and services. Apples products are distributed online as well as through company-owned stores and third-party retailers. The company generates roughly 40 of its revenue from the Americas, with the remainder earned internationally.","sic_code":"3571","sic_description":"ELECTRONIC COMPUTERS","ticker_root":"AAPL","homepage_url":"https://www.apple.com","total_employees":154000,"list_date":"1980-12-12","branding":{"logo_url":"https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_logo.svg","icon_url":"https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_icon.png"},"share_class_shares_outstanding":16319440000,"weighted_shares_outstanding":16319441000}', + ), + ( + "/v2/reference/news", + '{"results":[{"id":"JeJEhAVoKaqJ2zF9nzQYMg07UlEeWlis6Dsop33TPQY","publisher":{"name":"MarketWatch","homepage_url":"https://www.marketwatch.com/","logo_url":"https://s3.polygon.io/public/assets/news/logos/marketwatch.svg","favicon_url":"https://s3.polygon.io/public/assets/news/favicons/marketwatch.ico"},"title":"Theres a big hole in the Feds theory of inflation—incomes are falling at a record 10.9 rate","author":"MarketWatch","published_utc":"2022-04-28T17:08:00Z","article_url":"https://www.marketwatch.com/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705","tickers":["MSFT","TSN","NFLX","AMZN"],"amp_url":"https://www.marketwatch.com/amp/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705","image_url":"https://images.mktw.net/im-533637/social","description":"If inflation is all due to an overly generous federal government giving its people too much money, then our inflation problem is about to go away."}],"status":"OK","request_id":"f5248459196e12f27520afd41cee5126","count":10}', + ), + ( + "/v3/reference/tickers/types", + '{"results":[{"code":"CS","description":"Common Stock","asset_class":"stocks","locale":"us"},{"code":"PFD","description":"Preferred Stock","asset_class":"stocks","locale":"us"},{"code":"WARRANT","description":"Warrant","asset_class":"stocks","locale":"us"},{"code":"RIGHT","description":"Rights","asset_class":"stocks","locale":"us"},{"code":"BOND","description":"Corporate Bond","asset_class":"stocks","locale":"us"},{"code":"ETF","description":"Exchange Traded Fund","asset_class":"stocks","locale":"us"},{"code":"ETN","description":"Exchange Traded Note","asset_class":"stocks","locale":"us"},{"code":"SP","description":"Structured Product","asset_class":"stocks","locale":"us"},{"code":"ADRC","description":"American Depository Receipt Common","asset_class":"stocks","locale":"us"},{"code":"ADRW","description":"American Depository Receipt Warrants","asset_class":"stocks","locale":"us"},{"code":"ADRR","description":"American Depository Receipt Rights","asset_class":"stocks","locale":"us"},{"code":"FUND","description":"Fund","asset_class":"stocks","locale":"us"},{"code":"BASKET","description":"Basket","asset_class":"stocks","locale":"us"},{"code":"UNIT","description":"Unit","asset_class":"stocks","locale":"us"},{"code":"LT","description":"Liquidating Trust","asset_class":"stocks","locale":"us"}],"status":"OK","request_id":"efbfc7c2304bba6c2f19a2567f568134","count":15}', + ), ] class BaseTest(unittest.TestCase): @classmethod def setUpClass(cls): + cls.maxDiff = None cls.c = RESTClient("") httpretty.enable(verbose=True, allow_net_connect=False) for m in mocks: diff --git a/tests/test_tickers.py b/tests/test_tickers.py new file mode 100644 index 00000000..fc14190e --- /dev/null +++ b/tests/test_tickers.py @@ -0,0 +1,196 @@ +from polygon import RESTClient +from polygon.rest.models import ( + Ticker, + TickerDetails, + TickerNews, + TickerTypes, +) +from mocks import BaseTest + + +class TickersTest(BaseTest): + def test_list_tickers(self): + tickers = [t for t in self.c.list_tickers()] + expected = [ + Ticker( + active=True, + cik=None, + composite_figi="BBG00X5FSP48", + currency_name="usd", + currency_symbol=None, + base_currency_symbol=None, + base_currency_name=None, + delisted_utc=None, + last_updated_utc="2022-04-27T00:00:00Z", + locale="us", + market="stocks", + name="AAF First Priority CLO Bond ETF", + primary_exchange="ARCX", + share_class_figi="BBG00X5FSPZ4", + ticker="AAA", + type="ETF", + ), + Ticker( + active=True, + cik="0001708646", + composite_figi="BBG00LPXX872", + currency_name="usd", + currency_symbol=None, + base_currency_symbol=None, + base_currency_name=None, + delisted_utc=None, + last_updated_utc="2022-04-27T00:00:00Z", + locale="us", + market="stocks", + name="Goldman Sachs Physical Gold ETF Shares", + primary_exchange="BATS", + share_class_figi="BBG00LPXX8Z1", + ticker="AAAU", + type="ETF", + ), + ] + self.assertEqual(tickers, expected) + + def test_get_ticker_details(self): + details = self.c.get_ticker_details("AAPL") + expected = [ + TickerDetails( + active=True, + address={ + "address1": "ONE APPLE PARK WAY", + "city": "CUPERTINO", + "state": "CA", + "postal_code": "95014", + }, + branding={ + "logo_url": "https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_logo.svg", + "icon_url": "https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_icon.png", + }, + cik="0000320193", + composite_figi="BBG000B9XRY4", + currency_name="usd", + delisted_utc=None, + description="Apple designs a wide variety of consumer electronic devices, including smartphones (iPhone), tablets (iPad), PCs (Mac), smartwatches (Apple Watch), AirPods, and TV boxes (Apple TV), among others. The iPhone makes up the majority of Apples total revenue. In addition, Apple offers its customers a variety of services such as Apple Music, iCloud, Apple Care, Apple TV+, Apple Arcade, Apple Card, and Apple Pay, among others. Apples products run internally developed software and semiconductors, and the firm is well known for its integration of hardware, software and services. Apples products are distributed online as well as through company-owned stores and third-party retailers. The company generates roughly 40 of its revenue from the Americas, with the remainder earned internationally.", + ticker_root="AAPL", + homepage_url="https://www.apple.com", + list_date="1980-12-12", + locale="us", + market="stocks", + market_cap=2671492491700.0, + name="Apple Inc.", + phone_number="(408) 996-1010", + primary_exchange="XNAS", + share_class_figi="BBG001S5N8V8", + share_class_shares_outstanding=16319440000, + sic_code="3571", + sic_description="ELECTRONIC COMPUTERS", + ticker="AAPL", + total_employees=154000, + type="CS", + weighted_shares_outstanding=16319441000, + ) + ] + self.assertEqual(details, expected) + + def test_list_ticker_news(self): + news = [t for t in self.c.list_ticker_news("NFLX")] + expected = [ + TickerNews( + amp_url="https://www.marketwatch.com/amp/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705", + article_url="https://www.marketwatch.com/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705", + author="MarketWatch", + description="If inflation is all due to an overly generous federal government giving its people too much money, then our inflation problem is about to go away.", + id="JeJEhAVoKaqJ2zF9nzQYMg07UlEeWlis6Dsop33TPQY", + image_url="https://images.mktw.net/im-533637/social", + keywords=None, + published_utc="2022-04-28T17:08:00Z", + publisher={ + "name": "MarketWatch", + "homepage_url": "https://www.marketwatch.com/", + "logo_url": "https://s3.polygon.io/public/assets/news/logos/marketwatch.svg", + "favicon_url": "https://s3.polygon.io/public/assets/news/favicons/marketwatch.ico", + }, + tickers=["MSFT", "TSN", "NFLX", "AMZN"], + title="Theres a big hole in the Feds theory of inflation—incomes are falling at a record 10.9 rate", + ) + ] + self.assertEqual(news, expected) + + def test_get_ticker_types(self): + types = self.c.get_ticker_types("stocks") + expected = [ + TickerTypes( + asset_class="stocks", code="CS", description="Common Stock", locale="us" + ), + TickerTypes( + asset_class="stocks", + code="PFD", + description="Preferred Stock", + locale="us", + ), + TickerTypes( + asset_class="stocks", code="WARRANT", description="Warrant", locale="us" + ), + TickerTypes( + asset_class="stocks", code="RIGHT", description="Rights", locale="us" + ), + TickerTypes( + asset_class="stocks", + code="BOND", + description="Corporate Bond", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="ETF", + description="Exchange Traded Fund", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="ETN", + description="Exchange Traded Note", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="SP", + description="Structured Product", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="ADRC", + description="American Depository Receipt Common", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="ADRW", + description="American Depository Receipt Warrants", + locale="us", + ), + TickerTypes( + asset_class="stocks", + code="ADRR", + description="American Depository Receipt Rights", + locale="us", + ), + TickerTypes( + asset_class="stocks", code="FUND", description="Fund", locale="us" + ), + TickerTypes( + asset_class="stocks", code="BASKET", description="Basket", locale="us" + ), + TickerTypes( + asset_class="stocks", code="UNIT", description="Unit", locale="us" + ), + TickerTypes( + asset_class="stocks", + code="LT", + description="Liquidating Trust", + locale="us", + ), + ] + + self.assertEqual(types, expected) From 75b0aa226b61a101e50d768b0c5237326903b651 Mon Sep 17 00:00:00 2001 From: Miles Dayoub <38268139+mcdayoub@users.noreply.github.com> Date: Thu, 28 Apr 2022 16:25:50 -0400 Subject: [PATCH 32/41] Trade endpoints (#134) * added last trade and last trade crypto --- polygon/rest/base.py | 6 ++-- polygon/rest/models/trades.py | 65 +++++++++++++++++++++++++++++++++++ polygon/rest/trades.py | 50 ++++++++++++++++++++++++++- rest-example.py | 7 ---- 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 19b5efd2..18293c26 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -67,8 +67,10 @@ def _get( if result_key: obj = obj[result_key] - else: - # If the result_key does not exist, still need to put the results in a list + + # If obj is not yet a list, need to turn it into a list + # This is for the Daily Open/Close and Last Trade endpoints + if type(obj) != list: obj = [obj] if deserializer: diff --git a/polygon/rest/models/trades.py b/polygon/rest/models/trades.py index 5fc7a1d5..e14cfa0b 100644 --- a/polygon/rest/models/trades.py +++ b/polygon/rest/models/trades.py @@ -21,3 +21,68 @@ class Trade: @staticmethod def from_dict(d): return Trade(**d) + + +@dataclass +class LastTrade: + ticker: str + trf_timestamp: int + sequence_number: float + sip_timestamp: int + participant_timestamp: int + conditions: List[int] + correction: int + id: str + price: float + trf_id: int + size: float + exchange: int + tape: int + + @staticmethod + def from_dict(d): + return LastTrade( + d.get("T", None), + d.get("f", None), + d.get("q", None), + d.get("t", None), + d.get("y", None), + d.get("c", None), + d.get("e", None), + d.get("i", None), + d.get("p", None), + d.get("r", None), + d.get("s", None), + d.get("x", None), + d.get("z", None), + ) + + +@dataclass +class Last: + conditions: List[int] + exchange: int + price: float + size: float + timestamp: int + + @staticmethod + def from_dict(d): + return Last(**d) + + +@dataclass +class LastTradeCrypto: + last: Last + ticker: str + status: str + request_id: str + + @staticmethod + def from_dict(d): + return LastTradeCrypto( + d.get("last", None), + d.get("symbol", None), + d.get("status", None), + d.get("request_id", None), + ) diff --git a/polygon/rest/trades.py b/polygon/rest/trades.py index c652493b..89dd24eb 100644 --- a/polygon/rest/trades.py +++ b/polygon/rest/trades.py @@ -1,6 +1,6 @@ from .base import BaseClient from typing import Optional, Any, Dict, Union, Iterator -from .models import Trade, Sort, Order +from .models import Trade, LastTrade, LastTradeCrypto, Sort, Order from urllib3 import HTTPResponse from datetime import datetime, date @@ -44,3 +44,51 @@ def list_trades( raw=raw, deserializer=Trade.from_dict, ) + + def get_last_trade( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[LastTrade, HTTPResponse]: + """ + Get the most recent trade for a ticker. + + :param ticker: The ticker symbol of the asset + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Last trade + """ + url = f"/v2/last/trade/{ticker}" + + return self._get( + path=url, + params=self._get_params(self.get_last_trade, locals()), + result_key="results", + deserializer=LastTrade.from_dict, + raw=raw, + ) + + def get_last_trade_crypto( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[LastTrade, HTTPResponse]: + """ + Get the most recent trade for a ticker. + + :param ticker: The ticker symbol of the asset + :param params: Any additional query params + :param raw: Return raw object instead of results object + :return: Last trade + """ + url = f"/v1/last/crypto/{from_}/{to}" + + return self._get( + path=url, + params=self._get_params(self.get_last_trade_crypto, locals()), + deserializer=LastTradeCrypto.from_dict, + raw=raw, + ) diff --git a/rest-example.py b/rest-example.py index b16f12e7..b2bca0cc 100644 --- a/rest-example.py +++ b/rest-example.py @@ -8,10 +8,3 @@ print(aggs) aggs = client.get_aggs("AAPL", 1, "day", date(2005, 4, 4), datetime(2005, 4, 4)) print(aggs) - -trades = [] -for t in client.list_trades("AAA", timestamp="2022-04-20", limit=5, sort=Sort.ASC): - trades.append(t) -print(trades) - -print(client.list_trades("AAA", timestamp="2022-04-20", limit=5, raw=True)) From 4e0f66e71a74ad81c7597fd7cb8544d0c36353d8 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Fri, 29 Apr 2022 10:21:04 -0400 Subject: [PATCH 33/41] Market tests (#135) --- polygon/rest/models/markets.py | 9 ++- polygon/rest/reference.py | 8 +- tests/mocks.py | 8 ++ tests/test_markets.py | 141 +++++++++++++++++++++++++++++++++ tests/test_tickers.py | 1 - 5 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 tests/test_markets.py diff --git a/polygon/rest/models/markets.py b/polygon/rest/models/markets.py index efa5b2ff..85adfa7b 100644 --- a/polygon/rest/models/markets.py +++ b/polygon/rest/models/markets.py @@ -42,4 +42,11 @@ class MarketStatus: @staticmethod def from_dict(d): - return MarketStatus(**d) + return MarketStatus( + d.get("afterHours", None), + d.get("currencies", None), + d.get("earlyHours", None), + d.get("exchanges", None), + d.get("market", None), + d.get("serverTime", None), + ) diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 9fd848ff..4b278d31 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -23,7 +23,7 @@ from urllib3 import HTTPResponse from datetime import date -# https://polygon.io/docs/stocks + class MarketsClient(BaseClient): def get_market_holidays( self, params: Optional[Dict[str, Any]] = None, raw: bool = False @@ -38,7 +38,11 @@ def get_market_holidays( url = "/v1/marketstatus/upcoming" return self._get( - path=url, params=params, deserializer=MarketHoliday.from_dict, raw=raw + path=url, + params=params, + deserializer=MarketHoliday.from_dict, + raw=raw, + result_key="", ) def get_market_status( diff --git a/tests/mocks.py b/tests/mocks.py index e0b62bc4..fd2a81bf 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -39,6 +39,14 @@ "/v3/reference/tickers/types", '{"results":[{"code":"CS","description":"Common Stock","asset_class":"stocks","locale":"us"},{"code":"PFD","description":"Preferred Stock","asset_class":"stocks","locale":"us"},{"code":"WARRANT","description":"Warrant","asset_class":"stocks","locale":"us"},{"code":"RIGHT","description":"Rights","asset_class":"stocks","locale":"us"},{"code":"BOND","description":"Corporate Bond","asset_class":"stocks","locale":"us"},{"code":"ETF","description":"Exchange Traded Fund","asset_class":"stocks","locale":"us"},{"code":"ETN","description":"Exchange Traded Note","asset_class":"stocks","locale":"us"},{"code":"SP","description":"Structured Product","asset_class":"stocks","locale":"us"},{"code":"ADRC","description":"American Depository Receipt Common","asset_class":"stocks","locale":"us"},{"code":"ADRW","description":"American Depository Receipt Warrants","asset_class":"stocks","locale":"us"},{"code":"ADRR","description":"American Depository Receipt Rights","asset_class":"stocks","locale":"us"},{"code":"FUND","description":"Fund","asset_class":"stocks","locale":"us"},{"code":"BASKET","description":"Basket","asset_class":"stocks","locale":"us"},{"code":"UNIT","description":"Unit","asset_class":"stocks","locale":"us"},{"code":"LT","description":"Liquidating Trust","asset_class":"stocks","locale":"us"}],"status":"OK","request_id":"efbfc7c2304bba6c2f19a2567f568134","count":15}', ), + ( + "/v1/marketstatus/upcoming", + '[{"exchange":"NYSE","name":"Memorial Day","date":"2022-05-30","status":"closed"},{"exchange":"NASDAQ","name":"Memorial Day","date":"2022-05-30","status":"closed"},{"exchange":"NASDAQ","name":"Juneteenth","date":"2022-06-20","status":"closed"},{"exchange":"NYSE","name":"Juneteenth","date":"2022-06-20","status":"closed"},{"exchange":"NYSE","name":"Independence Day","date":"2022-07-04","status":"closed"},{"exchange":"NASDAQ","name":"Independence Day","date":"2022-07-04","status":"closed"},{"exchange":"NYSE","name":"Labor Day","date":"2022-09-05","status":"closed"},{"exchange":"NASDAQ","name":"Labor Day","date":"2022-09-05","status":"closed"},{"exchange":"NYSE","name":"Thanksgiving","date":"2022-11-24","status":"closed"},{"exchange":"NASDAQ","name":"Thanksgiving","date":"2022-11-24","status":"closed"},{"exchange":"NYSE","name":"Thanksgiving","date":"2022-11-25","status":"early-close","open":"2022-11-25T14:30:00.000Z","close":"2022-11-25T18:00:00.000Z"},{"exchange":"NASDAQ","name":"Thanksgiving","date":"2022-11-25","status":"early-close","open":"2022-11-25T14:30:00.000Z","close":"2022-11-25T18:00:00.000Z"},{"exchange":"NYSE","name":"Christmas","date":"2022-12-26","status":"closed"},{"exchange":"NASDAQ","name":"Christmas","date":"2022-12-26","status":"closed"}]', + ), + ( + "/v1/marketstatus/now", + '{"market":"extended-hours","earlyHours":false,"afterHours":true,"serverTime":"2022-04-28T16:48:08-04:00","exchanges":{"nyse":"extended-hours","nasdaq":"extended-hours","otc":"extended-hours"},"currencies":{"fx":"open","crypto":"open"}}', + ), ] diff --git a/tests/test_markets.py b/tests/test_markets.py new file mode 100644 index 00000000..5076babc --- /dev/null +++ b/tests/test_markets.py @@ -0,0 +1,141 @@ +from polygon import RESTClient +from polygon.rest.models import MarketHoliday, MarketStatus +from mocks import BaseTest + + +class MarketsTest(BaseTest): + def test_get_market_holidays(self): + holidays = self.c.get_market_holidays() + expected = [ + MarketHoliday( + close=None, + date="2022-05-30", + exchange="NYSE", + name="Memorial Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-05-30", + exchange="NASDAQ", + name="Memorial Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-06-20", + exchange="NASDAQ", + name="Juneteenth", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-06-20", + exchange="NYSE", + name="Juneteenth", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-07-04", + exchange="NYSE", + name="Independence Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-07-04", + exchange="NASDAQ", + name="Independence Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-09-05", + exchange="NYSE", + name="Labor Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-09-05", + exchange="NASDAQ", + name="Labor Day", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-11-24", + exchange="NYSE", + name="Thanksgiving", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-11-24", + exchange="NASDAQ", + name="Thanksgiving", + open=None, + status="closed", + ), + MarketHoliday( + close="2022-11-25T18:00:00.000Z", + date="2022-11-25", + exchange="NYSE", + name="Thanksgiving", + open="2022-11-25T14:30:00.000Z", + status="early-close", + ), + MarketHoliday( + close="2022-11-25T18:00:00.000Z", + date="2022-11-25", + exchange="NASDAQ", + name="Thanksgiving", + open="2022-11-25T14:30:00.000Z", + status="early-close", + ), + MarketHoliday( + close=None, + date="2022-12-26", + exchange="NYSE", + name="Christmas", + open=None, + status="closed", + ), + MarketHoliday( + close=None, + date="2022-12-26", + exchange="NASDAQ", + name="Christmas", + open=None, + status="closed", + ), + ] + self.assertEqual(holidays, expected) + + def test_get_market_status(self): + status = self.c.get_market_status() + expected = [ + MarketStatus( + after_hours=True, + currencies={"fx": "open", "crypto": "open"}, + early_hours=False, + exchanges={ + "nyse": "extended-hours", + "nasdaq": "extended-hours", + "otc": "extended-hours", + }, + market="extended-hours", + server_time="2022-04-28T16:48:08-04:00", + ) + ] + self.assertEqual(status, expected) diff --git a/tests/test_tickers.py b/tests/test_tickers.py index fc14190e..bcdf5be6 100644 --- a/tests/test_tickers.py +++ b/tests/test_tickers.py @@ -1,4 +1,3 @@ -from polygon import RESTClient from polygon.rest.models import ( Ticker, TickerDetails, From 0b6b71593969cd183aeb7a09d3bc287630ed8acf Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Fri, 29 Apr 2022 10:36:13 -0400 Subject: [PATCH 34/41] add user agent string (#137) * add user agent string * lint --- polygon/rest/base.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/polygon/rest/base.py b/polygon/rest/base.py index 18293c26..f719a8e9 100644 --- a/polygon/rest/base.py +++ b/polygon/rest/base.py @@ -31,7 +31,11 @@ def __init__( # https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html # https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool self.client = urllib3.PoolManager( - num_pools=num_pools, headers={"Authorization": "Bearer " + self.API_KEY} + num_pools=num_pools, + headers={ + "Authorization": "Bearer " + self.API_KEY, + "User-Agent": "Python client", + }, ) self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout) self.retries = retries From 0e0d09b8afd90b4052e820adaea48cb9bd70bd75 Mon Sep 17 00:00:00 2001 From: Miles Dayoub <38268139+mcdayoub@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:12:58 -0400 Subject: [PATCH 35/41] Trades tests (#136) * trades tests * trial error * trial error * style --- tests/mocks.py | 12 +++++++ tests/test_trades.py | 83 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/test_trades.py diff --git a/tests/mocks.py b/tests/mocks.py index fd2a81bf..62f54c20 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -39,6 +39,18 @@ "/v3/reference/tickers/types", '{"results":[{"code":"CS","description":"Common Stock","asset_class":"stocks","locale":"us"},{"code":"PFD","description":"Preferred Stock","asset_class":"stocks","locale":"us"},{"code":"WARRANT","description":"Warrant","asset_class":"stocks","locale":"us"},{"code":"RIGHT","description":"Rights","asset_class":"stocks","locale":"us"},{"code":"BOND","description":"Corporate Bond","asset_class":"stocks","locale":"us"},{"code":"ETF","description":"Exchange Traded Fund","asset_class":"stocks","locale":"us"},{"code":"ETN","description":"Exchange Traded Note","asset_class":"stocks","locale":"us"},{"code":"SP","description":"Structured Product","asset_class":"stocks","locale":"us"},{"code":"ADRC","description":"American Depository Receipt Common","asset_class":"stocks","locale":"us"},{"code":"ADRW","description":"American Depository Receipt Warrants","asset_class":"stocks","locale":"us"},{"code":"ADRR","description":"American Depository Receipt Rights","asset_class":"stocks","locale":"us"},{"code":"FUND","description":"Fund","asset_class":"stocks","locale":"us"},{"code":"BASKET","description":"Basket","asset_class":"stocks","locale":"us"},{"code":"UNIT","description":"Unit","asset_class":"stocks","locale":"us"},{"code":"LT","description":"Liquidating Trust","asset_class":"stocks","locale":"us"}],"status":"OK","request_id":"efbfc7c2304bba6c2f19a2567f568134","count":15}', ), + ( + "/v2/last/trade/AAPL", + '{"results":{"c":[12,37],"i":"237688","p":166.25,"s":2,"x":4,"r":202,"z":3,"T":"AAPL","t":1651179319310617300,"y":1651179319308000000,"f":1651179319310588400,"q":7084210},"status":"OK","request_id":"d4bafa50e72cf9ed19ac538ae1a3185a"}', + ), + ( + "/v1/last/crypto/BTC/USD", + '{"last":{"conditions":[2],"exchange":2,"price":39976.89682331,"size":0.005,"timestamp":1651180409688},"request_id":"d67c9bfe1fa0c29db9177d78b3ab713c","status":"success","symbol":"BTC-USD"}', + ), + ( + "/v3/trades/AAPL", + '{"results":[{"conditions":[12,37],"correction":1,"exchange":11,"id":"183276","participant_timestamp":1651181822461636600,"price":156.43,"sequence_number":7179341,"sip_timestamp":1651181822461979400,"size":10,"tape":3,"trf_id":3,"trf_timestamp":1651181557090806500},{"conditions":[12,37],"correction":1,"exchange":12,"id":"183276","participant_timestamp":1651181822461636600,"price":157.43,"sequence_number":7179341,"sip_timestamp":1651181822461979400,"size":10,"tape":3,"trf_id":3,"trf_timestamp":1651181557090806500}],"status":"OK","request_id":"756f9910624b35a47eb07f21a7a373bb"}', + ), ( "/v1/marketstatus/upcoming", '[{"exchange":"NYSE","name":"Memorial Day","date":"2022-05-30","status":"closed"},{"exchange":"NASDAQ","name":"Memorial Day","date":"2022-05-30","status":"closed"},{"exchange":"NASDAQ","name":"Juneteenth","date":"2022-06-20","status":"closed"},{"exchange":"NYSE","name":"Juneteenth","date":"2022-06-20","status":"closed"},{"exchange":"NYSE","name":"Independence Day","date":"2022-07-04","status":"closed"},{"exchange":"NASDAQ","name":"Independence Day","date":"2022-07-04","status":"closed"},{"exchange":"NYSE","name":"Labor Day","date":"2022-09-05","status":"closed"},{"exchange":"NASDAQ","name":"Labor Day","date":"2022-09-05","status":"closed"},{"exchange":"NYSE","name":"Thanksgiving","date":"2022-11-24","status":"closed"},{"exchange":"NASDAQ","name":"Thanksgiving","date":"2022-11-24","status":"closed"},{"exchange":"NYSE","name":"Thanksgiving","date":"2022-11-25","status":"early-close","open":"2022-11-25T14:30:00.000Z","close":"2022-11-25T18:00:00.000Z"},{"exchange":"NASDAQ","name":"Thanksgiving","date":"2022-11-25","status":"early-close","open":"2022-11-25T14:30:00.000Z","close":"2022-11-25T18:00:00.000Z"},{"exchange":"NYSE","name":"Christmas","date":"2022-12-26","status":"closed"},{"exchange":"NASDAQ","name":"Christmas","date":"2022-12-26","status":"closed"}]', diff --git a/tests/test_trades.py b/tests/test_trades.py new file mode 100644 index 00000000..a1717a0e --- /dev/null +++ b/tests/test_trades.py @@ -0,0 +1,83 @@ +from mocks import BaseTest +from polygon.rest.models import ( + Trade, + LastTrade, + Last, + LastTradeCrypto, +) + + +class TradesTest(BaseTest): + def test_get_last_trade(self): + last_trade = self.c.get_last_trade("AAPL") + expected = [ + LastTrade( + ticker="AAPL", + trf_timestamp=1651179319310588400, + sequence_number=7084210, + sip_timestamp=1651179319310617300, + participant_timestamp=1651179319308000000, + conditions=[12, 37], + correction=None, + id="237688", + price=166.25, + trf_id=202, + size=2, + exchange=4, + tape=3, + ) + ] + self.assertEqual(last_trade, expected) + + def test_get_last_trade_crypto(self): + last_trade_crypto = self.c.get_last_trade_crypto("BTC", "USD") + expected = [ + LastTradeCrypto( + last={ + "conditions": [2], + "exchange": 2, + "price": 39976.89682331, + "size": 0.005, + "timestamp": 1651180409688, + }, + ticker="BTC-USD", + status="success", + request_id="d67c9bfe1fa0c29db9177d78b3ab713c", + ) + ] + self.assertEqual(last_trade_crypto, expected) + + def test_trades(self): + trades = [t for t in self.c.list_trades(ticker="AAPL", limit=2)] + print(trades) + expected = [ + Trade( + conditions=[12, 37], + correction=1, + exchange=11, + id="183276", + participant_timestamp=1651181822461636600, + price=156.43, + sequence_number=7179341, + sip_timestamp=1651181822461979400, + size=10, + tape=3, + trf_id=3, + trf_timestamp=1651181557090806500, + ), + Trade( + conditions=[12, 37], + correction=1, + exchange=12, + id="183276", + participant_timestamp=1651181822461636600, + price=157.43, + sequence_number=7179341, + sip_timestamp=1651181822461979400, + size=10, + tape=3, + trf_id=3, + trf_timestamp=1651181557090806500, + ), + ] + self.assertEqual(trades, expected) From 06334a35995c26c244f770b80c831cc67269268a Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Fri, 29 Apr 2022 11:44:05 -0400 Subject: [PATCH 36/41] add missing automethod docs (#138) * add missing automethod docs * fix name * formatting --- docs/source/Aggs.rst | 25 +++++++++++++++++++++++++ docs/source/Quotes.rst | 1 - docs/source/Trades.rst | 10 ++++++++++ docs/source/index.rst | 1 + 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 docs/source/Aggs.rst diff --git a/docs/source/Aggs.rst b/docs/source/Aggs.rst new file mode 100644 index 00000000..6db60e68 --- /dev/null +++ b/docs/source/Aggs.rst @@ -0,0 +1,25 @@ +.. _aggs_header: + +Aggs +========== + +=========== +Get aggs +=========== +.. automethod:: polygon.RESTClient.get_aggs + +============================ +Get grouped daily aggs +============================ +.. automethod:: polygon.RESTClient.get_grouped_daily_aggs + +============================ +Get daily open close agg +============================ +.. automethod:: polygon.RESTClient.get_daily_open_close_agg + +============================ +Get previous close agg +============================ +.. automethod:: polygon.RESTClient.get_previous_close_agg + diff --git a/docs/source/Quotes.rst b/docs/source/Quotes.rst index 4c379455..f5b7b824 100644 --- a/docs/source/Quotes.rst +++ b/docs/source/Quotes.rst @@ -6,7 +6,6 @@ Quotes =========== List quotes =========== - .. automethod:: polygon.RESTClient.list_quotes ============== diff --git a/docs/source/Trades.rst b/docs/source/Trades.rst index 50e628c4..fc3d9d96 100644 --- a/docs/source/Trades.rst +++ b/docs/source/Trades.rst @@ -7,3 +7,13 @@ Trades List trades =========== .. automethod:: polygon.RESTClient.list_trades + +=========== +Get last trade +=========== +.. automethod:: polygon.RESTClient.get_last_trade + +=========== +Get last trade (crypto) +=========== +.. automethod:: polygon.RESTClient.get_last_trade_crypto diff --git a/docs/source/index.rst b/docs/source/index.rst index 10a3a0cd..36bd6e23 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -8,6 +8,7 @@ This documentation is for the Python client only. For details about the response :caption: Contents: Getting-Started + Aggs Quotes Reference Trades From 49962fb294a29b3ad80cf1f0f81ff6acf2f6b837 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:45:10 -0400 Subject: [PATCH 37/41] Add tests for splits, dividends, conditions, exchanges (#139) --- polygon/rest/reference.py | 8 +- tests/mocks.py | 16 ++ tests/test_conditions.py | 250 ++++++++++++++++++++++++++++++++ tests/test_dividends.py | 110 ++++++++++++++ tests/test_exchanges.py | 298 ++++++++++++++++++++++++++++++++++++++ tests/test_splits.py | 32 ++++ 6 files changed, 712 insertions(+), 2 deletions(-) create mode 100644 tests/test_conditions.py create mode 100644 tests/test_dividends.py create mode 100644 tests/test_exchanges.py create mode 100644 tests/test_splits.py diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index 4b278d31..e7acaa3d 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -385,7 +385,7 @@ def get_exchanges( locale: Optional[Union[str, Locale]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, - ) -> Union[Exchange, HTTPResponse]: + ) -> Union[List[Exchange], HTTPResponse]: """ List all exchanges that Polygon.io knows about. @@ -398,5 +398,9 @@ def get_exchanges( url = "/v3/reference/exchanges" return self._get( - path=url, params=params, deserializer=Exchange.from_dict, raw=raw + path=url, + params=params, + deserializer=Exchange.from_dict, + raw=raw, + result_key="results", ) diff --git a/tests/mocks.py b/tests/mocks.py index 62f54c20..f369ab14 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -59,6 +59,22 @@ "/v1/marketstatus/now", '{"market":"extended-hours","earlyHours":false,"afterHours":true,"serverTime":"2022-04-28T16:48:08-04:00","exchanges":{"nyse":"extended-hours","nasdaq":"extended-hours","otc":"extended-hours"},"currencies":{"fx":"open","crypto":"open"}}', ), + ( + "/v3/reference/splits", + '{"results":[{"execution_date":"2022-07-18","split_from":1,"split_to":20,"ticker":"GOOGL"},{"execution_date":"2022-07-18","split_from":1,"split_to":20,"ticker":"GOOG"},{"execution_date":"2022-07-01","split_from":1,"split_to":3,"ticker":"CTO"},{"execution_date":"2022-06-29","split_from":1,"split_to":10,"ticker":"SHOP"},{"execution_date":"2022-06-22","split_from":1,"split_to":10,"ticker":"SHOP"},{"execution_date":"2022-06-10","split_from":1,"split_to":4,"ticker":"DXCM"},{"execution_date":"2022-06-06","split_from":1,"split_to":20,"ticker":"AMZN"},{"execution_date":"2022-05-20","split_from":2,"split_to":1,"ticker":"BRW"},{"execution_date":"2022-05-16","split_from":1,"split_to":2,"ticker":"CM"},{"execution_date":"2022-05-02","split_from":3,"split_to":4,"ticker":"CIG.C"}],"status":"OK","request_id":"b52de486daf5491e6b9ebdf5e0bf65bc"}', + ), + ( + "/v3/reference/dividends", + '{"results":[{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2025-06-12","frequency":4,"pay_date":"2025-06-30","record_date":"2025-06-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2025-03-13","frequency":4,"pay_date":"2025-03-31","record_date":"2025-03-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-12-12","frequency":4,"pay_date":"2024-12-31","record_date":"2024-12-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-09-12","frequency":4,"pay_date":"2024-09-30","record_date":"2024-09-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-06-13","frequency":4,"pay_date":"2024-06-30","record_date":"2024-06-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-03-14","frequency":4,"pay_date":"2024-03-31","record_date":"2024-03-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2023-12-14","frequency":4,"pay_date":"2023-12-31","record_date":"2023-12-15","ticker":"CSSEN"},{"cash_amount":0.5,"declaration_date":"2022-02-10","dividend_type":"CD","ex_dividend_date":"2023-11-13","frequency":4,"pay_date":"2023-11-15","record_date":"2023-11-14","ticker":"AIRTP"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2023-09-14","frequency":4,"pay_date":"2023-09-30","record_date":"2023-09-15","ticker":"CSSEN"},{"cash_amount":0.5,"declaration_date":"2022-02-10","dividend_type":"CD","ex_dividend_date":"2023-08-11","frequency":4,"pay_date":"2023-08-15","record_date":"2023-08-14","ticker":"AIRTP"}],"status":"OK","request_id":"0326f1f88a2867a7184c116f5b1edd00"}', + ), + ( + "/v3/reference/conditions", + '{"results":[{"id":1,"type":"sale_condition","name":"Acquisition","asset_class":"stocks","sip_mapping":{"UTP":"A"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":2,"type":"sale_condition","name":"Average Price Trade","asset_class":"stocks","sip_mapping":{"CTA":"B","UTP":"W"},"update_rules":{"consolidated":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":3,"type":"sale_condition","name":"Automatic Execution","asset_class":"stocks","sip_mapping":{"CTA":"E"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":4,"type":"sale_condition","name":"Bunched Trade","asset_class":"stocks","sip_mapping":{"UTP":"B"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":5,"type":"sale_condition","name":"Bunched Sold Trade","asset_class":"stocks","sip_mapping":{"UTP":"G"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":6,"type":"sale_condition","name":"CAP Election","asset_class":"stocks","sip_mapping":{"CTA":"I"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"],"legacy":true},{"id":7,"type":"sale_condition","name":"Cash Sale","asset_class":"stocks","sip_mapping":{"CTA":"C","UTP":"C"},"update_rules":{"consolidated":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":8,"type":"sale_condition","name":"Closing Prints","asset_class":"stocks","sip_mapping":{"UTP":"6"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":9,"type":"sale_condition","name":"Cross Trade","asset_class":"stocks","sip_mapping":{"CTA":"X","UTP":"X"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":10,"type":"sale_condition","name":"Derivatively Priced","asset_class":"stocks","sip_mapping":{"CTA":"4","UTP":"4"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]}],"status":"OK","request_id":"4c915a9cb249e40d08d031d70567d615","count":10}', + ), + ( + "/v3/reference/exchanges", + ' {"results":[{"id":1,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE American, LLC","acronym":"AMEX","mic":"XASE","operating_mic":"XNYS","participant_id":"A","url":"https://www.nyse.com/markets/nyse-american"},{"id":2,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq OMX BX, Inc.","mic":"XBOS","operating_mic":"XNAS","participant_id":"B","url":"https://www.nasdaq.com/solutions/nasdaq-bx-stock-market"},{"id":3,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE National, Inc.","acronym":"NSX","mic":"XCIS","operating_mic":"XNYS","participant_id":"C","url":"https://www.nyse.com/markets/nyse-national"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA NYSE TRF","mic":"FINY","operating_mic":"XNYS","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Carteret","mic":"FINN","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Chicago","mic":"FINC","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Alternative Display Facility","mic":"XADF","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":5,"type":"SIP","asset_class":"stocks","locale":"us","name":"Unlisted Trading Privileges","operating_mic":"XNAS","participant_id":"E","url":"https://www.utpplan.com"},{"id":6,"type":"TRF","asset_class":"stocks","locale":"us","name":"International Securities Exchange, LLC - Stocks","mic":"XISE","operating_mic":"XNAS","participant_id":"I","url":"https://nasdaq.com/solutions/nasdaq-ise"},{"id":7,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGA","mic":"EDGA","operating_mic":"XCBO","participant_id":"J","url":"https://www.cboe.com/us/equities"},{"id":8,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGX","mic":"EDGX","operating_mic":"XCBO","participant_id":"K","url":"https://www.cboe.com/us/equities"},{"id":9,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Chicago, Inc.","mic":"XCHI","operating_mic":"XNYS","participant_id":"M","url":"https://www.nyse.com/markets/nyse-chicago"},{"id":10,"type":"exchange","asset_class":"stocks","locale":"us","name":"New York Stock Exchange","mic":"XNYS","operating_mic":"XNYS","participant_id":"N","url":"https://www.nyse.com"},{"id":11,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Arca, Inc.","mic":"ARCX","operating_mic":"XNYS","participant_id":"P","url":"https://www.nyse.com/markets/nyse-arca"},{"id":12,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq","mic":"XNAS","operating_mic":"XNAS","participant_id":"T","url":"https://www.nasdaq.com"},{"id":13,"type":"SIP","asset_class":"stocks","locale":"us","name":"Consolidated Tape Association","operating_mic":"XNYS","participant_id":"S","url":"https://www.nyse.com/data/cta"},{"id":14,"type":"exchange","asset_class":"stocks","locale":"us","name":"Long-Term Stock Exchange","mic":"LTSE","operating_mic":"LTSE","participant_id":"L","url":"https://www.ltse.com"},{"id":15,"type":"exchange","asset_class":"stocks","locale":"us","name":"Investors Exchange","mic":"IEXG","operating_mic":"IEXG","participant_id":"V","url":"https://www.iextrading.com"},{"id":16,"type":"TRF","asset_class":"stocks","locale":"us","name":"Cboe Stock Exchange","mic":"CBSX","operating_mic":"XCBO","participant_id":"W","url":"https://www.cboe.com"},{"id":17,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq Philadelphia Exchange LLC","mic":"XPHL","operating_mic":"XNAS","participant_id":"X","url":"https://www.nasdaq.com/solutions/nasdaq-phlx"},{"id":18,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BYX","mic":"BATY","operating_mic":"XCBO","participant_id":"Y","url":"https://www.cboe.com/us/equities"},{"id":19,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BZX","mic":"BATS","operating_mic":"XCBO","participant_id":"Z","url":"https://www.cboe.com/us/equities"},{"id":20,"type":"exchange","asset_class":"stocks","locale":"us","name":"MIAX Pearl","mic":"EPRL","operating_mic":"MIHI","participant_id":"H","url":"https://www.miaxoptions.com/alerts/pearl-equities"},{"id":21,"type":"exchange","asset_class":"stocks","locale":"us","name":"Members Exchange","mic":"MEMX","operating_mic":"MEMX","participant_id":"U","url":"https://www.memx.com"}],"status":"OK","request_id":"c0109b8a70a931efe47cef085c7a7f5e","count":24}', + ), ] diff --git a/tests/test_conditions.py b/tests/test_conditions.py new file mode 100644 index 00000000..0e1b2fb1 --- /dev/null +++ b/tests/test_conditions.py @@ -0,0 +1,250 @@ +from polygon.rest.models import Condition +from mocks import BaseTest + + +class ConditionsTest(BaseTest): + def test_list_conditions(self): + conditions = [c for c in self.c.list_conditions("stocks")] + expected = [ + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=1, + legacy=None, + name="Acquisition", + sip_mapping={"UTP": "A"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=2, + legacy=None, + name="Average Price Trade", + sip_mapping={"CTA": "B", "UTP": "W"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": False, + "updates_open_close": False, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": False, + "updates_open_close": False, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=3, + legacy=None, + name="Automatic Execution", + sip_mapping={"CTA": "E"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=4, + legacy=None, + name="Bunched Trade", + sip_mapping={"UTP": "B"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=5, + legacy=None, + name="Bunched Sold Trade", + sip_mapping={"UTP": "G"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": False, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": False, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=6, + legacy=True, + name="CAP Election", + sip_mapping={"CTA": "I"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=7, + legacy=None, + name="Cash Sale", + sip_mapping={"CTA": "C", "UTP": "C"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": False, + "updates_open_close": False, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": False, + "updates_open_close": False, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=8, + legacy=None, + name="Closing Prints", + sip_mapping={"UTP": "6"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=9, + legacy=None, + name="Cross Trade", + sip_mapping={"CTA": "X", "UTP": "X"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": True, + "updates_volume": True, + }, + }, + ), + Condition( + abbreviation=None, + asset_class="stocks", + data_types=["trade"], + description=None, + exchange=None, + id=10, + legacy=None, + name="Derivatively Priced", + sip_mapping={"CTA": "4", "UTP": "4"}, + type="sale_condition", + update_rules={ + "consolidated": { + "updates_high_low": True, + "updates_open_close": False, + "updates_volume": True, + }, + "market_center": { + "updates_high_low": True, + "updates_open_close": False, + "updates_volume": True, + }, + }, + ), + ] + self.assertEqual(conditions, expected) diff --git a/tests/test_dividends.py b/tests/test_dividends.py new file mode 100644 index 00000000..925f1f2f --- /dev/null +++ b/tests/test_dividends.py @@ -0,0 +1,110 @@ +from polygon.rest.models import Dividend +from mocks import BaseTest + + +class DividendsTest(BaseTest): + def test_list_dividends(self): + dividends = [d for d in self.c.list_dividends()] + expected = [ + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2025-06-12", + frequency=4, + pay_date="2025-06-30", + record_date="2025-06-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2025-03-13", + frequency=4, + pay_date="2025-03-31", + record_date="2025-03-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2024-12-12", + frequency=4, + pay_date="2024-12-31", + record_date="2024-12-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2024-09-12", + frequency=4, + pay_date="2024-09-30", + record_date="2024-09-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2024-06-13", + frequency=4, + pay_date="2024-06-30", + record_date="2024-06-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2024-03-14", + frequency=4, + pay_date="2024-03-31", + record_date="2024-03-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2023-12-14", + frequency=4, + pay_date="2023-12-31", + record_date="2023-12-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.5, + declaration_date="2022-02-10", + dividend_type="CD", + ex_dividend_date="2023-11-13", + frequency=4, + pay_date="2023-11-15", + record_date="2023-11-14", + ticker="AIRTP", + ), + Dividend( + cash_amount=0.59375, + declaration_date="2020-09-09", + dividend_type="CD", + ex_dividend_date="2023-09-14", + frequency=4, + pay_date="2023-09-30", + record_date="2023-09-15", + ticker="CSSEN", + ), + Dividend( + cash_amount=0.5, + declaration_date="2022-02-10", + dividend_type="CD", + ex_dividend_date="2023-08-11", + frequency=4, + pay_date="2023-08-15", + record_date="2023-08-14", + ticker="AIRTP", + ), + ] + self.assertEqual(dividends, expected) diff --git a/tests/test_exchanges.py b/tests/test_exchanges.py new file mode 100644 index 00000000..13157437 --- /dev/null +++ b/tests/test_exchanges.py @@ -0,0 +1,298 @@ +from polygon.rest.models import Exchange +from mocks import BaseTest + + +class ExchangesTest(BaseTest): + def test_get_exchanges(self): + exchanges = self.c.get_exchanges("stocks") + expected = [ + Exchange( + acronym="AMEX", + asset_class="stocks", + id=1, + locale="us", + mic="XASE", + name="NYSE American, LLC", + operating_mic="XNYS", + participant_id="A", + type="exchange", + url="https://www.nyse.com/markets/nyse-american", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=2, + locale="us", + mic="XBOS", + name="Nasdaq OMX BX, Inc.", + operating_mic="XNAS", + participant_id="B", + type="exchange", + url="https://www.nasdaq.com/solutions/nasdaq-bx-stock-market", + ), + Exchange( + acronym="NSX", + asset_class="stocks", + id=3, + locale="us", + mic="XCIS", + name="NYSE National, Inc.", + operating_mic="XNYS", + participant_id="C", + type="exchange", + url="https://www.nyse.com/markets/nyse-national", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=4, + locale="us", + mic="FINY", + name="FINRA NYSE TRF", + operating_mic="XNYS", + participant_id="D", + type="TRF", + url="https://www.finra.org", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=4, + locale="us", + mic="FINN", + name="FINRA Nasdaq TRF Carteret", + operating_mic="FINR", + participant_id="D", + type="TRF", + url="https://www.finra.org", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=4, + locale="us", + mic="FINC", + name="FINRA Nasdaq TRF Chicago", + operating_mic="FINR", + participant_id="D", + type="TRF", + url="https://www.finra.org", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=4, + locale="us", + mic="XADF", + name="FINRA Alternative Display Facility", + operating_mic="FINR", + participant_id="D", + type="TRF", + url="https://www.finra.org", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=5, + locale="us", + mic=None, + name="Unlisted Trading Privileges", + operating_mic="XNAS", + participant_id="E", + type="SIP", + url="https://www.utpplan.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=6, + locale="us", + mic="XISE", + name="International Securities Exchange, LLC - Stocks", + operating_mic="XNAS", + participant_id="I", + type="TRF", + url="https://nasdaq.com/solutions/nasdaq-ise", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=7, + locale="us", + mic="EDGA", + name="Cboe EDGA", + operating_mic="XCBO", + participant_id="J", + type="exchange", + url="https://www.cboe.com/us/equities", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=8, + locale="us", + mic="EDGX", + name="Cboe EDGX", + operating_mic="XCBO", + participant_id="K", + type="exchange", + url="https://www.cboe.com/us/equities", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=9, + locale="us", + mic="XCHI", + name="NYSE Chicago, Inc.", + operating_mic="XNYS", + participant_id="M", + type="exchange", + url="https://www.nyse.com/markets/nyse-chicago", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=10, + locale="us", + mic="XNYS", + name="New York Stock Exchange", + operating_mic="XNYS", + participant_id="N", + type="exchange", + url="https://www.nyse.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=11, + locale="us", + mic="ARCX", + name="NYSE Arca, Inc.", + operating_mic="XNYS", + participant_id="P", + type="exchange", + url="https://www.nyse.com/markets/nyse-arca", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=12, + locale="us", + mic="XNAS", + name="Nasdaq", + operating_mic="XNAS", + participant_id="T", + type="exchange", + url="https://www.nasdaq.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=13, + locale="us", + mic=None, + name="Consolidated Tape Association", + operating_mic="XNYS", + participant_id="S", + type="SIP", + url="https://www.nyse.com/data/cta", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=14, + locale="us", + mic="LTSE", + name="Long-Term Stock Exchange", + operating_mic="LTSE", + participant_id="L", + type="exchange", + url="https://www.ltse.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=15, + locale="us", + mic="IEXG", + name="Investors Exchange", + operating_mic="IEXG", + participant_id="V", + type="exchange", + url="https://www.iextrading.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=16, + locale="us", + mic="CBSX", + name="Cboe Stock Exchange", + operating_mic="XCBO", + participant_id="W", + type="TRF", + url="https://www.cboe.com", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=17, + locale="us", + mic="XPHL", + name="Nasdaq Philadelphia Exchange LLC", + operating_mic="XNAS", + participant_id="X", + type="exchange", + url="https://www.nasdaq.com/solutions/nasdaq-phlx", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=18, + locale="us", + mic="BATY", + name="Cboe BYX", + operating_mic="XCBO", + participant_id="Y", + type="exchange", + url="https://www.cboe.com/us/equities", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=19, + locale="us", + mic="BATS", + name="Cboe BZX", + operating_mic="XCBO", + participant_id="Z", + type="exchange", + url="https://www.cboe.com/us/equities", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=20, + locale="us", + mic="EPRL", + name="MIAX Pearl", + operating_mic="MIHI", + participant_id="H", + type="exchange", + url="https://www.miaxoptions.com/alerts/pearl-equities", + ), + Exchange( + acronym=None, + asset_class="stocks", + id=21, + locale="us", + mic="MEMX", + name="Members Exchange", + operating_mic="MEMX", + participant_id="U", + type="exchange", + url="https://www.memx.com", + ), + ] + self.assertEqual(exchanges, expected) diff --git a/tests/test_splits.py b/tests/test_splits.py new file mode 100644 index 00000000..83b8f184 --- /dev/null +++ b/tests/test_splits.py @@ -0,0 +1,32 @@ +from polygon.rest.models import Split +from mocks import BaseTest + + +class SplitsTest(BaseTest): + def test_list_splits(self): + splits = [s for s in self.c.list_splits()] + expected = [ + Split( + execution_date="2022-07-18", split_from=1, split_to=20, ticker="GOOGL" + ), + Split( + execution_date="2022-07-18", split_from=1, split_to=20, ticker="GOOG" + ), + Split(execution_date="2022-07-01", split_from=1, split_to=3, ticker="CTO"), + Split( + execution_date="2022-06-29", split_from=1, split_to=10, ticker="SHOP" + ), + Split( + execution_date="2022-06-22", split_from=1, split_to=10, ticker="SHOP" + ), + Split(execution_date="2022-06-10", split_from=1, split_to=4, ticker="DXCM"), + Split( + execution_date="2022-06-06", split_from=1, split_to=20, ticker="AMZN" + ), + Split(execution_date="2022-05-20", split_from=2, split_to=1, ticker="BRW"), + Split(execution_date="2022-05-16", split_from=1, split_to=2, ticker="CM"), + Split( + execution_date="2022-05-02", split_from=3, split_to=4, ticker="CIG.C" + ), + ] + self.assertEqual(splits, expected) From c1ed0042eb1765ddf564b37b8be269a1d18a4189 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Fri, 29 Apr 2022 12:48:24 -0400 Subject: [PATCH 38/41] Fix pagination and tests (#140) --- tests/mocks.py | 18 ++++++++++-------- tests/test_tickers.py | 36 ++++++++++++++++++++++++++++++++++++ tests/test_trades.py | 1 - 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/tests/mocks.py b/tests/mocks.py index f369ab14..5b12cc30 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -8,11 +8,11 @@ '{"ticker":"AAPL","queryCount":2,"resultsCount":2,"adjusted":true,"results":[{"v":6.42646396e+08,"vw":1.469,"o":1.5032,"c":1.4604,"h":1.5064,"l":1.4489,"t":1112331600000,"n":82132},{"v":5.78172308e+08,"vw":1.4589,"o":1.4639,"c":1.4675,"h":1.4754,"l":1.4343,"t":1112587200000,"n":65543}],"status":"OK","request_id":"12afda77aab3b1936c5fb6ef4241ae42","count":2}', ), ( - "/v2/aggs/grouped/locale/us/market/stocks/2005-04-04", + "/v2/aggs/grouped/locale/us/market/stocks/2005-04-04?adjusted=True", '{"queryCount":1,"resultsCount":1,"adjusted": true,"results": [{"T":"GIK","v":895345,"vw":9.9979,"o":9.99,"c":10.02,"h":10.02,"l":9.9,"t":1602705600000,"n":96}],"status":"OK","request_id":"eae3ded2d6d43f978125b7a8a609fad9","count":1}', ), ( - "/v1/open-close/AAPL/2005-04-01", + "/v1/open-close/AAPL/2005-04-01?adjusted=True", '{"status": "OK","from": "2021-04-01","symbol": "AAPL","open": 123.66,"high": 124.18,"low": 122.49,"close": 123,"volume": 75089134,"afterHours": 123,"preMarket": 123.45}', ), ( @@ -32,7 +32,7 @@ '{"ticker":"AAPL","name":"Apple Inc.","market":"stocks","locale":"us","primary_exchange":"XNAS","type":"CS","active":true,"currency_name":"usd","cik":"0000320193","composite_figi":"BBG000B9XRY4","share_class_figi":"BBG001S5N8V8","market_cap":2.6714924917e+12,"phone_number":"(408) 996-1010","address":{"address1":"ONE APPLE PARK WAY","city":"CUPERTINO","state":"CA","postal_code":"95014"},"description":"Apple designs a wide variety of consumer electronic devices, including smartphones (iPhone), tablets (iPad), PCs (Mac), smartwatches (Apple Watch), AirPods, and TV boxes (Apple TV), among others. The iPhone makes up the majority of Apples total revenue. In addition, Apple offers its customers a variety of services such as Apple Music, iCloud, Apple Care, Apple TV+, Apple Arcade, Apple Card, and Apple Pay, among others. Apples products run internally developed software and semiconductors, and the firm is well known for its integration of hardware, software and services. Apples products are distributed online as well as through company-owned stores and third-party retailers. The company generates roughly 40 of its revenue from the Americas, with the remainder earned internationally.","sic_code":"3571","sic_description":"ELECTRONIC COMPUTERS","ticker_root":"AAPL","homepage_url":"https://www.apple.com","total_employees":154000,"list_date":"1980-12-12","branding":{"logo_url":"https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_logo.svg","icon_url":"https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-02-01_icon.png"},"share_class_shares_outstanding":16319440000,"weighted_shares_outstanding":16319441000}', ), ( - "/v2/reference/news", + "/v2/reference/news?ticker=NFLX", '{"results":[{"id":"JeJEhAVoKaqJ2zF9nzQYMg07UlEeWlis6Dsop33TPQY","publisher":{"name":"MarketWatch","homepage_url":"https://www.marketwatch.com/","logo_url":"https://s3.polygon.io/public/assets/news/logos/marketwatch.svg","favicon_url":"https://s3.polygon.io/public/assets/news/favicons/marketwatch.ico"},"title":"Theres a big hole in the Feds theory of inflation—incomes are falling at a record 10.9 rate","author":"MarketWatch","published_utc":"2022-04-28T17:08:00Z","article_url":"https://www.marketwatch.com/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705","tickers":["MSFT","TSN","NFLX","AMZN"],"amp_url":"https://www.marketwatch.com/amp/story/theres-a-big-hole-in-the-feds-theory-of-inflationincomes-are-falling-at-a-record-10-9-rate-11651165705","image_url":"https://images.mktw.net/im-533637/social","description":"If inflation is all due to an overly generous federal government giving its people too much money, then our inflation problem is about to go away."}],"status":"OK","request_id":"f5248459196e12f27520afd41cee5126","count":10}', ), ( @@ -48,7 +48,7 @@ '{"last":{"conditions":[2],"exchange":2,"price":39976.89682331,"size":0.005,"timestamp":1651180409688},"request_id":"d67c9bfe1fa0c29db9177d78b3ab713c","status":"success","symbol":"BTC-USD"}', ), ( - "/v3/trades/AAPL", + "/v3/trades/AAPL?limit=2", '{"results":[{"conditions":[12,37],"correction":1,"exchange":11,"id":"183276","participant_timestamp":1651181822461636600,"price":156.43,"sequence_number":7179341,"sip_timestamp":1651181822461979400,"size":10,"tape":3,"trf_id":3,"trf_timestamp":1651181557090806500},{"conditions":[12,37],"correction":1,"exchange":12,"id":"183276","participant_timestamp":1651181822461636600,"price":157.43,"sequence_number":7179341,"sip_timestamp":1651181822461979400,"size":10,"tape":3,"trf_id":3,"trf_timestamp":1651181557090806500}],"status":"OK","request_id":"756f9910624b35a47eb07f21a7a373bb"}', ), ( @@ -68,12 +68,12 @@ '{"results":[{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2025-06-12","frequency":4,"pay_date":"2025-06-30","record_date":"2025-06-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2025-03-13","frequency":4,"pay_date":"2025-03-31","record_date":"2025-03-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-12-12","frequency":4,"pay_date":"2024-12-31","record_date":"2024-12-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-09-12","frequency":4,"pay_date":"2024-09-30","record_date":"2024-09-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-06-13","frequency":4,"pay_date":"2024-06-30","record_date":"2024-06-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2024-03-14","frequency":4,"pay_date":"2024-03-31","record_date":"2024-03-15","ticker":"CSSEN"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2023-12-14","frequency":4,"pay_date":"2023-12-31","record_date":"2023-12-15","ticker":"CSSEN"},{"cash_amount":0.5,"declaration_date":"2022-02-10","dividend_type":"CD","ex_dividend_date":"2023-11-13","frequency":4,"pay_date":"2023-11-15","record_date":"2023-11-14","ticker":"AIRTP"},{"cash_amount":0.59375,"declaration_date":"2020-09-09","dividend_type":"CD","ex_dividend_date":"2023-09-14","frequency":4,"pay_date":"2023-09-30","record_date":"2023-09-15","ticker":"CSSEN"},{"cash_amount":0.5,"declaration_date":"2022-02-10","dividend_type":"CD","ex_dividend_date":"2023-08-11","frequency":4,"pay_date":"2023-08-15","record_date":"2023-08-14","ticker":"AIRTP"}],"status":"OK","request_id":"0326f1f88a2867a7184c116f5b1edd00"}', ), ( - "/v3/reference/conditions", + "/v3/reference/conditions?asset.class=stocks", '{"results":[{"id":1,"type":"sale_condition","name":"Acquisition","asset_class":"stocks","sip_mapping":{"UTP":"A"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":2,"type":"sale_condition","name":"Average Price Trade","asset_class":"stocks","sip_mapping":{"CTA":"B","UTP":"W"},"update_rules":{"consolidated":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":3,"type":"sale_condition","name":"Automatic Execution","asset_class":"stocks","sip_mapping":{"CTA":"E"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":4,"type":"sale_condition","name":"Bunched Trade","asset_class":"stocks","sip_mapping":{"UTP":"B"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":5,"type":"sale_condition","name":"Bunched Sold Trade","asset_class":"stocks","sip_mapping":{"UTP":"G"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":6,"type":"sale_condition","name":"CAP Election","asset_class":"stocks","sip_mapping":{"CTA":"I"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"],"legacy":true},{"id":7,"type":"sale_condition","name":"Cash Sale","asset_class":"stocks","sip_mapping":{"CTA":"C","UTP":"C"},"update_rules":{"consolidated":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":false,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]},{"id":8,"type":"sale_condition","name":"Closing Prints","asset_class":"stocks","sip_mapping":{"UTP":"6"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":9,"type":"sale_condition","name":"Cross Trade","asset_class":"stocks","sip_mapping":{"CTA":"X","UTP":"X"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":true,"updates_volume":true}},"data_types":["trade"]},{"id":10,"type":"sale_condition","name":"Derivatively Priced","asset_class":"stocks","sip_mapping":{"CTA":"4","UTP":"4"},"update_rules":{"consolidated":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true},"market_center":{"updates_high_low":true,"updates_open_close":false,"updates_volume":true}},"data_types":["trade"]}],"status":"OK","request_id":"4c915a9cb249e40d08d031d70567d615","count":10}', ), ( "/v3/reference/exchanges", - ' {"results":[{"id":1,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE American, LLC","acronym":"AMEX","mic":"XASE","operating_mic":"XNYS","participant_id":"A","url":"https://www.nyse.com/markets/nyse-american"},{"id":2,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq OMX BX, Inc.","mic":"XBOS","operating_mic":"XNAS","participant_id":"B","url":"https://www.nasdaq.com/solutions/nasdaq-bx-stock-market"},{"id":3,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE National, Inc.","acronym":"NSX","mic":"XCIS","operating_mic":"XNYS","participant_id":"C","url":"https://www.nyse.com/markets/nyse-national"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA NYSE TRF","mic":"FINY","operating_mic":"XNYS","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Carteret","mic":"FINN","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Chicago","mic":"FINC","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Alternative Display Facility","mic":"XADF","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":5,"type":"SIP","asset_class":"stocks","locale":"us","name":"Unlisted Trading Privileges","operating_mic":"XNAS","participant_id":"E","url":"https://www.utpplan.com"},{"id":6,"type":"TRF","asset_class":"stocks","locale":"us","name":"International Securities Exchange, LLC - Stocks","mic":"XISE","operating_mic":"XNAS","participant_id":"I","url":"https://nasdaq.com/solutions/nasdaq-ise"},{"id":7,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGA","mic":"EDGA","operating_mic":"XCBO","participant_id":"J","url":"https://www.cboe.com/us/equities"},{"id":8,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGX","mic":"EDGX","operating_mic":"XCBO","participant_id":"K","url":"https://www.cboe.com/us/equities"},{"id":9,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Chicago, Inc.","mic":"XCHI","operating_mic":"XNYS","participant_id":"M","url":"https://www.nyse.com/markets/nyse-chicago"},{"id":10,"type":"exchange","asset_class":"stocks","locale":"us","name":"New York Stock Exchange","mic":"XNYS","operating_mic":"XNYS","participant_id":"N","url":"https://www.nyse.com"},{"id":11,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Arca, Inc.","mic":"ARCX","operating_mic":"XNYS","participant_id":"P","url":"https://www.nyse.com/markets/nyse-arca"},{"id":12,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq","mic":"XNAS","operating_mic":"XNAS","participant_id":"T","url":"https://www.nasdaq.com"},{"id":13,"type":"SIP","asset_class":"stocks","locale":"us","name":"Consolidated Tape Association","operating_mic":"XNYS","participant_id":"S","url":"https://www.nyse.com/data/cta"},{"id":14,"type":"exchange","asset_class":"stocks","locale":"us","name":"Long-Term Stock Exchange","mic":"LTSE","operating_mic":"LTSE","participant_id":"L","url":"https://www.ltse.com"},{"id":15,"type":"exchange","asset_class":"stocks","locale":"us","name":"Investors Exchange","mic":"IEXG","operating_mic":"IEXG","participant_id":"V","url":"https://www.iextrading.com"},{"id":16,"type":"TRF","asset_class":"stocks","locale":"us","name":"Cboe Stock Exchange","mic":"CBSX","operating_mic":"XCBO","participant_id":"W","url":"https://www.cboe.com"},{"id":17,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq Philadelphia Exchange LLC","mic":"XPHL","operating_mic":"XNAS","participant_id":"X","url":"https://www.nasdaq.com/solutions/nasdaq-phlx"},{"id":18,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BYX","mic":"BATY","operating_mic":"XCBO","participant_id":"Y","url":"https://www.cboe.com/us/equities"},{"id":19,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BZX","mic":"BATS","operating_mic":"XCBO","participant_id":"Z","url":"https://www.cboe.com/us/equities"},{"id":20,"type":"exchange","asset_class":"stocks","locale":"us","name":"MIAX Pearl","mic":"EPRL","operating_mic":"MIHI","participant_id":"H","url":"https://www.miaxoptions.com/alerts/pearl-equities"},{"id":21,"type":"exchange","asset_class":"stocks","locale":"us","name":"Members Exchange","mic":"MEMX","operating_mic":"MEMX","participant_id":"U","url":"https://www.memx.com"}],"status":"OK","request_id":"c0109b8a70a931efe47cef085c7a7f5e","count":24}', + '{"results":[{"id":1,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE American, LLC","acronym":"AMEX","mic":"XASE","operating_mic":"XNYS","participant_id":"A","url":"https://www.nyse.com/markets/nyse-american"},{"id":2,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq OMX BX, Inc.","mic":"XBOS","operating_mic":"XNAS","participant_id":"B","url":"https://www.nasdaq.com/solutions/nasdaq-bx-stock-market"},{"id":3,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE National, Inc.","acronym":"NSX","mic":"XCIS","operating_mic":"XNYS","participant_id":"C","url":"https://www.nyse.com/markets/nyse-national"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA NYSE TRF","mic":"FINY","operating_mic":"XNYS","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Carteret","mic":"FINN","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Chicago","mic":"FINC","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Alternative Display Facility","mic":"XADF","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":5,"type":"SIP","asset_class":"stocks","locale":"us","name":"Unlisted Trading Privileges","operating_mic":"XNAS","participant_id":"E","url":"https://www.utpplan.com"},{"id":6,"type":"TRF","asset_class":"stocks","locale":"us","name":"International Securities Exchange, LLC - Stocks","mic":"XISE","operating_mic":"XNAS","participant_id":"I","url":"https://nasdaq.com/solutions/nasdaq-ise"},{"id":7,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGA","mic":"EDGA","operating_mic":"XCBO","participant_id":"J","url":"https://www.cboe.com/us/equities"},{"id":8,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGX","mic":"EDGX","operating_mic":"XCBO","participant_id":"K","url":"https://www.cboe.com/us/equities"},{"id":9,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Chicago, Inc.","mic":"XCHI","operating_mic":"XNYS","participant_id":"M","url":"https://www.nyse.com/markets/nyse-chicago"},{"id":10,"type":"exchange","asset_class":"stocks","locale":"us","name":"New York Stock Exchange","mic":"XNYS","operating_mic":"XNYS","participant_id":"N","url":"https://www.nyse.com"},{"id":11,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Arca, Inc.","mic":"ARCX","operating_mic":"XNYS","participant_id":"P","url":"https://www.nyse.com/markets/nyse-arca"},{"id":12,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq","mic":"XNAS","operating_mic":"XNAS","participant_id":"T","url":"https://www.nasdaq.com"},{"id":13,"type":"SIP","asset_class":"stocks","locale":"us","name":"Consolidated Tape Association","operating_mic":"XNYS","participant_id":"S","url":"https://www.nyse.com/data/cta"},{"id":14,"type":"exchange","asset_class":"stocks","locale":"us","name":"Long-Term Stock Exchange","mic":"LTSE","operating_mic":"LTSE","participant_id":"L","url":"https://www.ltse.com"},{"id":15,"type":"exchange","asset_class":"stocks","locale":"us","name":"Investors Exchange","mic":"IEXG","operating_mic":"IEXG","participant_id":"V","url":"https://www.iextrading.com"},{"id":16,"type":"TRF","asset_class":"stocks","locale":"us","name":"Cboe Stock Exchange","mic":"CBSX","operating_mic":"XCBO","participant_id":"W","url":"https://www.cboe.com"},{"id":17,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq Philadelphia Exchange LLC","mic":"XPHL","operating_mic":"XNAS","participant_id":"X","url":"https://www.nasdaq.com/solutions/nasdaq-phlx"},{"id":18,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BYX","mic":"BATY","operating_mic":"XCBO","participant_id":"Y","url":"https://www.cboe.com/us/equities"},{"id":19,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BZX","mic":"BATS","operating_mic":"XCBO","participant_id":"Z","url":"https://www.cboe.com/us/equities"},{"id":20,"type":"exchange","asset_class":"stocks","locale":"us","name":"MIAX Pearl","mic":"EPRL","operating_mic":"MIHI","participant_id":"H","url":"https://www.miaxoptions.com/alerts/pearl-equities"},{"id":21,"type":"exchange","asset_class":"stocks","locale":"us","name":"Members Exchange","mic":"MEMX","operating_mic":"MEMX","participant_id":"U","url":"https://www.memx.com"}],"status":"OK","request_id":"c0109b8a70a931efe47cef085c7a7f5e","count":24}', ), ] @@ -82,7 +82,9 @@ class BaseTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.maxDiff = None - cls.c = RESTClient("") + cls.c = RESTClient("", verbose=True) httpretty.enable(verbose=True, allow_net_connect=False) for m in mocks: - httpretty.register_uri(httpretty.GET, cls.c.BASE + m[0], m[1]) + httpretty.register_uri( + httpretty.GET, cls.c.BASE + m[0], m[1], match_querystring=True + ) diff --git a/tests/test_tickers.py b/tests/test_tickers.py index bcdf5be6..58d60adc 100644 --- a/tests/test_tickers.py +++ b/tests/test_tickers.py @@ -11,6 +11,42 @@ class TickersTest(BaseTest): def test_list_tickers(self): tickers = [t for t in self.c.list_tickers()] expected = [ + Ticker( + active=True, + cik="0001090872", + composite_figi="BBG000C2V3D6", + currency_name="usd", + currency_symbol=None, + base_currency_symbol=None, + base_currency_name=None, + delisted_utc=None, + last_updated_utc="2022-04-27T00:00:00Z", + locale="us", + market="stocks", + name="Agilent Technologies Inc.", + primary_exchange="XNYS", + share_class_figi="BBG001SCTQY4", + ticker="A", + type="CS", + ), + Ticker( + active=True, + cik="0001675149", + composite_figi="BBG00B3T3HD3", + currency_name="usd", + currency_symbol=None, + base_currency_symbol=None, + base_currency_name=None, + delisted_utc=None, + last_updated_utc="2022-04-27T00:00:00Z", + locale="us", + market="stocks", + name="Alcoa Corporation", + primary_exchange="XNYS", + share_class_figi="BBG00B3T3HF1", + ticker="AA", + type="CS", + ), Ticker( active=True, cik=None, diff --git a/tests/test_trades.py b/tests/test_trades.py index a1717a0e..3c7e9bbb 100644 --- a/tests/test_trades.py +++ b/tests/test_trades.py @@ -49,7 +49,6 @@ def test_get_last_trade_crypto(self): def test_trades(self): trades = [t for t in self.c.list_trades(ticker="AAPL", limit=2)] - print(trades) expected = [ Trade( conditions=[12, 37], From d92f678085f8af2a6cb7e1abb420b97ae49e85c9 Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Fri, 29 Apr 2022 12:55:50 -0400 Subject: [PATCH 39/41] add snapshot (#141) * add snapshot * style --- polygon/rest/aggs.py | 2 +- polygon/rest/models/__init__.py | 3 +- polygon/rest/models/aggs.py | 10 +- polygon/rest/models/shared.py | 11 ++ polygon/rest/models/snapshot.py | 177 ++++++++++++++++++++++++++++++++ polygon/rest/snapshot.py | 136 ++++++++++++++++++++++++ 6 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 polygon/rest/models/snapshot.py create mode 100644 polygon/rest/snapshot.py diff --git a/polygon/rest/aggs.py b/polygon/rest/aggs.py index 1822471e..da77d97e 100644 --- a/polygon/rest/aggs.py +++ b/polygon/rest/aggs.py @@ -4,7 +4,7 @@ from urllib3 import HTTPResponse from datetime import datetime, date -# https://polygon.io/docs/stocks + class AggsClient(BaseClient): def get_aggs( self, diff --git a/polygon/rest/models/__init__.py b/polygon/rest/models/__init__.py index 85139477..29c99ecd 100644 --- a/polygon/rest/models/__init__.py +++ b/polygon/rest/models/__init__.py @@ -1,3 +1,4 @@ +from .shared import * from .aggs import * from .trades import * from .quotes import * @@ -7,4 +8,4 @@ from .dividends import * from .conditions import * from .exchanges import * -from .shared import * +from .snapshot import * diff --git a/polygon/rest/models/aggs.py b/polygon/rest/models/aggs.py index 5b947523..892ab197 100644 --- a/polygon/rest/models/aggs.py +++ b/polygon/rest/models/aggs.py @@ -4,11 +4,11 @@ @dataclass class Agg: - open: float - high: float - low: float - close: float - volume: float + open: Optional[float] + high: Optional[float] + low: Optional[float] + close: Optional[float] + volume: Optional[float] vwap: Optional[float] timestamp: Optional[int] transactions: Optional[int] diff --git a/polygon/rest/models/shared.py b/polygon/rest/models/shared.py index 3b7b3d4a..c3f0d851 100644 --- a/polygon/rest/models/shared.py +++ b/polygon/rest/models/shared.py @@ -60,3 +60,14 @@ class ExchangeType(Enum): EXCHANGE = "exchange" TRF = "TRF" SIP = "SIP" + + +class Direction(Enum): + GAINERS = "gainers" + LOSERS = "losers" + + +class SnapshotMarketType(Enum): + STOCKS = "stocks" + FOREX = "forex" + CRYPTO = "crypto" diff --git a/polygon/rest/models/snapshot.py b/polygon/rest/models/snapshot.py new file mode 100644 index 00000000..4681d8f9 --- /dev/null +++ b/polygon/rest/models/snapshot.py @@ -0,0 +1,177 @@ +from dataclasses import dataclass +from typing import Optional, List, Dict +from .aggs import Agg +from .quotes import LastQuote +from .trades import LastTrade + + +@dataclass +class SnapshotMin: + "Most recent minute bar" + accumulated_volume: Optional[float] + open: Optional[float] + high: Optional[float] + low: Optional[float] + close: Optional[float] + volume: Optional[float] + vwap: Optional[float] + + @staticmethod + def from_dict(d): + return SnapshotMin( + d.get("ac", None), + d.get("o", None), + d.get("h", None), + d.get("l", None), + d.get("c", None), + d.get("v", None), + d.get("vw", None), + ) + + +@dataclass +class Snapshot: + day: Optional[Agg] + last_quote: Optional[LastQuote] + last_trade: Optional[LastTrade] + min: Optional[SnapshotMin] + prev_day: Optional[Agg] + ticker: str + todays_change: float + todays_change_percent: float + updated: int + + @staticmethod + def from_dict(d): + return Snapshot( + d.get("day", None), + d.get("lastQuote", None), + d.get("lastTrade", None), + d.get("min", None), + d.get("prevDay", None), + d.get("ticker", None), + d.get("todaysChange", None), + d.get("todaysChangePercent", None), + d.get("updated", None), + ) + + +@dataclass +class DayOptionContractSnapshot: + change: Optional[float] + change_percent: Optional[float] + close: Optional[float] + high: Optional[float] + last_updated: Optional[int] + low: Optional[float] + open: Optional[float] + previous_close: Optional[float] + volume: Optional[float] + vwap: Optional[float] + + @staticmethod + def from_dict(d): + return DayOptionContractSnapshot(**d) + + +@dataclass +class OptionDetails: + contract_type: str + exercise_style: str + expiration_date: str + shares_per_contract: float + strike_price: float + ticker: str + + @staticmethod + def from_dict(d): + return OptionDetails(**d) + + +@dataclass +class OptionLastQuote: + ask: Optional[float] + ask_size: Optional[float] + bid: Optional[float] + bid_size: Optional[float] + last_updated: Optional[int] + midpoint: Optional[float] + timeframe: Optional[str] + + @staticmethod + def from_dict(d): + return OptionLastQuote(**d) + + +@dataclass +class OptionGreeks: + delta: Optional[float] + gamma: Optional[float] + theta: Optional[float] + vega: Optional[float] + + @staticmethod + def from_dict(d): + return OptionGreeks(**d) + + +@dataclass +class UnderlyingAsset: + change_to_break_even: Optional[float] + last_updated: Optional[int] + price: Optional[float] + ticker: Optional[str] + timeframe: Optional[str] + + @staticmethod + def from_dict(d): + return UnderlyingAsset(**d) + + +@dataclass +class OptionContractSnapshot: + break_even_price: Optional[float] + day: Optional[Agg] + details: Optional[OptionDetails] + greeks: Optional[OptionGreeks] + implied_volatility: Optional[float] + last_quote: Optional[OptionLastQuote] + open_interest: Optional[float] + underlying_asset: Optional[float] + + @staticmethod + def from_dict(d): + return OptionContractSnapshot(**d) + + +@dataclass +class OrderBookQuote: + price: Optional[float] + exchange_shares: Dict[str, float] + + @staticmethod + def from_dict(d): + return OrderBookQuote(**d) + + +@dataclass +class SnapshotTickerFullBook: + ticker: Optional[str] + bids: Optional[List[OrderBookQuote]] + asks: Optional[List[OrderBookQuote]] + bid_count: Optional[float] + ask_count: Optional[float] + spread: Optional[float] + updated: int + + @staticmethod + def from_dict(d): + return SnapshotTickerFullBook( + d.get("ticker", None), + d.get("bids", None), + d.get("asks", None), + d.get("bidCount", None), + d.get("askCount", None), + d.get("spread", None), + d.get("updated", None), + ) diff --git a/polygon/rest/snapshot.py b/polygon/rest/snapshot.py new file mode 100644 index 00000000..7c8b06df --- /dev/null +++ b/polygon/rest/snapshot.py @@ -0,0 +1,136 @@ +from .base import BaseClient +from typing import Optional, Any, Dict, List, Union +from .models import ( + Snapshot, + Direction, + OptionContractSnapshot, + SnapshotMarketType, + SnapshotTickerFullBook, +) +from urllib3 import HTTPResponse + + +class SnapshotClient(BaseClient): + def get_snapshot_all( + self, + market_type: Optional[Union[str, SnapshotMarketType]] = "stocks", + tickers: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[List[Snapshot], HTTPResponse]: + """ + Get the most up-to-date market data for all traded stock symbols. + + Note: Snapshot data is cleared at 12am EST and gets populated as data is received from the exchanges. This can happen as early as 4am EST. + + :param market_type: Which market to get a snapshot of. + :param tickers: A comma separated list of tickers to get snapshots for. + :return: List of Snapshots + """ + url = f"/v2/snapshot/locale/us/markets/{market_type}/tickers" + if type(tickers) is list: + tickers = ",".join(tickers) + return self._get( + path=url, + params=self._get_params(self.get_snapshot_all, locals()), + deserializer=Snapshot.from_dict, + raw=raw, + ) + + def get_snapshot_direction( + self, + direction: Union[str, Direction], + market_type: Optional[Union[str, SnapshotMarketType]] = "stocks", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[List[Snapshot], HTTPResponse]: + """ + Get the most up-to-date market data for the current top 20 gainers or losers of the day in the stocks/equities markets. + + Top gainers are those tickers whose price has increased by the highest percentage since the previous day's close. Top losers are those tickers whose price has decreased by the highest percentage since the previous day's close. + + Note: Snapshot data is cleared at 12am EST and gets populated as data is received from the exchanges. + + :param market_type: Which market to get a snapshot of. + :param direction: The direction ("gainers" or "losers") + :return: List of Snapshots + """ + url = f"/v2/snapshot/locale/us/markets/{market_type}/{direction}" + return self._get( + path=url, + params=self._get_params(self.get_snapshot_direction, locals()), + result_key="tickers", + deserializer=Snapshot.from_dict, + raw=raw, + ) + + def get_snapshot_ticker( + self, + ticker: str, + market_type: Optional[Union[str, SnapshotMarketType]] = "stocks", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[Snapshot, HTTPResponse]: + """ + Get the most up-to-date market data for all traded stock symbols. + + Note: Snapshot data is cleared at 12am EST and gets populated as data is received from the exchanges. This can happen as early as 4am EST. + + :param market_type: Which market to get a snapshot of. + :param ticker: The ticker symbol. + :return: List of Snapshots + """ + url = f"/v2/snapshot/locale/us/markets/{market_type}/tickers/{ticker}" + return self._get( + path=url, + params=self._get_params(self.get_snapshot_ticker, locals()), + result_key="ticker", + deserializer=Snapshot.from_dict, + raw=raw, + ) + + def get_snapshot_option( + self, + underlying_asset: str, + option_contract: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[OptionContractSnapshot, HTTPResponse]: + """ + Get the snapshot of an option contract for a stock equity. + + :param underlying_asset: The underlying ticker symbol of the option contract. + :param option_contract: The option contract identifier. + :return: List of Snapshots + """ + url = f"/v2/snapshot/options/{underlying_asset}/{option_contract}" + return self._get( + path=url, + params=self._get_params(self.get_snapshot_option, locals()), + result_key="results", + deserializer=OptionContractSnapshot.from_dict, + raw=raw, + ) + + def get_snapshot_crypto_book( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + ) -> Union[SnapshotTickerFullBook, HTTPResponse]: + """ + Get the current level 2 book of a single ticker. This is the combined book from all of the exchanges. + + Note: Snapshot data is cleared at 12am EST and gets populated as data is received from the exchanges. + + :param ticker: The ticker symbol. + :return: List of Snapshots + """ + url = f" /v2/snapshot/locale/global/markets/crypto/tickers/{ticker}/book" + return self._get( + path=url, + params=self._get_params(self.get_snapshot_crypto_book, locals()), + result_key="data", + deserializer=SnapshotTickerFullBook.from_dict, + raw=raw, + ) From bb303aa85da5311e2d5aa7611381d0d7a9337770 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Fri, 29 Apr 2022 15:11:31 -0400 Subject: [PATCH 40/41] Snapshot tests (#143) --- polygon/rest/__init__.py | 2 + polygon/rest/models/snapshot.py | 130 +++++++-------- polygon/rest/snapshot.py | 5 +- tests/mocks.py | 20 +++ tests/test_snapshots.py | 277 ++++++++++++++++++++++++++++++++ 5 files changed, 367 insertions(+), 67 deletions(-) create mode 100644 tests/test_snapshots.py diff --git a/polygon/rest/__init__.py b/polygon/rest/__init__.py index 31f100f1..4be8a032 100644 --- a/polygon/rest/__init__.py +++ b/polygon/rest/__init__.py @@ -1,6 +1,7 @@ from .aggs import AggsClient from .trades import TradesClient from .quotes import QuotesClient +from .snapshot import SnapshotClient from .reference import ( MarketsClient, TickersClient, @@ -15,6 +16,7 @@ class RESTClient( AggsClient, TradesClient, QuotesClient, + SnapshotClient, MarketsClient, TickersClient, SplitsClient, diff --git a/polygon/rest/models/snapshot.py b/polygon/rest/models/snapshot.py index 4681d8f9..4a814d28 100644 --- a/polygon/rest/models/snapshot.py +++ b/polygon/rest/models/snapshot.py @@ -8,13 +8,13 @@ @dataclass class SnapshotMin: "Most recent minute bar" - accumulated_volume: Optional[float] - open: Optional[float] - high: Optional[float] - low: Optional[float] - close: Optional[float] - volume: Optional[float] - vwap: Optional[float] + accumulated_volume: Optional[float] = None + open: Optional[float] = None + high: Optional[float] = None + low: Optional[float] = None + close: Optional[float] = None + volume: Optional[float] = None + vwap: Optional[float] = None @staticmethod def from_dict(d): @@ -31,15 +31,15 @@ def from_dict(d): @dataclass class Snapshot: - day: Optional[Agg] - last_quote: Optional[LastQuote] - last_trade: Optional[LastTrade] - min: Optional[SnapshotMin] - prev_day: Optional[Agg] - ticker: str - todays_change: float - todays_change_percent: float - updated: int + day: Optional[Agg] = None + last_quote: Optional[LastQuote] = None + last_trade: Optional[LastTrade] = None + min: Optional[SnapshotMin] = None + prev_day: Optional[Agg] = None + ticker: Optional[str] = None + todays_change: Optional[float] = None + todays_change_percent: Optional[float] = None + updated: Optional[int] = None @staticmethod def from_dict(d): @@ -58,16 +58,16 @@ def from_dict(d): @dataclass class DayOptionContractSnapshot: - change: Optional[float] - change_percent: Optional[float] - close: Optional[float] - high: Optional[float] - last_updated: Optional[int] - low: Optional[float] - open: Optional[float] - previous_close: Optional[float] - volume: Optional[float] - vwap: Optional[float] + change: Optional[float] = None + change_percent: Optional[float] = None + close: Optional[float] = None + high: Optional[float] = None + last_updated: Optional[int] = None + low: Optional[float] = None + open: Optional[float] = None + previous_close: Optional[float] = None + volume: Optional[float] = None + vwap: Optional[float] = None @staticmethod def from_dict(d): @@ -76,12 +76,12 @@ def from_dict(d): @dataclass class OptionDetails: - contract_type: str - exercise_style: str - expiration_date: str - shares_per_contract: float - strike_price: float - ticker: str + 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 + ticker: Optional[str] = None @staticmethod def from_dict(d): @@ -90,13 +90,13 @@ def from_dict(d): @dataclass class OptionLastQuote: - ask: Optional[float] - ask_size: Optional[float] - bid: Optional[float] - bid_size: Optional[float] - last_updated: Optional[int] - midpoint: Optional[float] - timeframe: Optional[str] + ask: Optional[float] = None + ask_size: Optional[float] = None + bid: Optional[float] = None + bid_size: Optional[float] = None + last_updated: Optional[int] = None + midpoint: Optional[float] = None + timeframe: Optional[str] = None @staticmethod def from_dict(d): @@ -105,10 +105,10 @@ def from_dict(d): @dataclass class OptionGreeks: - delta: Optional[float] - gamma: Optional[float] - theta: Optional[float] - vega: Optional[float] + delta: Optional[float] = None + gamma: Optional[float] = None + theta: Optional[float] = None + vega: Optional[float] = None @staticmethod def from_dict(d): @@ -117,11 +117,11 @@ def from_dict(d): @dataclass class UnderlyingAsset: - change_to_break_even: Optional[float] - last_updated: Optional[int] - price: Optional[float] - ticker: Optional[str] - timeframe: Optional[str] + change_to_break_even: Optional[float] = None + last_updated: Optional[int] = None + price: Optional[float] = None + ticker: Optional[str] = None + timeframe: Optional[str] = None @staticmethod def from_dict(d): @@ -130,14 +130,14 @@ def from_dict(d): @dataclass class OptionContractSnapshot: - break_even_price: Optional[float] - day: Optional[Agg] - details: Optional[OptionDetails] - greeks: Optional[OptionGreeks] - implied_volatility: Optional[float] - last_quote: Optional[OptionLastQuote] - open_interest: Optional[float] - underlying_asset: Optional[float] + break_even_price: Optional[float] = None + day: Optional[Agg] = None + details: Optional[OptionDetails] = None + greeks: Optional[OptionGreeks] = None + implied_volatility: Optional[float] = None + last_quote: Optional[OptionLastQuote] = None + open_interest: Optional[float] = None + underlying_asset: Optional[float] = None @staticmethod def from_dict(d): @@ -146,8 +146,8 @@ def from_dict(d): @dataclass class OrderBookQuote: - price: Optional[float] - exchange_shares: Dict[str, float] + price: Optional[float] = None + exchange_shares: Optional[Dict[str, float]] = None @staticmethod def from_dict(d): @@ -156,13 +156,13 @@ def from_dict(d): @dataclass class SnapshotTickerFullBook: - ticker: Optional[str] - bids: Optional[List[OrderBookQuote]] - asks: Optional[List[OrderBookQuote]] - bid_count: Optional[float] - ask_count: Optional[float] - spread: Optional[float] - updated: int + ticker: Optional[str] = None + bids: Optional[List[OrderBookQuote]] = None + asks: Optional[List[OrderBookQuote]] = None + bid_count: Optional[float] = None + ask_count: Optional[float] = None + spread: Optional[float] = None + updated: Optional[int] = None @staticmethod def from_dict(d): diff --git a/polygon/rest/snapshot.py b/polygon/rest/snapshot.py index 7c8b06df..2aa5eefa 100644 --- a/polygon/rest/snapshot.py +++ b/polygon/rest/snapshot.py @@ -35,6 +35,7 @@ def get_snapshot_all( params=self._get_params(self.get_snapshot_all, locals()), deserializer=Snapshot.from_dict, raw=raw, + result_key="tickers", ) def get_snapshot_direction( @@ -103,7 +104,7 @@ def get_snapshot_option( :param option_contract: The option contract identifier. :return: List of Snapshots """ - url = f"/v2/snapshot/options/{underlying_asset}/{option_contract}" + url = f"/v3/snapshot/options/{underlying_asset}/{option_contract}" return self._get( path=url, params=self._get_params(self.get_snapshot_option, locals()), @@ -126,7 +127,7 @@ def get_snapshot_crypto_book( :param ticker: The ticker symbol. :return: List of Snapshots """ - url = f" /v2/snapshot/locale/global/markets/crypto/tickers/{ticker}/book" + url = f"/v2/snapshot/locale/global/markets/crypto/tickers/{ticker}/book" return self._get( path=url, params=self._get_params(self.get_snapshot_crypto_book, locals()), diff --git a/tests/mocks.py b/tests/mocks.py index 5b12cc30..6a6491ae 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -75,6 +75,26 @@ "/v3/reference/exchanges", '{"results":[{"id":1,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE American, LLC","acronym":"AMEX","mic":"XASE","operating_mic":"XNYS","participant_id":"A","url":"https://www.nyse.com/markets/nyse-american"},{"id":2,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq OMX BX, Inc.","mic":"XBOS","operating_mic":"XNAS","participant_id":"B","url":"https://www.nasdaq.com/solutions/nasdaq-bx-stock-market"},{"id":3,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE National, Inc.","acronym":"NSX","mic":"XCIS","operating_mic":"XNYS","participant_id":"C","url":"https://www.nyse.com/markets/nyse-national"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA NYSE TRF","mic":"FINY","operating_mic":"XNYS","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Carteret","mic":"FINN","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Nasdaq TRF Chicago","mic":"FINC","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":4,"type":"TRF","asset_class":"stocks","locale":"us","name":"FINRA Alternative Display Facility","mic":"XADF","operating_mic":"FINR","participant_id":"D","url":"https://www.finra.org"},{"id":5,"type":"SIP","asset_class":"stocks","locale":"us","name":"Unlisted Trading Privileges","operating_mic":"XNAS","participant_id":"E","url":"https://www.utpplan.com"},{"id":6,"type":"TRF","asset_class":"stocks","locale":"us","name":"International Securities Exchange, LLC - Stocks","mic":"XISE","operating_mic":"XNAS","participant_id":"I","url":"https://nasdaq.com/solutions/nasdaq-ise"},{"id":7,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGA","mic":"EDGA","operating_mic":"XCBO","participant_id":"J","url":"https://www.cboe.com/us/equities"},{"id":8,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe EDGX","mic":"EDGX","operating_mic":"XCBO","participant_id":"K","url":"https://www.cboe.com/us/equities"},{"id":9,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Chicago, Inc.","mic":"XCHI","operating_mic":"XNYS","participant_id":"M","url":"https://www.nyse.com/markets/nyse-chicago"},{"id":10,"type":"exchange","asset_class":"stocks","locale":"us","name":"New York Stock Exchange","mic":"XNYS","operating_mic":"XNYS","participant_id":"N","url":"https://www.nyse.com"},{"id":11,"type":"exchange","asset_class":"stocks","locale":"us","name":"NYSE Arca, Inc.","mic":"ARCX","operating_mic":"XNYS","participant_id":"P","url":"https://www.nyse.com/markets/nyse-arca"},{"id":12,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq","mic":"XNAS","operating_mic":"XNAS","participant_id":"T","url":"https://www.nasdaq.com"},{"id":13,"type":"SIP","asset_class":"stocks","locale":"us","name":"Consolidated Tape Association","operating_mic":"XNYS","participant_id":"S","url":"https://www.nyse.com/data/cta"},{"id":14,"type":"exchange","asset_class":"stocks","locale":"us","name":"Long-Term Stock Exchange","mic":"LTSE","operating_mic":"LTSE","participant_id":"L","url":"https://www.ltse.com"},{"id":15,"type":"exchange","asset_class":"stocks","locale":"us","name":"Investors Exchange","mic":"IEXG","operating_mic":"IEXG","participant_id":"V","url":"https://www.iextrading.com"},{"id":16,"type":"TRF","asset_class":"stocks","locale":"us","name":"Cboe Stock Exchange","mic":"CBSX","operating_mic":"XCBO","participant_id":"W","url":"https://www.cboe.com"},{"id":17,"type":"exchange","asset_class":"stocks","locale":"us","name":"Nasdaq Philadelphia Exchange LLC","mic":"XPHL","operating_mic":"XNAS","participant_id":"X","url":"https://www.nasdaq.com/solutions/nasdaq-phlx"},{"id":18,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BYX","mic":"BATY","operating_mic":"XCBO","participant_id":"Y","url":"https://www.cboe.com/us/equities"},{"id":19,"type":"exchange","asset_class":"stocks","locale":"us","name":"Cboe BZX","mic":"BATS","operating_mic":"XCBO","participant_id":"Z","url":"https://www.cboe.com/us/equities"},{"id":20,"type":"exchange","asset_class":"stocks","locale":"us","name":"MIAX Pearl","mic":"EPRL","operating_mic":"MIHI","participant_id":"H","url":"https://www.miaxoptions.com/alerts/pearl-equities"},{"id":21,"type":"exchange","asset_class":"stocks","locale":"us","name":"Members Exchange","mic":"MEMX","operating_mic":"MEMX","participant_id":"U","url":"https://www.memx.com"}],"status":"OK","request_id":"c0109b8a70a931efe47cef085c7a7f5e","count":24}', ), + ( + "/v2/snapshot/locale/us/markets/stocks/tickers?market.type=stocks", + '{"count": 1,"status": "OK","tickers": [{"day": {"c": 20.506,"h": 20.64,"l": 20.506,"o": 20.64,"v": 37216,"vw": 20.616},"lastQuote": {"P": 20.6,"S": 22,"p": 20.5,"s": 13,"t": 1605192959994246100},"lastTrade": {"c": [14,41],"i": "71675577320245","p": 20.506,"s": 2416,"t": 1605192894630916600,"x": 4},"min": {"av": 37216,"c": 20.506,"h": 20.506,"l": 20.506,"o": 20.506,"v": 5000,"vw": 20.5105},"prevDay": {"c": 20.63,"h": 21,"l": 20.5,"o": 20.79,"v": 292738,"vw": 20.6939},"ticker": "BCAT","todaysChange": -0.124,"todaysChangePerc": -0.601,"updated": 1605192894630916600}]}', + ), + ( + "/v2/snapshot/locale/us/markets/stocks/gainers?market.type=stocks", + '{"status":"OK","tickers":[{"day":{"c":6.42,"h":6.99,"l":6.4,"o":6.81,"v":115782,"vw":6.656},"lastQuote":{"P":6.43,"S":1,"p":6.4,"s":1,"t":1651251738312628478},"lastTrade":{"c":[14,41],"i":"100","p":6.42,"s":200,"t":1651251334045891221,"x":8},"min":{"av":115689,"c":6.42,"h":6.542,"l":6.42,"o":6.49,"v":2671,"vw":6.4604},"prevDay":{"c":0.29,"h":0.348,"l":0.29,"o":0.3443,"v":1488660,"vw":0.317},"ticker":"NVCN","todaysChange":6.13,"todaysChangePerc":2113.793,"updated":1651251360000000000},{"day":{"c":4.2107,"h":4.95,"l":4.21,"o":4.31,"v":453199,"vw":4.4181},"lastQuote":{"P":4.22,"S":9,"p":4.21,"s":11,"t":1651251781709136903},"lastTrade":{"c":null,"i":"1084","p":4.2116,"s":241,"t":1651251789345841015,"x":4},"min":{"av":453189,"c":4.2107,"h":4.2107,"l":4.2107,"o":4.2107,"v":1012,"vw":4.2107},"prevDay":{"c":0.1953,"h":0.2966,"l":0.195,"o":0.29,"v":8784033,"vw":0.2278},"ticker":"BIOL","todaysChange":4.016,"todaysChangePerc":2056.477,"updated":1651251789345841015}]}', + ), + ( + "/v2/snapshot/locale/us/markets/stocks/tickers/AAPL?market.type=stocks", + '{"request_id":"957db942cab2d6b0633b9b4820db0cb2","status":"OK","ticker":{"day":{"c":160.315,"h":166.2,"l":159.8,"o":161.84,"v":68840127,"vw":162.7124},"lastQuote":{"P":159.99,"S":5,"p":159.98,"s":3,"t":1651251948407646487},"lastTrade":{"c":null,"i":"121351","p":159.99,"s":200,"t":1651251948294080343,"x":12},"min":{"av":68834255,"c":160.3,"h":160.71,"l":160.3,"o":160.71,"v":197226,"vw":160.5259},"prevDay":{"c":163.64,"h":164.515,"l":158.93,"o":159.25,"v":130149192,"vw":161.8622},"ticker":"AAPL","todaysChange":-3.65,"todaysChangePerc":-2.231,"updated":1651251948294080343}}', + ), + ( + "/v2/snapshot/locale/global/markets/crypto/tickers/X:BTCUSD/book", + '{"data": {"askCount": 593.1412981600005,"asks": [{"p": 11454,"x": {"2": 1}},{"p": 11455,"x": {"2": 1}}],"bidCount": 694.951789670001,"bids": [{"p": 16303.17,"x": {"1": 2}},{"p": 16302.94,"x": {"1": 0.02859424,"6": 0.023455}}],"spread": -4849.17,"ticker": "X:BTCUSD","updated": 1605295074162},"status": "OK"}', + ), + ( + "/v3/snapshot/options/AAPL/O:AAPL230616C00150000", + '{"request_id":"104d9b901d0c9e81d284cb8b41c5cdd3","results":{"break_even_price":179.075,"day":{"change":-2.3999999999999986,"change_percent":-7.643312101910824,"close":29,"high":32.25,"last_updated":1651204800000000000,"low":29,"open":29.99,"previous_close":31.4,"volume":8,"vwap":30.7738},"details":{"contract_type":"call","exercise_style":"american","expiration_date":"2023-06-16","shares_per_contract":100,"strike_price":150,"ticker":"O:AAPL230616C00150000"},"greeks":{"delta":0.6436614934293701,"gamma":0.0061735291012820675,"theta":-0.028227189324641973,"vega":0.6381159723175714},"implied_volatility":0.3570277203465058,"last_quote":{"ask":29.25,"ask_size":209,"bid":28.9,"bid_size":294,"last_updated":1651254260800059648,"midpoint":29.075,"timeframe":"REAL-TIME"},"open_interest":8133,"underlying_asset":{"change_to_break_even":19.11439999999999,"last_updated":1651254263172073152,"price":159.9606,"ticker":"AAPL","timeframe":"REAL-TIME"}},"status":"OK"}', + ), ] diff --git a/tests/test_snapshots.py b/tests/test_snapshots.py new file mode 100644 index 00000000..5de72195 --- /dev/null +++ b/tests/test_snapshots.py @@ -0,0 +1,277 @@ +from polygon.rest.models import Snapshot, OptionContractSnapshot, SnapshotTickerFullBook +from mocks import BaseTest + + +class SnapshotsTest(BaseTest): + def test_get_snapshot_all(self): + snapshots = self.c.get_snapshot_all() + expected = [ + Snapshot( + day={ + "c": 20.506, + "h": 20.64, + "l": 20.506, + "o": 20.64, + "v": 37216, + "vw": 20.616, + }, + last_quote={ + "P": 20.6, + "S": 22, + "p": 20.5, + "s": 13, + "t": 1605192959994246100, + }, + last_trade={ + "c": [14, 41], + "i": "71675577320245", + "p": 20.506, + "s": 2416, + "t": 1605192894630916600, + "x": 4, + }, + min={ + "av": 37216, + "c": 20.506, + "h": 20.506, + "l": 20.506, + "o": 20.506, + "v": 5000, + "vw": 20.5105, + }, + prev_day={ + "c": 20.63, + "h": 21, + "l": 20.5, + "o": 20.79, + "v": 292738, + "vw": 20.6939, + }, + ticker="BCAT", + todays_change=-0.124, + todays_change_percent=None, + updated=1605192894630916600, + ) + ] + self.assertEqual(snapshots, expected) + + def test_get_snapshot_direction(self): + snapshots = self.c.get_snapshot_direction("gainers") + expected = [ + Snapshot( + day={ + "c": 6.42, + "h": 6.99, + "l": 6.4, + "o": 6.81, + "v": 115782, + "vw": 6.656, + }, + last_quote={ + "P": 6.43, + "S": 1, + "p": 6.4, + "s": 1, + "t": 1651251738312628478, + }, + last_trade={ + "c": [14, 41], + "i": "100", + "p": 6.42, + "s": 200, + "t": 1651251334045891221, + "x": 8, + }, + min={ + "av": 115689, + "c": 6.42, + "h": 6.542, + "l": 6.42, + "o": 6.49, + "v": 2671, + "vw": 6.4604, + }, + prev_day={ + "c": 0.29, + "h": 0.348, + "l": 0.29, + "o": 0.3443, + "v": 1488660, + "vw": 0.317, + }, + ticker="NVCN", + todays_change=6.13, + todays_change_percent=None, + updated=1651251360000000000, + ), + Snapshot( + day={ + "c": 4.2107, + "h": 4.95, + "l": 4.21, + "o": 4.31, + "v": 453199, + "vw": 4.4181, + }, + last_quote={ + "P": 4.22, + "S": 9, + "p": 4.21, + "s": 11, + "t": 1651251781709136903, + }, + last_trade={ + "c": None, + "i": "1084", + "p": 4.2116, + "s": 241, + "t": 1651251789345841015, + "x": 4, + }, + min={ + "av": 453189, + "c": 4.2107, + "h": 4.2107, + "l": 4.2107, + "o": 4.2107, + "v": 1012, + "vw": 4.2107, + }, + prev_day={ + "c": 0.1953, + "h": 0.2966, + "l": 0.195, + "o": 0.29, + "v": 8784033, + "vw": 0.2278, + }, + ticker="BIOL", + todays_change=4.016, + todays_change_percent=None, + updated=1651251789345841015, + ), + ] + self.assertEqual(snapshots, expected) + + def test_get_snapshot_ticker(self): + snapshots = self.c.get_snapshot_ticker("AAPL") + expected = [ + Snapshot( + day={ + "c": 160.315, + "h": 166.2, + "l": 159.8, + "o": 161.84, + "v": 68840127, + "vw": 162.7124, + }, + last_quote={ + "P": 159.99, + "S": 5, + "p": 159.98, + "s": 3, + "t": 1651251948407646487, + }, + last_trade={ + "c": None, + "i": "121351", + "p": 159.99, + "s": 200, + "t": 1651251948294080343, + "x": 12, + }, + min={ + "av": 68834255, + "c": 160.3, + "h": 160.71, + "l": 160.3, + "o": 160.71, + "v": 197226, + "vw": 160.5259, + }, + prev_day={ + "c": 163.64, + "h": 164.515, + "l": 158.93, + "o": 159.25, + "v": 130149192, + "vw": 161.8622, + }, + ticker="AAPL", + todays_change=-3.65, + todays_change_percent=None, + updated=1651251948294080343, + ) + ] + self.assertEqual(snapshots, expected) + + def test_get_snapshot_option(self): + snapshots = self.c.get_snapshot_option("AAPL", "O:AAPL230616C00150000") + expected = [ + OptionContractSnapshot( + break_even_price=179.075, + day={ + "change": -2.3999999999999986, + "change_percent": -7.643312101910824, + "close": 29, + "high": 32.25, + "last_updated": 1651204800000000000, + "low": 29, + "open": 29.99, + "previous_close": 31.4, + "volume": 8, + "vwap": 30.7738, + }, + details={ + "contract_type": "call", + "exercise_style": "american", + "expiration_date": "2023-06-16", + "shares_per_contract": 100, + "strike_price": 150, + "ticker": "O:AAPL230616C00150000", + }, + greeks={ + "delta": 0.6436614934293701, + "gamma": 0.0061735291012820675, + "theta": -0.028227189324641973, + "vega": 0.6381159723175714, + }, + implied_volatility=0.3570277203465058, + last_quote={ + "ask": 29.25, + "ask_size": 209, + "bid": 28.9, + "bid_size": 294, + "last_updated": 1651254260800059648, + "midpoint": 29.075, + "timeframe": "REAL-TIME", + }, + open_interest=8133, + underlying_asset={ + "change_to_break_even": 19.11439999999999, + "last_updated": 1651254263172073152, + "price": 159.9606, + "ticker": "AAPL", + "timeframe": "REAL-TIME", + }, + ) + ] + self.assertEqual(snapshots, expected) + + def test_get_snapshot_crypto_book(self): + snapshots = self.c.get_snapshot_crypto_book("X:BTCUSD") + expected = [ + SnapshotTickerFullBook( + ticker="X:BTCUSD", + bids=[ + {"p": 16303.17, "x": {"1": 2}}, + {"p": 16302.94, "x": {"1": 0.02859424, "6": 0.023455}}, + ], + asks=[{"p": 11454, "x": {"2": 1}}, {"p": 11455, "x": {"2": 1}}], + bid_count=694.951789670001, + ask_count=593.1412981600005, + spread=-4849.17, + updated=1605295074162, + ) + ] + self.assertEqual(snapshots, expected) From b4d81cda32f4bab0334d561f8f67ebd32f3d24c5 Mon Sep 17 00:00:00 2001 From: Darcy Linde <47221647+Darcy-Linde@users.noreply.github.com> Date: Fri, 29 Apr 2022 15:42:17 -0400 Subject: [PATCH 41/41] Snapshot rst (#144) --- docs/source/Snapshot.rst | 29 +++++++++++++++++++++++++++++ docs/source/index.rst | 1 + polygon/rest/reference.py | 6 +++--- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 docs/source/Snapshot.rst diff --git a/docs/source/Snapshot.rst b/docs/source/Snapshot.rst new file mode 100644 index 00000000..274341e1 --- /dev/null +++ b/docs/source/Snapshot.rst @@ -0,0 +1,29 @@ +.. _snapshot_header: + +Snapshot +================================= + +================================= +Get all snapshots +================================= +.. automethod:: polygon.RESTClient.get_snapshot_all + +================================= +Get gainers/losers snapshot +================================= +.. automethod:: polygon.RESTClient.get_snapshot_direction + +================================= +Get ticker snapshot +================================= +.. automethod:: polygon.RESTClient.get_snapshot_ticker + +================================= +Get options snapshot +================================= +.. automethod:: polygon.RESTClient.get_snapshot_option + +================================= +Get crypto L2 book snapshot +================================= +.. automethod:: polygon.RESTClient.get_snapshot_crypto_book \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 36bd6e23..fbcb3e3d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,6 +9,7 @@ This documentation is for the Python client only. For details about the response Getting-Started Aggs + Snapshot Quotes Reference Trades diff --git a/polygon/rest/reference.py b/polygon/rest/reference.py index e7acaa3d..5082e35b 100644 --- a/polygon/rest/reference.py +++ b/polygon/rest/reference.py @@ -33,7 +33,7 @@ def get_market_holidays( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object - :return: List of quotes + :return: List of market holidays """ url = "/v1/marketstatus/upcoming" @@ -53,7 +53,7 @@ def get_market_status( :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object - :return: List of quotes + :return: Market status """ url = "/v1/marketstatus/now" @@ -393,7 +393,7 @@ def get_exchanges( :param locale: Filter by locale. :param params: Any additional query params :param raw: Return HTTPResponse object instead of results object - :return: List of quotes + :return: List of exchanges """ url = "/v3/reference/exchanges"