From 5b5b45f5c433a7791936a009f98a403852921008 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:39:38 -0600 Subject: [PATCH 01/22] fix: stop sending the options argument as a query parameter BaseClient._get_params turns a method's locals() into query parameters, skipping only `params` and `raw`. It did not skip `options`, so any REST method called with a RequestOptionBuilder also sent `options=` in the query string. Skip `options` too. Every endpoint builds its query through _get_params, so this fixes them all. Add regression tests for a GET and a paginated list call. --- massive/rest/base.py | 3 ++- test_rest/test_request_options.py | 35 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test_rest/test_request_options.py diff --git a/massive/rest/base.py b/massive/rest/base.py index 294dd482..7e85be4a 100644 --- a/massive/rest/base.py +++ b/massive/rest/base.py @@ -196,7 +196,8 @@ def _get_params( # https://docs.python.org/3.8/library/inspect.html#inspect.Signature for argname, v in inspect.signature(fn).parameters.items(): # https://docs.python.org/3.8/library/inspect.html#inspect.Parameter - if argname in ["params", "raw"]: + # these configure the request itself and are never query params + if argname in ["params", "raw", "options"]: continue if v.default != v.empty: # timestamp_lt -> timestamp.lt diff --git a/test_rest/test_request_options.py b/test_rest/test_request_options.py new file mode 100644 index 00000000..805b2255 --- /dev/null +++ b/test_rest/test_request_options.py @@ -0,0 +1,35 @@ +from massive.rest.models.request import RequestOptionBuilder +from base import BaseTest + +import pook # type: ignore + + +class RequestOptionsTest(BaseTest): + """`options` sets headers; it must not leak into the query string.""" + + def options(self): + return RequestOptionBuilder(edge_id="test-edge", edge_ip_address="1.2.3.4") + + def assert_no_options_in_query(self, mock): + self.assertEqual(len(mock.matches), 1) + self.assertNotIn("options", mock.matches[0].query or {}) + + def test_get_with_options(self): + mock = pook.get( + self.c.BASE + "/v3/reference/tickers/OPTS", + reply=200, + response_body='{"results": {"ticker": "OPTS"}}', + ) + details = self.c.get_ticker_details("OPTS", options=self.options()) + self.assertEqual(details.ticker, "OPTS") + self.assert_no_options_in_query(mock) + + def test_paginate_with_options(self): + mock = pook.get( + self.c.BASE + "/v3/trades/OPTS", + reply=200, + response_body='{"results": []}', + ) + trades = list(self.c.list_trades("OPTS", options=self.options())) + self.assertEqual(trades, []) + self.assert_no_options_in_query(mock) From 052a9fff05c926db10f964a073a2f0a07da544bd Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:53:56 -0600 Subject: [PATCH 02/22] test: stop pook mocks leaking between REST test classes BaseTest turned pook on and registered its mocks in setUpClass but never turned pook off, so every class's mocks stayed active for the rest of the run. That hid a problem in two tests. test_list_stocks_dividends_ticker_any_of and test_get_snapshot_indices each send the same request twice, but each mock answers only once. Their second request was answered by a copy that an earlier class had registered, so both fail with PookNoMatches when their module runs on its own. Turn pook off in tearDownClass. Let a test class name the mocks that must answer more than once, and register those with persist. Other mocks still answer once, because the pagination tests rely on it: a first-page mock also matches the request for the next page. --- test_rest/base.py | 17 ++++++++++++++++- test_rest/test_dividends.py | 3 +++ test_rest/test_snapshots.py | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/test_rest/base.py b/test_rest/base.py index 40854146..41b652d4 100644 --- a/test_rest/base.py +++ b/test_rest/base.py @@ -3,6 +3,7 @@ import os import re import unittest +from typing import Set import pook # type: ignore # mocks are stored in file tree @@ -32,6 +33,10 @@ class BaseTest(unittest.TestCase): + # mocks that answer more than once, for tests that repeat a request; + # others answer once, which the pagination tests rely on + persistent_mocks: Set[str] = set() + @classmethod def setUpClass(cls): cls.maxDiff = None @@ -40,4 +45,14 @@ def setUpClass(cls): for m in mocks: url = cls.c.BASE + m[0] # print("register", url) - pook.get(url, reply=200, response_body=m[1]) + pook.get( + url, + reply=200, + response_body=m[1], + persist=m[0] in cls.persistent_mocks, + ) + + @classmethod + def tearDownClass(cls): + # stop pook and drop the mocks, so they don't leak into later classes + pook.off() diff --git a/test_rest/test_dividends.py b/test_rest/test_dividends.py index 7b6575d0..8549df9d 100644 --- a/test_rest/test_dividends.py +++ b/test_rest/test_dividends.py @@ -3,6 +3,9 @@ class DividendsTest(BaseTest): + # test_list_stocks_dividends_ticker_any_of requests this twice + persistent_mocks = {"/stocks/v1/dividends?ticker.any_of=AAPL%2CVZ"} + def test_list_dividends(self): dividends = [d for d in self.c.list_dividends()] expected = [ diff --git a/test_rest/test_snapshots.py b/test_rest/test_snapshots.py index 3ead4e15..4472970a 100644 --- a/test_rest/test_snapshots.py +++ b/test_rest/test_snapshots.py @@ -26,6 +26,9 @@ class SnapshotsTest(BaseTest): + # test_get_snapshot_indices requests this twice + persistent_mocks = {"/v3/snapshot/indices?ticker.any_of=SPX%2CAPx%2CAPy"} + def test_list_universal_snapshots(self): expected = [ UniversalSnapshot( From a000902d31c8ff11f2195fed406474a47d2f348d Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:54:18 -0600 Subject: [PATCH 03/22] ci: run unit tests on Python 3.12, 3.13 and 3.14 The package supports Python 3.10 and later, but CI ran the unit tests only on 3.10 and 3.11. Add 3.12, 3.13 and 3.14 to the matrix, on both Ubuntu and Windows. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1ae9ada..b498c0b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ['3.10', '3.11'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] runs-on: ${{ matrix.os }} name: ${{ matrix.os }} Unit test ${{ matrix.python-version }} steps: From a06ef394ca93e4ee8565f45de3515a101269b59e Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:06:54 -0600 Subject: [PATCH 04/22] fix: log the topic for an invalid subscription _parse_subscription called logger.warning("invalid subscription:", s), passing the topic as a format argument with no placeholder. Logging printed "--- Logging error ---" and a traceback instead of the warning, and the rejected topic was never shown. Use a %s placeholder so the warning reads "invalid subscription: ", and add a test to test_status.py that goes through subscribe(). --- massive/websocket/__init__.py | 2 +- test_websocket/test_status.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 7463b4cb..da11c040 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -265,7 +265,7 @@ def _parse_subscription(s: str): s = s.strip() split = s.split(".", 1) # Split at the first period if len(split) != 2: - logger.warning("invalid subscription:", s) + logger.warning("invalid subscription: %s", s) return [None, None] return split diff --git a/test_websocket/test_status.py b/test_websocket/test_status.py index d333c9c8..c2bf2666 100644 --- a/test_websocket/test_status.py +++ b/test_websocket/test_status.py @@ -95,3 +95,13 @@ async def test_auth_reply_status_is_logged(self): "Maximum number of websocket connections exceeded." ], ) + + async def test_invalid_subscription_is_logged(self): + # a topic without a channel prefix is skipped with a warning + c = WebSocketClient(api_key="") + with self.assertLogs("WebSocketClient", level="WARNING") as logs: + c.subscribe("AAPL") + self.assertEqual( + logs.output, ["WARNING:WebSocketClient:invalid subscription: AAPL"] + ) + self.assertEqual(c.scheduled_subs, set()) From 182dd9d414355310b46e67f667924bcba9cc29ee Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:15:49 -0600 Subject: [PATCH 05/22] feat: let type checkers see model constructors @modelclass builds an __init__ that accepts every field positionally or by keyword, but type checkers could not see it: a call such as CryptoQuote(pair="BTC-USD", bid_price=1.5) was reported as "Unexpected keyword argument" for every field. Mark modelclass with dataclass_transform (PEP 681) so checkers derive the constructor from the field annotations. The decorator is imported only under TYPE_CHECKING, from typing on 3.11+ and from typing_extensions on 3.10, and is a no-op at runtime, so there is no new runtime dependency and Python 3.10 keeps working. --- massive/modelclass.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/massive/modelclass.py b/massive/modelclass.py index 117f7910..0605180a 100644 --- a/massive/modelclass.py +++ b/massive/modelclass.py @@ -1,10 +1,23 @@ import inspect +import sys import typing from dataclasses import dataclass +if typing.TYPE_CHECKING: + if sys.version_info >= (3, 11): + from typing import dataclass_transform + else: + from typing_extensions import dataclass_transform +else: + + def dataclass_transform(**kwargs): + return lambda f: f + + _T = typing.TypeVar("_T") +@dataclass_transform() def modelclass(cls: typing.Type[_T]) -> typing.Type[_T]: cls = dataclass(cls) type_hints = typing.get_type_hints(cls) From ce957c77be50e5442bbd3da9b1f125dfa80113c9 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:30:17 -0600 Subject: [PATCH 06/22] fix: correct type hints that disagree with the API Several hints describe values the API never sends or returns: - CryptoQuote.bid_price, ask_price and ask_size were int; XQ sends fractional numbers ("bp": 33052.79, "as": 0.601). They are float. - IndexValue.timestamp was str; V sends integer Unix milliseconds. - list_tickers(cusip=...) accepted only int. The API treats a CUSIP as a string: it is alphanumeric, and leading zeros matter ("037833100"). The hint now accepts str as well as int, so existing callers keep type-checking, and the docstring recommends a string. - get_previous_close_agg() was annotated as returning one PreviousCloseAgg, but it returns the "results" array as a list. - list_treasury_yields(), list_short_interest(), list_short_volume() and list_ipos() were annotated as returning a List, but like every other list_* method they return a paginating iterator. Hints that are imprecise but still admit every value the API sends, such as integer timestamps hinted as float, are left alone: narrowing them would gain little and could break callers that type-check today. Only annotations and docstrings change; runtime behaviour is the same. The tests pin the runtime types the corrected REST hints now describe. --- massive/rest/aggs.py | 4 ++-- massive/rest/economy.py | 4 ++-- massive/rest/reference.py | 12 ++++++------ massive/rest/vX.py | 4 ++-- massive/websocket/models/models.py | 8 ++++---- test_rest/test_aggs.py | 1 + test_rest/test_pagination.py | 15 +++++++++++++++ 7 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 test_rest/test_pagination.py diff --git a/massive/rest/aggs.py b/massive/rest/aggs.py index cb874fac..e72bea19 100644 --- a/massive/rest/aggs.py +++ b/massive/rest/aggs.py @@ -168,7 +168,7 @@ def get_previous_close_agg( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[PreviousCloseAgg, HTTPResponse]: + ) -> Union[List[PreviousCloseAgg], HTTPResponse]: """ Get the previous day's open, high, low, and close (OHLC) for the specified stock ticker. @@ -176,7 +176,7 @@ def get_previous_close_agg( :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 + :return: List of previous close aggregates (the API returns a one-element list) """ url = f"/v2/aggs/ticker/{ticker}/prev" diff --git a/massive/rest/economy.py b/massive/rest/economy.py index 4c4b251f..7ba52d88 100644 --- a/massive/rest/economy.py +++ b/massive/rest/economy.py @@ -35,7 +35,7 @@ def list_treasury_yields( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[List[TreasuryYield], HTTPResponse]: + ) -> Union[Iterator[TreasuryYield], HTTPResponse]: """ Retrieve treasury yield data. @@ -51,7 +51,7 @@ def list_treasury_yields( :param params: Additional query parameters. :param raw: Return raw HTTPResponse object if True, else return List[TreasuryYield]. :param options: RequestOptionBuilder for additional headers or params. - :return: A list of TreasuryYield objects or HTTPResponse if raw=True. + :return: An iterator of TreasuryYield objects or HTTPResponse if raw=True. """ url = "/fed/v1/treasury-yields" diff --git a/massive/rest/reference.py b/massive/rest/reference.py index b6886c55..12525548 100644 --- a/massive/rest/reference.py +++ b/massive/rest/reference.py @@ -92,7 +92,7 @@ def list_tickers( type: Optional[str] = None, market: Optional[str] = None, exchange: Optional[str] = None, - cusip: Optional[int] = None, + cusip: Optional[Union[int, str]] = None, cik: Optional[int] = None, date: Optional[str] = None, active: Optional[bool] = None, @@ -115,7 +115,7 @@ def list_tickers( :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 assets primary exchange Market Identifier Code (MIC) according to ISO 10383. 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 cusip: Specify the CUSIP code of the asset you want to search for. The API treats a CUSIP as a string, so pass a string such as "037833100": an int drops leading zeros and cannot hold the letters some CUSIPs contain. An int is still accepted for backward compatibility. 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. @@ -606,7 +606,7 @@ def list_short_interest( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[List[ShortInterest], HTTPResponse]: + ) -> Union[Iterator[ShortInterest], HTTPResponse]: """ Retrieve short interest data for stocks. @@ -632,7 +632,7 @@ def list_short_interest( :param params: Additional query parameters. :param raw: Return raw HTTPResponse object if True, else return List[ShortInterest]. :param options: RequestOptionBuilder for additional headers or params. - :return: A list of ShortInterest objects or HTTPResponse if raw=True. + :return: An iterator of ShortInterest objects or HTTPResponse if raw=True. """ url = "/stocks/v1/short-interest" @@ -669,7 +669,7 @@ def list_short_volume( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[List[ShortVolume], HTTPResponse]: + ) -> Union[Iterator[ShortVolume], HTTPResponse]: """ Retrieve short volume data for stocks. @@ -695,7 +695,7 @@ def list_short_volume( :param params: Additional query parameters. :param raw: Return raw HTTPResponse object if True, else return List[ShortVolume]. :param options: RequestOptionBuilder for additional headers or params. - :return: A list of ShortVolume objects or HTTPResponse if raw=True. + :return: An iterator of ShortVolume objects or HTTPResponse if raw=True. """ url = "/stocks/v1/short-volume" diff --git a/massive/rest/vX.py b/massive/rest/vX.py index ebd95a1a..91b1e782 100644 --- a/massive/rest/vX.py +++ b/massive/rest/vX.py @@ -93,7 +93,7 @@ def list_ipos( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[List[IPOListing], HTTPResponse]: + ) -> Union[Iterator[IPOListing], HTTPResponse]: """ Retrieve upcoming or historical IPOs. @@ -108,7 +108,7 @@ def list_ipos( :param params: Additional query params. :param raw: Return raw HTTPResponse object if True, else return List[IPOListing]. :param options: RequestOptionBuilder for additional headers or params. - :return: A list of IPOListing objects or HTTPResponse if raw=True. + :return: An iterator of IPOListing objects or HTTPResponse if raw=True. """ url = "/vX/reference/ipos" diff --git a/massive/websocket/models/models.py b/massive/websocket/models/models.py index 6b3acd90..d3711e57 100644 --- a/massive/websocket/models/models.py +++ b/massive/websocket/models/models.py @@ -217,10 +217,10 @@ class CryptoQuote: event_type: Optional[Union[str, EventType]] = None pair: Optional[str] = None - bid_price: Optional[int] = None + bid_price: Optional[float] = None bid_size: Optional[float] = None - ask_price: Optional[int] = None - ask_size: Optional[int] = None + ask_price: Optional[float] = None + ask_size: Optional[float] = None timestamp: Optional[float] = None exchange_id: Optional[int] = None received_timestamp: Optional[int] = None @@ -328,7 +328,7 @@ class IndexValue: event_type: Optional[Union[str, EventType]] = None value: Optional[float] = None ticker: Optional[str] = None - timestamp: Optional[str] = None + timestamp: Optional[int] = None @staticmethod def from_dict(d): diff --git a/test_rest/test_aggs.py b/test_rest/test_aggs.py index 850a00da..5ec5826a 100644 --- a/test_rest/test_aggs.py +++ b/test_rest/test_aggs.py @@ -98,6 +98,7 @@ def test_get_daily_open_close_agg(self): def test_get_previous_close_agg(self): aggs = self.c.get_previous_close_agg("AAPL") + self.assertIsInstance(aggs, list) expected = [ PreviousCloseAgg( ticker="AAPL", diff --git a/test_rest/test_pagination.py b/test_rest/test_pagination.py new file mode 100644 index 00000000..f0f86aa2 --- /dev/null +++ b/test_rest/test_pagination.py @@ -0,0 +1,15 @@ +import types + +from base import BaseTest + + +class PaginationTest(BaseTest): + def test_list_methods_return_iterators(self): + # The iterators are lazy, so no request is sent. + for result in ( + self.c.list_treasury_yields(), + self.c.list_short_interest(), + self.c.list_short_volume(), + self.c.vx.list_ipos(), + ): + self.assertIsInstance(result, types.GeneratorType) From 89df4590f72feb8da8a800423dd4a49b99eebe73 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:55:47 -0600 Subject: [PATCH 07/22] fix: include the HTTP status in BadResponse BaseClient._get raised BadResponse(resp.data.decode("utf-8")) for any non-200 response, so the status code was lost. Callers had to guess from the body whether the key was not entitled (403) or the resource was missing (404). BadResponse now takes a keyword-only status argument and stores it as an attribute, and _get passes resp.status. Positional arguments still go to Exception unchanged, so str(exc) and exc.args are the same as before, and BadResponse() still works (status is None). exceptions.py gets an __all__, so the package's star import does not re-export typing.Optional as massive.Optional. --- massive/exceptions.py | 13 +++++++++++- massive/rest/base.py | 2 +- test_rest/test_bad_response.py | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test_rest/test_bad_response.py diff --git a/massive/exceptions.py b/massive/exceptions.py index b8960763..d5b1c40b 100644 --- a/massive/exceptions.py +++ b/massive/exceptions.py @@ -1,3 +1,9 @@ +from typing import Optional + +# the package star-imports this module; keep Optional out of its namespace +__all__ = ["AuthError", "BadResponse"] + + class AuthError(Exception): """ Empty or invalid API key @@ -9,6 +15,11 @@ class AuthError(Exception): class BadResponse(Exception): """ Non-200 response from API + + The message is the response body. ``status`` is the HTTP status code, or + None if not given. """ - pass + def __init__(self, *args: object, status: Optional[int] = None): + super().__init__(*args) + self.status = status diff --git a/massive/rest/base.py b/massive/rest/base.py index 294dd482..7b728685 100644 --- a/massive/rest/base.py +++ b/massive/rest/base.py @@ -152,7 +152,7 @@ def _get( ) if resp.status != 200: - raise BadResponse(resp.data.decode("utf-8")) + raise BadResponse(resp.data.decode("utf-8"), status=resp.status) if raw: return resp diff --git a/test_rest/test_bad_response.py b/test_rest/test_bad_response.py new file mode 100644 index 00000000..23c86e7b --- /dev/null +++ b/test_rest/test_bad_response.py @@ -0,0 +1,38 @@ +from massive.exceptions import BadResponse +from base import BaseTest + +import pook # type: ignore + + +class BadResponseTest(BaseTest): + def test_status_is_set(self): + cases = [ + (403, '{"status":"NOT_AUTHORIZED","message":"not entitled"}'), + (404, '{"status":"NOT_FOUND","message":"not found"}'), + ] + for status, body in cases: + with self.subTest(status=status): + ticker = f"ERR{status}" # not covered by the fixture mocks + pook.get( + self.c.BASE + "/v3/reference/tickers/" + ticker, + reply=status, + response_body=body, + ) + with self.assertRaises(BadResponse) as ctx: + self.c.get_ticker_details(ticker) + self.assertEqual(ctx.exception.status, status) + self.assertEqual(ctx.exception.args, (body,)) + self.assertEqual(str(ctx.exception), body) + + def test_status_defaults_to_none(self): + for args in [(), ("boom",), ("boom", 1)]: + with self.subTest(args=args): + exc = BadResponse(*args) + self.assertEqual(exc.args, args) + self.assertIsNone(exc.status) + + def test_status_does_not_change_message(self): + exc = BadResponse("boom", status=500) + self.assertEqual(exc.args, ("boom",)) + self.assertEqual(str(exc), "boom") + self.assertEqual(exc.status, 500) From ab204773bfec96f71b3ced60a9a85f6d2e490617 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:01:44 -0600 Subject: [PATCH 08/22] ci: run unit tests on free-threaded Python 3.14t The client is used from multi-threaded programs, and the GIL can hide race conditions. Add one job that runs the unit tests on free-threaded 3.14t with PYTHON_GIL=0, after checking that the GIL really is off. The job installs with pip, because the tests need only the package and pook. Add a test that shares one RESTClient between 16 threads against a local server that echoes each request back. It checks that every response answers its own request, including the per-request edge headers, that the threads really overlapped, and that per-request headers never reach the client's default headers. --- .github/workflows/test.yml | 20 +++++++++ test_rest/test_concurrency.py | 76 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 test_rest/test_concurrency.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1ae9ada..889444cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,3 +32,23 @@ jobs: run: poetry install - name: Unit tests run: make test + test-free-threaded: + runs-on: ubuntu-latest + name: ubuntu-latest Unit test 3.14t (PYTHON_GIL=0) + env: + PYTHON_GIL: '0' + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.14t' + - name: Install pypi deps + # the tests need only the package and pook, not the dev tools + run: pip install -e . pook + - name: Check that the GIL is off + run: python -c "import sys; assert not sys._is_gil_enabled(), sys.version" + - name: Unit tests + run: | + python -m unittest discover -s test_rest + python -m unittest discover -s test_websocket diff --git a/test_rest/test_concurrency.py b/test_rest/test_concurrency.py new file mode 100644 index 00000000..9f4e9aa7 --- /dev/null +++ b/test_rest/test_concurrency.py @@ -0,0 +1,76 @@ +import json +import threading +import unittest +from concurrent.futures import ThreadPoolExecutor +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + +from massive import RESTClient +from massive.rest.models.request import RequestOptionBuilder, X_MASSIVE_EDGE_ID + + +class EchoServer(ThreadingHTTPServer): + "Echoes each request back, and records the most requests in flight at once." + + daemon_threads = True + + def __init__(self): + super().__init__(("127.0.0.1", 0), EchoHandler) + self.lock = threading.Lock() + self.in_flight = 0 + self.peak = 0 + + +class EchoHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" # keep-alive, so pooled connections are reused + server: EchoServer + + def do_GET(self): + with self.server.lock: + self.server.in_flight += 1 + self.server.peak = max(self.server.peak, self.server.in_flight) + body = json.dumps([self.path, self.headers.get(X_MASSIVE_EDGE_ID)]).encode() + self.send_response(200) + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + with self.server.lock: + self.server.in_flight -= 1 + + def log_message(self, format, *args): + pass + + +class ConcurrencyTest(unittest.TestCase): + threads = 16 + calls = 64 + + def test_shared_client(self): + httpd = EchoServer() + threading.Thread(target=httpd.serve_forever, daemon=True).start() + self.addCleanup(httpd.server_close) + self.addCleanup(httpd.shutdown) + host, port = httpd.server_address[:2] + c = RESTClient("key", base=f"http://{host!s}:{port}", maxsize=self.threads) + headers_before = list(c.headers.items()) + barrier = threading.Barrier(self.threads, timeout=10) + + def run(t): + barrier.wait() # start together, so the requests overlap + for i in range(self.calls): + path = f"/v3/reference/tickers/T{t}N{i}" + # odd calls send per-request headers, even calls send none + edge_id = f"edge-{t}-{i}" if i % 2 else None + options = RequestOptionBuilder(edge_id, "10.0.0.1") if edge_id else None + # _get, which every endpoint calls; endpoint methods currently + # also copy `options` into the query string + resp = c._get(path=path, params={"n": i}, raw=True, options=options) + # the response answers this call's request, not another thread's + self.assertEqual(json.loads(resp.data), [f"{path}?n={i}", edge_id]) + + with ThreadPoolExecutor(self.threads) as pool: + for f in [pool.submit(run, t) for t in range(self.threads)]: + f.result() + + self.assertGreater(httpd.peak, 1) # the threads really overlapped + # per-request headers never leak into the client's default headers + self.assertEqual(list(c.headers.items()), headers_before) From 0f6a9d7e333a45f253abf7dbf156c6911ceef30d Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:15:49 -0600 Subject: [PATCH 09/22] feat: let type checkers see model constructors @modelclass builds an __init__ that accepts every field positionally or by keyword, but type checkers could not see it: a call such as CryptoQuote(pair="BTC-USD", bid_price=1.5) was reported as "Unexpected keyword argument" for every field. Mark modelclass with dataclass_transform (PEP 681) so checkers derive the constructor from the field annotations. The decorator is imported only under TYPE_CHECKING, from typing on 3.11+ and from typing_extensions on 3.10, and is a no-op at runtime, so there is no new runtime dependency and Python 3.10 keeps working. --- massive/modelclass.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/massive/modelclass.py b/massive/modelclass.py index 117f7910..0605180a 100644 --- a/massive/modelclass.py +++ b/massive/modelclass.py @@ -1,10 +1,23 @@ import inspect +import sys import typing from dataclasses import dataclass +if typing.TYPE_CHECKING: + if sys.version_info >= (3, 11): + from typing import dataclass_transform + else: + from typing_extensions import dataclass_transform +else: + + def dataclass_transform(**kwargs): + return lambda f: f + + _T = typing.TypeVar("_T") +@dataclass_transform() def modelclass(cls: typing.Type[_T]) -> typing.Type[_T]: cls = dataclass(cls) type_hints = typing.get_type_hints(cls) From 81b08a364f30b350d32e3cc7b56eb99b138948e8 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:02:29 -0600 Subject: [PATCH 10/22] fix: match WebSocket wildcard topics on the exact channel Subscribing to a wildcard such as A.* drops the other subscribed topics on that channel. The match used t.startswith(channel), so it also dropped topics on every channel whose name starts with the same letters: subscribe("A.*") unsubscribed AM.AAPL. It also matched the wildcard itself, so subscribing to A.* a second time unsubscribed it. Compare the channel exactly, and skip the wildcard being subscribed. unsubscribe() used the same match and gets the same fix. As before, only topics already sent are checked. --- massive/websocket/__init__.py | 4 ++-- test_websocket/test_wildcard.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 test_websocket/test_wildcard.py diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 7463b4cb..24773b56 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -285,7 +285,7 @@ def subscribe(self, *subscriptions: str): # If user subs to X.*, remove other X.\w+ if sym == "*": for t in list(self.subs): - if t.startswith(topic): + if t != s and t.strip().split(".", 1)[0] == topic: self.scheduled_subs.discard(t) self.schedule_resub = True @@ -306,7 +306,7 @@ def unsubscribe(self, *subscriptions: str): # If user unsubs to X.*, remove other X.\w+ if sym == "*": for t in list(self.subs): - if t.startswith(topic): + if t.strip().split(".", 1)[0] == topic: self.scheduled_subs.discard(t) self.schedule_resub = True diff --git a/test_websocket/test_wildcard.py b/test_websocket/test_wildcard.py new file mode 100644 index 00000000..9224a165 --- /dev/null +++ b/test_websocket/test_wildcard.py @@ -0,0 +1,28 @@ +import unittest +from massive import WebSocketClient + + +class WildcardTest(unittest.TestCase): + def client(self, *subs): + c = WebSocketClient(api_key="", subscriptions=list(subs)) + c.subs = set(subs) # as if connect() had sent them + return c + + def test_subscribe_wildcard_keeps_other_channels(self): + c = self.client("A.MSFT", "AM.AAPL") + c.subscribe("A.*") + self.assertEqual(c.scheduled_subs, {"A.*", "AM.AAPL"}) + + def test_subscribe_wildcard_twice_keeps_it(self): + c = self.client("A.*") + c.subscribe("A.*") + self.assertEqual(c.scheduled_subs, {"A.*"}) + + def test_unsubscribe_wildcard_keeps_other_channels(self): + c = self.client("A.*", "A.MSFT", "AM.AAPL") + c.unsubscribe("A.*") + self.assertEqual(c.scheduled_subs, {"AM.AAPL"}) + + +if __name__ == "__main__": + unittest.main() From 8da79e199baa5611fef7907c29105f5bf5c3ae2b Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:02:31 -0600 Subject: [PATCH 11/22] feat: ship py.typed so the package is checked as typed Without the PEP 561 marker, mypy skips the installed package and reports import-untyped, and users who silence that get Any for every massive type. - Add massive/py.typed. The existing packages entry in pyproject.toml already includes it in the wheel and sdist. - Re-export RESTClient and WebSocketClient explicitly ("X as X"), so "from massive import RESTClient" passes mypy --strict, which does not treat plain imports in a typed package as re-exports. No __all__ is added, so "from massive import *" exports the same names as before. - Add a test that "from massive import *" still provides the main names. --- massive/__init__.py | 4 ++-- massive/py.typed | 0 test_rest/test_exports.py | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 massive/py.typed create mode 100644 test_rest/test_exports.py diff --git a/massive/__init__.py b/massive/__init__.py index da6c5136..04f41281 100644 --- a/massive/__init__.py +++ b/massive/__init__.py @@ -1,6 +1,6 @@ -from .rest import RESTClient +from .rest import RESTClient as RESTClient from .rest.base import version -from .websocket import WebSocketClient +from .websocket import WebSocketClient as WebSocketClient from .exceptions import * __version__ = version diff --git a/massive/py.typed b/massive/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/test_rest/test_exports.py b/test_rest/test_exports.py new file mode 100644 index 00000000..3c3c40bc --- /dev/null +++ b/test_rest/test_exports.py @@ -0,0 +1,9 @@ +import unittest + + +class ExportsTest(unittest.TestCase): + def test_star_import(self): + ns = {} + exec("from massive import *", ns) + for name in ("RESTClient", "WebSocketClient", "AuthError", "BadResponse"): + self.assertIn(name, ns) From 52c0ab583c469843efc6f71abe5f842b6c4a2380 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:07:56 -0600 Subject: [PATCH 12/22] feat: add list_funding_conditions for /fed/v1/funding-conditions The Fed funding-conditions endpoint is documented in the OpenAPI spec and on massive.com/docs but had no client method; the economy client only covered treasury-yields, inflation, inflation-expectations, and labor-market. Add EconomyClient.list_funding_conditions, a paginated list method in the same shape as list_treasury_yields. Its query parameters follow the documented ones exactly: date, date.gt, date.gte, date.lt, date.lte, limit, and sort (this endpoint documents no date.any_of or order). sort is typed Optional[str], as in list_labor_market_indicators, rather than Union[str, Sort]. The endpoint takes column.direction values such as "date.desc", so Sort.ASC would send a bare "asc" that it does not accept. Add the FedFundingConditions model with all 22 documented result fields (date plus the fed funds, IORB, SOFR, OBFR, TGCR, repo/reverse repo, and commercial paper series). Tests cover a two-page fixture (including a weekend row whose business-day series are null), check with pook that all seven parameters are sent under their API names (date.gt rather than date_gt, and so on), and check that a multi-column sort string is sent unchanged. Add an example script. --- examples/rest/economy-funding_conditions.py | 13 +++ massive/rest/economy.py | 40 +++++++++ massive/rest/models/economy.py | 70 +++++++++++++++ ...=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x.json | 31 +++++++ ...onditions&date.gte=2025-06-01&limit=1.json | 32 +++++++ test_rest/test_economy.py | 89 +++++++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 examples/rest/economy-funding_conditions.py create mode 100644 test_rest/mocks/fed/v1/funding-conditions&cursor=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x.json create mode 100644 test_rest/mocks/fed/v1/funding-conditions&date.gte=2025-06-01&limit=1.json create mode 100644 test_rest/test_economy.py diff --git a/examples/rest/economy-funding_conditions.py b/examples/rest/economy-funding_conditions.py new file mode 100644 index 00000000..4dc948d2 --- /dev/null +++ b/examples/rest/economy-funding_conditions.py @@ -0,0 +1,13 @@ +from massive import RESTClient + +# docs +# https://massive.com/docs/rest/economy/funding-conditions + +# client = RESTClient("XXXXXX") # hardcoded api_key is used +client = RESTClient() # MASSIVE_API_KEY environment variable is used + +conditions = [] +for day in client.list_funding_conditions(date_gte="2025-06-01", sort="date.asc"): + conditions.append(day) + +print(conditions) diff --git a/massive/rest/economy.py b/massive/rest/economy.py index 4c4b251f..ddc4fb61 100644 --- a/massive/rest/economy.py +++ b/massive/rest/economy.py @@ -8,6 +8,7 @@ TreasuryYield, FedInflationExpectations, FedLaborMarket, + FedFundingConditions, EUMerchantAggregate, EUMerchantHierarchy, ) @@ -171,6 +172,45 @@ def list_labor_market_indicators( options=options, ) + def list_funding_conditions( + self, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedFundingConditions], HTTPResponse]: + """ + Daily U.S. money-market funding conditions from the Federal Reserve and the Federal Reserve Bank of New York, including the Federal Funds Effective Rate, SOFR, OBFR, tri-party general collateral repo rates, Treasury-collateralized overnight reverse repo and repo operation amounts, and commercial paper rates. + + :param date: Calendar date of the observation (YYYY-MM-DD). + :param date_gt: Filter greater than the value. + :param date_gte: Filter greater than or equal to the value. + :param date_lt: Filter less than the value. + :param date_lte: Filter less than or equal to the value. + :param limit: Limit the maximum number of results returned. Defaults to '100' if not specified. The maximum allowed limit is '50000'. + :param sort: A comma separated list of sort columns. For each column, append '.asc' or '.desc' to specify the sort direction, e.g. "date.desc". The sort column defaults to 'date' if not specified. The sort order defaults to 'asc' if not specified. The value is sent as given. + :param params: Additional query parameters. + :param raw: Return raw HTTPResponse object if True, else return Iterator[FedFundingConditions]. + :param options: RequestOptionBuilder for additional headers or params. + :return: An iterator of FedFundingConditions objects or HTTPResponse if raw=True. + """ + url = "/fed/v1/funding-conditions" + + return self._paginate( + path=url, + params=self._get_params(self.list_funding_conditions, locals()), + deserializer=FedFundingConditions.from_dict, + raw=raw, + result_key="results", + options=options, + ) + def list_eu_merchant_aggregates( self, transaction_date: Optional[Union[str, date]] = None, diff --git a/massive/rest/models/economy.py b/massive/rest/models/economy.py index 97386235..d0636f56 100644 --- a/massive/rest/models/economy.py +++ b/massive/rest/models/economy.py @@ -106,6 +106,76 @@ def from_dict(d): ) +@modelclass +class FedFundingConditions: + """ + Daily U.S. money-market funding conditions for a specific date. Rates are + percentages; volumes and operation amounts are in billions of U.S. dollars. + """ + + date: Optional[str] = None + effective_fed_funds_rate: Optional[float] = None + effective_fed_funds_volume: Optional[float] = None + fed_funds_target_lower: Optional[float] = None + fed_funds_target_upper: Optional[float] = None + fed_overnight_repo_treasury_amount: Optional[float] = None + fed_overnight_reverse_repo_treasury_amount: Optional[float] = None + financial_commercial_paper_90d_rate: Optional[float] = None + interest_on_reserve_balances: Optional[float] = None + nonfinancial_commercial_paper_90d_rate: Optional[float] = None + obfr_25th_percentile: Optional[float] = None + obfr_75th_percentile: Optional[float] = None + obfr_volume: Optional[float] = None + overnight_bank_funding_rate: Optional[float] = None + secured_overnight_financing_rate: Optional[float] = None + sofr_25th_percentile: Optional[float] = None + sofr_75th_percentile: Optional[float] = None + sofr_volume: Optional[float] = None + tgcr_25th_percentile: Optional[float] = None + tgcr_75th_percentile: Optional[float] = None + tri_party_general_collateral_rate: Optional[float] = None + tri_party_general_collateral_volume: Optional[float] = None + + @staticmethod + def from_dict(d): + return FedFundingConditions( + date=d.get("date"), + effective_fed_funds_rate=d.get("effective_fed_funds_rate"), + effective_fed_funds_volume=d.get("effective_fed_funds_volume"), + fed_funds_target_lower=d.get("fed_funds_target_lower"), + fed_funds_target_upper=d.get("fed_funds_target_upper"), + fed_overnight_repo_treasury_amount=d.get( + "fed_overnight_repo_treasury_amount" + ), + fed_overnight_reverse_repo_treasury_amount=d.get( + "fed_overnight_reverse_repo_treasury_amount" + ), + financial_commercial_paper_90d_rate=d.get( + "financial_commercial_paper_90d_rate" + ), + interest_on_reserve_balances=d.get("interest_on_reserve_balances"), + nonfinancial_commercial_paper_90d_rate=d.get( + "nonfinancial_commercial_paper_90d_rate" + ), + obfr_25th_percentile=d.get("obfr_25th_percentile"), + obfr_75th_percentile=d.get("obfr_75th_percentile"), + obfr_volume=d.get("obfr_volume"), + overnight_bank_funding_rate=d.get("overnight_bank_funding_rate"), + secured_overnight_financing_rate=d.get("secured_overnight_financing_rate"), + sofr_25th_percentile=d.get("sofr_25th_percentile"), + sofr_75th_percentile=d.get("sofr_75th_percentile"), + sofr_volume=d.get("sofr_volume"), + tgcr_25th_percentile=d.get("tgcr_25th_percentile"), + tgcr_75th_percentile=d.get("tgcr_75th_percentile"), + tri_party_general_collateral_rate=d.get( + "tri_party_general_collateral_rate" + ), + tri_party_general_collateral_volume=d.get( + "tri_party_general_collateral_volume" + ), + ) + + @modelclass class EUMerchantAggregate: """ diff --git a/test_rest/mocks/fed/v1/funding-conditions&cursor=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x.json b/test_rest/mocks/fed/v1/funding-conditions&cursor=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x.json new file mode 100644 index 00000000..1f20e1b3 --- /dev/null +++ b/test_rest/mocks/fed/v1/funding-conditions&cursor=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x.json @@ -0,0 +1,31 @@ +{ + "status": "OK", + "request_id": "b2170df985474b6d21a6eeccfb6bee67", + "count": 1, + "results": [ + { + "date": "2025-06-02", + "effective_fed_funds_rate": 4.33, + "effective_fed_funds_volume": 98, + "fed_funds_target_lower": 4.25, + "fed_funds_target_upper": 4.5, + "fed_overnight_repo_treasury_amount": 0, + "fed_overnight_reverse_repo_treasury_amount": 214.5, + "financial_commercial_paper_90d_rate": 4.35, + "interest_on_reserve_balances": 4.4, + "nonfinancial_commercial_paper_90d_rate": 4.34, + "obfr_25th_percentile": 4.3, + "obfr_75th_percentile": 4.33, + "obfr_volume": 305, + "overnight_bank_funding_rate": 4.32, + "secured_overnight_financing_rate": 4.31, + "sofr_25th_percentile": 4.28, + "sofr_75th_percentile": 4.32, + "sofr_volume": 2214, + "tgcr_25th_percentile": 4.27, + "tgcr_75th_percentile": 4.31, + "tri_party_general_collateral_rate": 4.3, + "tri_party_general_collateral_volume": 1876 + } + ] +} diff --git a/test_rest/mocks/fed/v1/funding-conditions&date.gte=2025-06-01&limit=1.json b/test_rest/mocks/fed/v1/funding-conditions&date.gte=2025-06-01&limit=1.json new file mode 100644 index 00000000..f294c384 --- /dev/null +++ b/test_rest/mocks/fed/v1/funding-conditions&date.gte=2025-06-01&limit=1.json @@ -0,0 +1,32 @@ +{ + "status": "OK", + "request_id": "6a7e466379af0a71039d60cc78e72282", + "count": 1, + "next_url": "https://api.massive.com/fed/v1/funding-conditions?cursor=ZGF0ZS5ndGU9MjAyNS0wNi0wMSZsaW1pdD0x", + "results": [ + { + "date": "2025-06-01", + "effective_fed_funds_rate": 4.33, + "effective_fed_funds_volume": null, + "fed_funds_target_lower": 4.25, + "fed_funds_target_upper": 4.5, + "fed_overnight_repo_treasury_amount": null, + "fed_overnight_reverse_repo_treasury_amount": null, + "financial_commercial_paper_90d_rate": null, + "interest_on_reserve_balances": 4.4, + "nonfinancial_commercial_paper_90d_rate": null, + "obfr_25th_percentile": null, + "obfr_75th_percentile": null, + "obfr_volume": null, + "overnight_bank_funding_rate": null, + "secured_overnight_financing_rate": null, + "sofr_25th_percentile": null, + "sofr_75th_percentile": null, + "sofr_volume": null, + "tgcr_25th_percentile": null, + "tgcr_75th_percentile": null, + "tri_party_general_collateral_rate": null, + "tri_party_general_collateral_volume": null + } + ] +} diff --git a/test_rest/test_economy.py b/test_rest/test_economy.py new file mode 100644 index 00000000..223475f1 --- /dev/null +++ b/test_rest/test_economy.py @@ -0,0 +1,89 @@ +import pook # type: ignore + +from base import BaseTest +from massive.rest.models.economy import FedFundingConditions + + +class EconomyTest(BaseTest): + def test_list_funding_conditions(self): + conditions = [ + c for c in self.c.list_funding_conditions(date_gte="2025-06-01", limit=1) + ] + expected = [ + FedFundingConditions( + date="2025-06-01", + effective_fed_funds_rate=4.33, + fed_funds_target_lower=4.25, + fed_funds_target_upper=4.5, + interest_on_reserve_balances=4.4, + ), + FedFundingConditions( + date="2025-06-02", + effective_fed_funds_rate=4.33, + effective_fed_funds_volume=98, + fed_funds_target_lower=4.25, + fed_funds_target_upper=4.5, + fed_overnight_repo_treasury_amount=0, + fed_overnight_reverse_repo_treasury_amount=214.5, + financial_commercial_paper_90d_rate=4.35, + interest_on_reserve_balances=4.4, + nonfinancial_commercial_paper_90d_rate=4.34, + obfr_25th_percentile=4.3, + obfr_75th_percentile=4.33, + obfr_volume=305, + overnight_bank_funding_rate=4.32, + secured_overnight_financing_rate=4.31, + sofr_25th_percentile=4.28, + sofr_75th_percentile=4.32, + sofr_volume=2214, + tgcr_25th_percentile=4.27, + tgcr_75th_percentile=4.31, + tri_party_general_collateral_rate=4.3, + tri_party_general_collateral_volume=1876, + ), + ] + self.assertEqual(conditions, expected) + + def test_list_funding_conditions_query_params(self): + # each documented parameter is sent under its API name (date.gt, not date_gt) + params = { + "date": "2025-06-02", + "date.gt": "2025-06-01", + "date.gte": "2025-06-01", + "date.lt": "2025-06-03", + "date.lte": "2025-06-03", + "limit": "10", + "sort": "date.desc", + } + mock = pook.get( + self.c.BASE + "/fed/v1/funding-conditions", + params=params, + reply=200, + response_json={"results": []}, + ) + conditions = self.c.list_funding_conditions( + date="2025-06-02", + date_gt="2025-06-01", + date_gte="2025-06-01", + date_lt="2025-06-03", + date_lte="2025-06-03", + limit=10, + sort="date.desc", + ) + self.assertEqual(list(conditions), []) + self.assertEqual(mock.calls, 1) + self.assertEqual(mock.matches[0].query, {k: [v] for k, v in params.items()}) + + def test_list_funding_conditions_sort_is_sent_as_given(self): + # sort takes "." values, comma separated, not a + # bare direction, so the client must send the string unchanged. + sort = "date.desc,effective_fed_funds_rate.asc" + mock = pook.get( + self.c.BASE + "/fed/v1/funding-conditions", + params={"sort": sort}, + reply=200, + response_json={"results": []}, + ) + self.assertEqual(list(self.c.list_funding_conditions(sort=sort)), []) + self.assertEqual(mock.calls, 1) + self.assertEqual(mock.matches[0].query, {"sort": [sort]}) From 6ead873b22b5f980cdd8b520b91d95fb13c6f414 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:09:00 -0600 Subject: [PATCH 13/22] feat: add get_daily_open_close_crypto for /v1/open-close/crypto/{from}/{to}/{date} The crypto daily open/close endpoint is documented in the OpenAPI spec and on massive.com/docs but had no client method. The docs and the crypto example pointed at get_daily_open_close_agg, which calls /v1/open-close/{ticker}/{date}, a different endpoint whose response (afterHours, preMarket, high, low, volume) does not match the crypto one. Add AggsClient.get_daily_open_close_crypto(from_, to, date, adjusted) and two models matching the documented response: - DailyOpenCloseCrypto: symbol, is_utc (isUTC), day, open, close, open_trades (openTrades), closing_trades (closingTrades). - DailyOpenCloseCryptoTrade: conditions (c), id (i), price (p), size (s), timestamp (t), exchange (x). Test against a fixture built from the documented example response. Give the method its own section in the Aggs docs, move the crypto docs link there, and point the crypto example at the new method. --- docs/source/Aggs.rst | 9 ++- examples/rest/crypto-daily_open_close.py | 7 ++- massive/rest/aggs.py | 41 ++++++++++++- massive/rest/models/aggs.py | 60 ++++++++++++++++++- .../BTC/USD/2020-10-09&adjusted=true.json | 51 ++++++++++++++++ test_rest/test_aggs.py | 52 ++++++++++++++++ 6 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 test_rest/mocks/v1/open-close/crypto/BTC/USD/2020-10-09&adjusted=true.json diff --git a/docs/source/Aggs.rst b/docs/source/Aggs.rst index b8e3fcc8..45fccd7c 100644 --- a/docs/source/Aggs.rst +++ b/docs/source/Aggs.rst @@ -41,10 +41,17 @@ Get daily open close agg - `Stocks daily open/close agg`_ - `Options daily open/close agg`_ -- `Crypto daily open/close agg`_ .. automethod:: massive.RESTClient.get_daily_open_close_agg +============================ +Get daily open close crypto +============================ + +- `Crypto daily open/close agg`_ + +.. automethod:: massive.RESTClient.get_daily_open_close_crypto + ============================ Get previous close agg ============================ diff --git a/examples/rest/crypto-daily_open_close.py b/examples/rest/crypto-daily_open_close.py index 5c29db0c..41971796 100644 --- a/examples/rest/crypto-daily_open_close.py +++ b/examples/rest/crypto-daily_open_close.py @@ -2,14 +2,15 @@ # docs # https://massive.com/docs/crypto/get_v1_open-close_crypto__from___to___date -# https://massive-api-client.readthedocs.io/en/latest/Aggs.html#get-daily-open-close-agg +# https://massive-api-client.readthedocs.io/en/latest/Aggs.html#get-daily-open-close-crypto # client = RESTClient("XXXXXX") # hardcoded api_key is used client = RESTClient() # MASSIVE_API_KEY environment variable is used # make request -request = client.get_daily_open_close_agg( - "X:BTCUSD", +request = client.get_daily_open_close_crypto( + "BTC", + "USD", "2023-01-09", ) diff --git a/massive/rest/aggs.py b/massive/rest/aggs.py index cb874fac..adfab927 100644 --- a/massive/rest/aggs.py +++ b/massive/rest/aggs.py @@ -1,6 +1,13 @@ from .base import BaseClient from typing import Optional, Any, Dict, List, Union, Iterator -from .models import Agg, GroupedDailyAgg, DailyOpenCloseAgg, PreviousCloseAgg, Sort +from .models import ( + Agg, + GroupedDailyAgg, + DailyOpenCloseAgg, + DailyOpenCloseCrypto, + PreviousCloseAgg, + Sort, +) from urllib3 import HTTPResponse from datetime import datetime, date @@ -161,6 +168,38 @@ def get_daily_open_close_agg( options=options, ) + def get_daily_open_close_crypto( + self, + # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp + from_: str, + to: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[DailyOpenCloseCrypto, HTTPResponse]: + """ + Get the open and close prices of a cryptocurrency pair on a certain day, along with the opening and closing trades. + + :param from_: The "from" symbol of the pair (e.g. "BTC"). + :param to: The "to" symbol of the pair (e.g. "USD"). + :param date: The date of the requested open/close in the format YYYY-MM-DD. + :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 for the crypto pair + """ + url = f"/v1/open-close/crypto/{from_}/{to}/{date}" + + return self._get( + path=url, + params=self._get_params(self.get_daily_open_close_crypto, locals()), + deserializer=DailyOpenCloseCrypto.from_dict, + raw=raw, + options=options, + ) + def get_previous_close_agg( self, ticker: str, diff --git a/massive/rest/models/aggs.py b/massive/rest/models/aggs.py index 49bba680..7315237e 100644 --- a/massive/rest/models/aggs.py +++ b/massive/rest/models/aggs.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import List, Optional from ...modelclass import modelclass @@ -95,6 +95,64 @@ def from_dict(d): ) +@modelclass +class DailyOpenCloseCryptoTrade: + "Contains data for one of the opening or closing trades of a crypto pair on a specified date." + + conditions: Optional[List[int]] = None + id: Optional[str] = None + price: Optional[float] = None + size: Optional[float] = None + timestamp: Optional[int] = None + exchange: Optional[int] = None + + @staticmethod + def from_dict(d): + return DailyOpenCloseCryptoTrade( + conditions=d.get("c", None), + id=d.get("i", None), + price=d.get("p", None), + size=d.get("s", None), + timestamp=d.get("t", None), + exchange=d.get("x", None), + ) + + +@modelclass +class DailyOpenCloseCrypto: + "Contains data for open and close prices, and the opening and closing trades, of a crypto pair on a specified date." + + symbol: Optional[str] = None + is_utc: Optional[bool] = None + day: Optional[str] = None + open: Optional[float] = None + close: Optional[float] = None + open_trades: Optional[List[DailyOpenCloseCryptoTrade]] = None + closing_trades: Optional[List[DailyOpenCloseCryptoTrade]] = None + + @staticmethod + def from_dict(d): + return DailyOpenCloseCrypto( + symbol=d.get("symbol", None), + is_utc=d.get("isUTC", None), + day=d.get("day", None), + open=d.get("open", None), + close=d.get("close", None), + open_trades=( + None + if "openTrades" not in d + else [DailyOpenCloseCryptoTrade.from_dict(t) for t in d["openTrades"]] + ), + closing_trades=( + None + if "closingTrades" not in d + else [ + DailyOpenCloseCryptoTrade.from_dict(t) for t in d["closingTrades"] + ] + ), + ) + + @modelclass class PreviousCloseAgg: "Contains data for the previous day's open, high, low, and close (OHLC) of the specified stock ticker." diff --git a/test_rest/mocks/v1/open-close/crypto/BTC/USD/2020-10-09&adjusted=true.json b/test_rest/mocks/v1/open-close/crypto/BTC/USD/2020-10-09&adjusted=true.json new file mode 100644 index 00000000..b3338177 --- /dev/null +++ b/test_rest/mocks/v1/open-close/crypto/BTC/USD/2020-10-09&adjusted=true.json @@ -0,0 +1,51 @@ +{ + "symbol": "BTC-USD", + "isUTC": true, + "day": "2020-10-09T00:00:00.000Z", + "open": 10932.44, + "close": 11050.64, + "openTrades": [ + { + "s": 0.002, + "p": 10932.44, + "x": 1, + "t": 1602201600056, + "c": [ + 2 + ], + "i": "511235746" + }, + { + "s": 0.02, + "p": 10923.76, + "x": 4, + "t": 1602201600141, + "c": [ + 2 + ], + "i": "511235751" + } + ], + "closingTrades": [ + { + "s": 0.006128, + "p": 11050.64, + "x": 4, + "t": 1602287999795, + "c": [ + 2 + ], + "i": "973323250" + }, + { + "s": 0.014, + "p": 11049.4, + "x": 17, + "t": 1602287999659, + "c": [ + 1 + ], + "i": "105717893" + } + ] +} diff --git a/test_rest/test_aggs.py b/test_rest/test_aggs.py index 850a00da..cff53ee1 100644 --- a/test_rest/test_aggs.py +++ b/test_rest/test_aggs.py @@ -3,6 +3,8 @@ Agg, GroupedDailyAgg, DailyOpenCloseAgg, + DailyOpenCloseCrypto, + DailyOpenCloseCryptoTrade, PreviousCloseAgg, ) @@ -96,6 +98,56 @@ def test_get_daily_open_close_agg(self): self.assertEqual(aggs, expected) + def test_get_daily_open_close_crypto(self): + aggs = self.c.get_daily_open_close_crypto( + "BTC", "USD", "2020-10-09", adjusted=True + ) + expected = DailyOpenCloseCrypto( + symbol="BTC-USD", + is_utc=True, + day="2020-10-09T00:00:00.000Z", + open=10932.44, + close=11050.64, + open_trades=[ + DailyOpenCloseCryptoTrade( + conditions=[2], + id="511235746", + price=10932.44, + size=0.002, + timestamp=1602201600056, + exchange=1, + ), + DailyOpenCloseCryptoTrade( + conditions=[2], + id="511235751", + price=10923.76, + size=0.02, + timestamp=1602201600141, + exchange=4, + ), + ], + closing_trades=[ + DailyOpenCloseCryptoTrade( + conditions=[2], + id="973323250", + price=11050.64, + size=0.006128, + timestamp=1602287999795, + exchange=4, + ), + DailyOpenCloseCryptoTrade( + conditions=[1], + id="105717893", + price=11049.4, + size=0.014, + timestamp=1602287999659, + exchange=17, + ), + ], + ) + + self.assertEqual(aggs, expected) + def test_get_previous_close_agg(self): aggs = self.c.get_previous_close_agg("AAPL") expected = [ From 1f2d9879b7e653c09b3ecfa9004f0cf8705e3de7 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:06:35 -0600 Subject: [PATCH 14/22] fix: keep pending WebSocket subscriptions across a reconnect subscribe() and unsubscribe() only change scheduled_subs, the topics the caller wants. The receive loop sends the change on its next turn, up to a second later, and then copies scheduled_subs into subs, the topics the connection has been sent. When the connection closed with an error, connect() set scheduled_subs back to subs before reconnecting. That line came with "resub on reconnect" (#207), and it does resubscribe the topics that were sent. But a change made in the second before the drop had not been sent yet, so it was thrown away: a topic subscribed just before the drop was missing on the new connection, and a topic unsubscribed came back. Keep scheduled_subs and only reset subs, so the new connection subscribes to every topic the caller wants. connect() also kept subs from an earlier call. Calling it again after it returned, for example after the server closed the connection cleanly, sent no subscribe message at all, because every topic looked sent already. Reset subs at the start of every connect() call. This is one way to end up with the missing subscriptions reported in #800. The mock server now records the messages each connection receives, and fails the connection on a DROP.X subscription. The shared test setup waits for the server to start, as test_status did. --- massive/websocket/__init__.py | 6 ++++- test_websocket/base_ws.py | 28 +++++++++++++++++++- test_websocket/mock_server.py | 14 +++++++++- test_websocket/test_reconnect.py | 45 ++++++++++++++++++++++++++++++++ test_websocket/test_status.py | 20 -------------- 5 files changed, 90 insertions(+), 23 deletions(-) create mode 100644 test_websocket/test_reconnect.py diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 7463b4cb..0f2d9610 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -103,6 +103,9 @@ async def connect( :param close_timeout: How long to wait for handshake when calling .close. :raises AuthError: If invalid API key is supplied. """ + # a new connection has no subscriptions, whatever an earlier call left + self.subs = set() + self.schedule_resub = True reconnects = 0 logger.debug("connect: %s", self.url) ssl_context = self._ssl_context() @@ -175,7 +178,8 @@ async def connect( logger.debug("connection closed (ERR): %s", e) self._flush_server_errors(force=True) reconnects += 1 - self.scheduled_subs = set(self.subs) + # keep scheduled_subs, which may hold changes not sent yet, + # and subscribe to all of it on the next connection self.subs = set() self.schedule_resub = True if self.max_reconnects is not None and reconnects > self.max_reconnects: diff --git a/test_websocket/base_ws.py b/test_websocket/base_ws.py index a21bc4d8..54f74319 100644 --- a/test_websocket/base_ws.py +++ b/test_websocket/base_ws.py @@ -1,8 +1,9 @@ import unittest import asyncio -from mock_server import run_mock_server +from mock_server import run_mock_server, inbox, port from typing import List from massive.websocket import WebSocketMessage +from websockets.asyncio.client import connect unittest.util._MAX_LENGTH = 30000 # type: ignore @@ -23,6 +24,31 @@ async def asyncSetUp(self): self.maxDiff = None loop = asyncio.get_event_loop() self.task = loop.create_task(run_mock_server()) + inbox.clear() # entries left by earlier tests + # wait until the mock server is accepting connections + for _ in range(100): + try: + async with connect(f"ws://localhost:{port}"): + break + except OSError: + await asyncio.sleep(0.05) + else: + self.fail("mock server did not start") + await self.until(lambda: inbox) # the connection above + inbox.clear() async def asyncTearDown(self): + # wait for the server to shut down so the next test can bind the port self.task.cancel() + try: + await self.task + except asyncio.CancelledError: + pass + + async def until(self, condition): + # wait for condition() to hold, checking every 10 ms for up to 5 s + for _ in range(500): + if condition(): + return + await asyncio.sleep(0.01) + self.fail("timed out") diff --git a/test_websocket/mock_server.py b/test_websocket/mock_server.py index a3e4b294..db00e84a 100644 --- a/test_websocket/mock_server.py +++ b/test_websocket/mock_server.py @@ -1,18 +1,23 @@ from websockets import serve # type: ignore import asyncio import json -from typing import Set +from typing import Any, List, Set port = 8765 subs: Set[str] = set() +# the messages each connection received, in order; one list per connection +inbox: List[List[Any]] = [] async def mock_server(websocket): + received: List[Any] = [] + inbox.append(received) await websocket.send( '[{"ev":"status","status":"connected","message":"Connected Successfully"}]' ) async for message in websocket: message = json.loads(message) + received.append(message) if "action" not in message: continue if message["action"] == "auth" and message["params"] == "MAX-CONNECTIONS": @@ -35,6 +40,13 @@ async def mock_server(websocket): await websocket.close(code=1000) return for p in message["params"].split(","): + if p == "DROP.X": + # emulate the connection failing, right after a trade + await websocket.send( + '[{"ev":"T","sym":"X","i":"1","x":1,"p":1,"s":1,"t":1,"q":1}]' + ) + await websocket.close(code=1011) + return if p.startswith("ERR."): # emulate the server rejecting a subscription await websocket.send( diff --git a/test_websocket/test_reconnect.py b/test_websocket/test_reconnect.py new file mode 100644 index 00000000..f7299c0a --- /dev/null +++ b/test_websocket/test_reconnect.py @@ -0,0 +1,45 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +import asyncio + + +def sent(conn, action): + # the topics in each `action` message one connection received + return [set(m["params"].split(",")) for m in conn if m.get("action") == action] + + +class ReconnectTest(BaseTest): + async def test_changes_made_before_a_drop_are_kept(self): + c = WebSocketClient( + api_key="", + feed=f"localhost:{port}", + secure=False, + subscriptions=["T.AAPL", "T.MSFT", "DROP.X"], + ) + + async def processor(msgs): + if len(inbox) == 1: + # DROP.X makes the server drop the connection; change the + # subscriptions before the client sends anything else + await c.websocket.wait_closed() + c.unsubscribe("T.MSFT", "DROP.X") + c.subscribe("T.NVDA") + + task = asyncio.create_task(c.connect(processor)) + await self.until(lambda: len(inbox) == 2 and sent(inbox[1], "subscribe")) + self.assertEqual(sent(inbox[1], "subscribe"), [{"T.AAPL", "T.NVDA"}]) + await c.close() + await task + + async def test_connect_again_subscribes_again(self): + # SLOW.X makes the server close the connection, so connect() returns + c = WebSocketClient( + api_key="", feed=f"localhost:{port}", secure=False, subscriptions=["SLOW.X"] + ) + with self.assertLogs("WebSocketClient", level="WARNING"): + for _ in range(2): + await asyncio.wait_for(c.connect(lambda msgs: asyncio.sleep(0)), 5) + self.assertEqual( + [sent(conn, "subscribe") for conn in inbox], [[{"SLOW.X"}], [{"SLOW.X"}]] + ) diff --git a/test_websocket/test_status.py b/test_websocket/test_status.py index d333c9c8..f9ef275e 100644 --- a/test_websocket/test_status.py +++ b/test_websocket/test_status.py @@ -2,30 +2,10 @@ from massive.websocket import logger from base_ws import BaseTest from mock_server import port -from websockets.asyncio.client import connect import asyncio class StatusTest(BaseTest): - async def asyncSetUp(self): - await super().asyncSetUp() - # wait until the mock server is accepting connections - for _ in range(100): - try: - async with connect(f"ws://localhost:{port}"): - return - except OSError: - await asyncio.sleep(0.05) - self.fail("mock server did not start") - - async def asyncTearDown(self): - # wait for the server to shut down so the next test can bind the port - self.task.cancel() - try: - await self.task - except asyncio.CancelledError: - pass - async def run_client(self, *subscriptions): c = WebSocketClient(api_key="", feed=f"localhost:{port}", secure=False) c.subscribe(*subscriptions) From 90a5fb675c20cc959db4456004cee2ba074d48c0 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:27:52 -0600 Subject: [PATCH 15/22] fix: make WebSocket subscribe and unsubscribe thread-safe subscribe(), unsubscribe() and unsubscribe_all() are called while connect() runs, often from another thread, but they changed scheduled_subs and schedule_resub with no lock. The receive loop read scheduled_subs, awaited the subscribe and unsubscribe sends, and then copied scheduled_subs into subs and cleared schedule_resub. A change made during either await was copied into subs without being sent, and its schedule_resub was cleared, so it was never sent. The server then streamed different topics from the ones requested, while subs said everything was sent. Guard both attributes with a lock, which the three methods take for their whole body. The receive loop now copies scheduled_subs and clears schedule_resub under the lock, sends the difference from that copy, and records the copy in subs. A change made during the sends sets schedule_resub again and goes out on the next turn. Code that changes scheduled_subs itself and sets schedule_resub keeps working: the loop still checks the flag on every turn. --- massive/websocket/__init__.py | 46 +++++++++++++++++++++++++--------- test_websocket/test_threads.py | 38 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 test_websocket/test_threads.py diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 0f2d9610..3bf043be 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -1,11 +1,13 @@ import os from collections import Counter from enum import Enum -from typing import Optional, Union, List, Set, Callable, Awaitable, Any +from typing import Optional, Union, List, Set, Callable, Awaitable, Any, TypeVar, cast import logging import json +import functools import asyncio import ssl +import threading import time from .models import * from websockets.asyncio.client import connect, ClientConnection @@ -22,6 +24,19 @@ # "max_connections", "slow_consumer", "force_disconnect") is logged as a warning. OK_STATUSES = {"connected", "auth_success", "success"} +_F = TypeVar("_F", bound=Callable[..., Any]) + + +def _changes_subscriptions(method: _F) -> _F: + # runs a WebSocketClient method that changes scheduled_subs under the + # client's lock, so it is safe to call from any thread + @functools.wraps(method) + def wrapper(self, *args, **kwargs): + with self._subs_lock: + return method(self, *args, **kwargs) + + return cast(_F, wrapper) + class WebSocketClient: def __init__( @@ -78,6 +93,10 @@ def __init__( subscriptions = [] self.scheduled_subs: Set[str] = set(subscriptions) self.schedule_resub = True + # guards scheduled_subs and schedule_resub, which subscribe(), + # unsubscribe() and unsubscribe_all() change on the caller's thread + # while connect() reads them + self._subs_lock = threading.Lock() self._server_errors: Counter = Counter() self._server_errors_since = 0.0 self.ca_certs = ca_certs @@ -137,16 +156,16 @@ async def connect( self._flush_server_errors(force=True) while True: if self.schedule_resub: - logger.debug( - "reconciling: %s %s", self.subs, self.scheduled_subs - ) - new_subs = self.scheduled_subs.difference(self.subs) + # a change made from here on sets schedule_resub again + with self._subs_lock: + desired = set(self.scheduled_subs) + self.schedule_resub = False + logger.debug("reconciling: %s %s", self.subs, desired) + new_subs = desired.difference(self.subs) await self._subscribe(new_subs) - old_subs = self.subs.difference(self.scheduled_subs) + old_subs = self.subs.difference(desired) await self._unsubscribe(old_subs) - self.subs = self.scheduled_subs - self.subs = set(self.scheduled_subs) - self.schedule_resub = False + self.subs = desired try: cmsg: Union[List[WebSocketMessage], Union[str, bytes]] = ( @@ -274,9 +293,10 @@ def _parse_subscription(s: str): return split + @_changes_subscriptions def subscribe(self, *subscriptions: str): """ - Subscribe to given subscriptions. + Subscribe to given subscriptions. Safe to call from any thread. :param subscriptions: Subscriptions (args) """ @@ -294,9 +314,10 @@ def subscribe(self, *subscriptions: str): self.schedule_resub = True + @_changes_subscriptions def unsubscribe(self, *subscriptions: str): """ - Unsubscribe from given subscriptions. + Unsubscribe from given subscriptions. Safe to call from any thread. :param subscriptions: Subscriptions (args) """ @@ -315,9 +336,10 @@ def unsubscribe(self, *subscriptions: str): self.schedule_resub = True + @_changes_subscriptions def unsubscribe_all(self): """ - Unsubscribe from all subscriptions. + Unsubscribe from all subscriptions. Safe to call from any thread. """ self.scheduled_subs = set() self.schedule_resub = True diff --git a/test_websocket/test_threads.py b/test_websocket/test_threads.py new file mode 100644 index 00000000..0f3bc215 --- /dev/null +++ b/test_websocket/test_threads.py @@ -0,0 +1,38 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +import asyncio + + +def streamed(conn): + # the topics one connection was asked to stream + topics = set() + for m in conn: + if m.get("action") == "subscribe": + topics |= set(m["params"].split(",")) + elif m.get("action") == "unsubscribe": + topics -= set(m["params"].split(",")) + return topics + + +class ThreadTest(BaseTest): + async def test_change_made_while_sending_is_sent(self): + c = WebSocketClient( + api_key="", feed=f"localhost:{port}", secure=False, subscriptions=["T.AAPL"] + ) + send = c._subscribe + changed = False + + async def send_and_change(topics): + nonlocal changed + await send(topics) + if not changed: + changed = True + # another thread's change, made while the loop is sending + c.subscribe("T.LATE") + + c._subscribe = send_and_change + task = asyncio.create_task(c.connect(lambda msgs: asyncio.sleep(0))) + await self.until(lambda: inbox and "T.LATE" in streamed(inbox[0])) + await c.close() + await task From 0c0a16c7220ae5cce9b2a00ced84b90ef5afcc07 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:16:21 -0600 Subject: [PATCH 16/22] feat: send WebSocket subscription changes without waiting for recv connect() sent subscription changes only when its receive loop came round again, after the next message or the one-second recv timeout. On a quiet feed, a subscribe() took up to a second to reach the server. Each connection now has one task that sends subscription changes. It starts after authentication by sending the whole scheduled set, then waits on an asyncio.Event. subscribe(), unsubscribe() and unsubscribe_all() set the event through call_soon_threadsafe(), which never blocks the caller. Being the only sender, the task never interleaves messages, and it merges a burst of changes into one subscribe and one unsubscribe message. The receive loop still checks schedule_resub on every turn, now to wake the task, so code that changes scheduled_subs itself and sets the flag keeps working. An error other than a closed connection ends the task and is raised by connect(), as before. The task is stopped when the connection ends. The receive path is otherwise unchanged. Sending while another coroutine waits in recv() on the same connection is safe in websockets 14.0 through 17.3, the current release (websockets/asyncio/connection.py). recv() only reads from the message assembler (14.0 L270, 14.2 L294, 15.0.1 L303, 16.1.1 L305, 17.3 L298), whose only concurrency check rejects a second concurrent reader (asyncio/messages.py, Assembler.get: 14.0 L142, 14.2 L141, 15.0.1 L150, 16.1.1 L149, 17.3 L148). send() waits only for a fragmented send in progress (fragmented_send_waiter, named send_in_progress in 16.1.1 and 17.3: 14.0 L427, 14.2 L451, 15.0.1 L469, 16.1.1 L472, 17.3 L466) before writing through send_context() (14.0 L434, 14.2 L458, 15.0.1 L476, 16.1.1 L479, 17.3 L473). --- massive/websocket/__init__.py | 149 ++++++++++++++++++++++++++-------- test_websocket/test_sender.py | 61 ++++++++++++++ 2 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 test_websocket/test_sender.py diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 3bf043be..eea7a70c 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -1,7 +1,18 @@ import os from collections import Counter from enum import Enum -from typing import Optional, Union, List, Set, Callable, Awaitable, Any, TypeVar, cast +from typing import ( + Optional, + Union, + List, + Set, + Callable, + Awaitable, + Any, + Tuple, + TypeVar, + cast, +) import logging import json import functools @@ -29,11 +40,14 @@ def _changes_subscriptions(method: _F) -> _F: # runs a WebSocketClient method that changes scheduled_subs under the - # client's lock, so it is safe to call from any thread + # client's lock, so it is safe to call from any thread, then wakes the + # task that sends the change @functools.wraps(method) def wrapper(self, *args, **kwargs): with self._subs_lock: - return method(self, *args, **kwargs) + result = method(self, *args, **kwargs) + self._notify() + return result return cast(_F, wrapper) @@ -97,6 +111,9 @@ def __init__( # unsubscribe() and unsubscribe_all() change on the caller's thread # while connect() reads them self._subs_lock = threading.Lock() + # while a connection is open: its loop, and the event that wakes its + # sender task (see _start_sender) + self._wake: Optional[Tuple[asyncio.AbstractEventLoop, asyncio.Event]] = None self._server_errors: Counter = Counter() self._server_errors_since = 0.0 self.ca_certs = ca_certs @@ -154,39 +171,39 @@ async def connect( # e.g. max_connections, which the server sends before closing self._log_server_statuses(auth_msg_parsed) self._flush_server_errors(force=True) - while True: - if self.schedule_resub: - # a change made from here on sets schedule_resub again - with self._subs_lock: - desired = set(self.scheduled_subs) - self.schedule_resub = False - logger.debug("reconciling: %s %s", self.subs, desired) - new_subs = desired.difference(self.subs) - await self._subscribe(new_subs) - old_subs = self.subs.difference(desired) - await self._unsubscribe(old_subs) - self.subs = desired - - try: - cmsg: Union[List[WebSocketMessage], Union[str, bytes]] = ( - await asyncio.wait_for(s.recv(), timeout=1) - ) - except asyncio.TimeoutError: + # subscription changes go out from a task of their own, + # starting with the whole scheduled set + sender, wake = self._start_sender() + try: + while True: + if sender.done(): + self._check_sender(sender) + if self.schedule_resub: + # e.g. set by code that changed scheduled_subs itself + wake.set() + + try: + cmsg: Union[List[WebSocketMessage], Union[str, bytes]] = ( + await asyncio.wait_for(s.recv(), timeout=1) + ) + except asyncio.TimeoutError: + self._flush_server_errors() + continue + + if not self.raw: + # we know cmsg is Data + msgJson = self.json.loads(cmsg) # type: ignore + for m in msgJson: + if m["ev"] == "status": + logger.debug("status: %s", m["message"]) + self._log_server_statuses(msgJson) + cmsg = parse(msgJson, logger, self.market) self._flush_server_errors() - continue - - if not self.raw: - # we know cmsg is Data - msgJson = self.json.loads(cmsg) # type: ignore - for m in msgJson: - if m["ev"] == "status": - logger.debug("status: %s", m["message"]) - self._log_server_statuses(msgJson) - cmsg = parse(msgJson, logger, self.market) - self._flush_server_errors() - - if len(cmsg) > 0: - await processor(cmsg) # type: ignore + + if len(cmsg) > 0: + await processor(cmsg) # type: ignore + finally: + await self._stop_sender(sender) except ConnectionClosedOK as e: logger.debug("connection closed (OK): %s", e) # the server sends a status (e.g. slow_consumer) before closing @@ -283,6 +300,68 @@ async def _unsubscribe(self, topics: Union[List[str], Set[str]]): self.json.dumps({"action": "unsubscribe", "params": subs}) ) + def _start_sender(self) -> Tuple["asyncio.Task[None]", asyncio.Event]: + """Start the task that sends subscription changes; see _notify.""" + wake = asyncio.Event() + wake.set() # first, the whole scheduled set + self._wake = (asyncio.get_running_loop(), wake) + return asyncio.ensure_future(self._send_changes(wake)), wake + + async def _send_changes(self, wake: asyncio.Event): + # The only sender of subscription messages, so messages for two + # changes never interleave. Sending while connect() waits in recv() is + # safe: in websockets, only two concurrent recv() calls conflict. + while True: + await wake.wait() + wake.clear() + await self._reconcile() + + def _check_sender(self, sender: "asyncio.Task[None]"): + # raise what ended the sender, unless the connection closed: then + # recv() raises too, once the messages already received are read + if sender.cancelled(): + return + exc = sender.exception() + if exc is not None and not isinstance( + exc, (ConnectionClosedOK, ConnectionClosedError) + ): + raise exc + + async def _stop_sender(self, sender: "asyncio.Task[None]"): + self._wake = None + sender.cancel() + await asyncio.wait({sender}) # does not raise + self._check_sender(sender) + + def _notify(self): + """Wake the sender, if a connection is open. Safe from any thread.""" + waker = self._wake + if waker is None: + return + loop, wake = waker + try: + loop.call_soon_threadsafe(wake.set) + except RuntimeError: + pass # the loop is closed + + async def _reconcile(self): + """Send the changes that move the server from subs to scheduled_subs.""" + with self._subs_lock: + if not self.schedule_resub: + return + desired = set(self.scheduled_subs) + self.schedule_resub = False + logger.debug("reconciling: %s %s", self.subs, desired) + try: + await self._subscribe(desired.difference(self.subs)) + await self._unsubscribe(self.subs.difference(desired)) + except BaseException: + # e.g. the connection closed: send it all on the next connection + with self._subs_lock: + self.schedule_resub = True + raise + self.subs = desired + @staticmethod def _parse_subscription(s: str): s = s.strip() diff --git a/test_websocket/test_sender.py b/test_websocket/test_sender.py new file mode 100644 index 00000000..71cb2898 --- /dev/null +++ b/test_websocket/test_sender.py @@ -0,0 +1,61 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +from unittest import mock +import asyncio + + +class NoRecvTimeout: + # asyncio, except that connect() waits in recv() until a message arrives + def __getattr__(self, name): + return getattr(asyncio, name) + + @staticmethod + def wait_for(aw, timeout): + return asyncio.wait_for(aw, None) + + +def sent(conn, action): + # the topics in each `action` message one connection received + return [set(m["params"].split(",")) for m in conn if m.get("action") == action] + + +class SenderTest(BaseTest): + async def connected(self, *subscriptions): + # a client whose receive loop has handled every message so far + c = WebSocketClient( + api_key="", + feed=f"localhost:{port}", + secure=False, + subscriptions=list(subscriptions), + ) + received = [] + + async def processor(msgs): + received.append(msgs) + + task = asyncio.create_task(c.connect(processor)) + # each subscribed topic gets two trade messages + await self.until(lambda: len(received) == 2 * len(subscriptions)) + return c, task + + async def test_change_is_sent_while_waiting_for_a_message(self): + with mock.patch("massive.websocket.asyncio", NoRecvTimeout()): + c, task = await self.connected("T.AAPL") + await asyncio.to_thread(c.subscribe, "T.MSFT") + await self.until(lambda: len(sent(inbox[0], "subscribe")) == 2) + await asyncio.to_thread(c.unsubscribe, "T.AAPL") + await self.until(lambda: sent(inbox[0], "unsubscribe")) + self.assertEqual(sent(inbox[0], "subscribe"), [{"T.AAPL"}, {"T.MSFT"}]) + self.assertEqual(sent(inbox[0], "unsubscribe"), [{"T.AAPL"}]) + await c.close() + await task + + async def test_scheduled_subs_can_still_be_changed_directly(self): + c, task = await self.connected("T.AAPL") + c.scheduled_subs.add("T.MSFT") + c.schedule_resub = True + await self.until(lambda: len(sent(inbox[0], "subscribe")) == 2) + self.assertEqual(sent(inbox[0], "subscribe")[1], {"T.MSFT"}) + await c.close() + await task From 6c8a38d0e27f90815d220901e369f92cc50ac97b Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:18:01 -0600 Subject: [PATCH 17/22] feat: add WebSocketClient.set_subscriptions() and resubscribe() Two things a long-running client needs were not possible: - Replacing one set of topics with another, removals first. The server enforces a per-connection subscription limit (it answers "Subscription limit reached for feed", which the client logs since #1039). The client always sends the subscribe message before the unsubscribe message, so a swap made at the limit asks for more topics than the limit allows before the unsubscribe arrives. - Sending a subscribe message again for a topic the server never acknowledged. subscribe() sends only topics missing from subs, so a topic already sent can never be sent twice. set_subscriptions(desired) replaces the scheduled topics in one step. The next update then sends one unsubscribe message for the removed topics, followed by one subscribe message for the added ones. resubscribe(*topics) adds topics to the next subscribe message. A topic that is neither subscribed nor scheduled raises ValueError, and then nothing is sent. subscribe(), unsubscribe() and unsubscribe_all() keep their order: subscribe first, then unsubscribe. --- docs/source/WebSocket.rst | 10 ++++ massive/websocket/__init__.py | 58 +++++++++++++++++++++++- test_websocket/test_set_subscriptions.py | 55 ++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 test_websocket/test_set_subscriptions.py diff --git a/docs/source/WebSocket.rst b/docs/source/WebSocket.rst index c624d9d2..f557525b 100644 --- a/docs/source/WebSocket.rst +++ b/docs/source/WebSocket.rst @@ -34,6 +34,16 @@ Unsubscribe ============================ .. automethod:: massive.WebSocketClient.unsubscribe +============================ +Set subscriptions +============================ +.. automethod:: massive.WebSocketClient.set_subscriptions + +============================ +Resubscribe +============================ +.. automethod:: massive.WebSocketClient.resubscribe + ============================ Close ============================ diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index eea7a70c..dadd68e0 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -12,6 +12,7 @@ Tuple, TypeVar, cast, + Iterable, ) import logging import json @@ -111,6 +112,11 @@ def __init__( # unsubscribe() and unsubscribe_all() change on the caller's thread # while connect() reads them self._subs_lock = threading.Lock() + # set_subscriptions() was called since the last update was sent, so + # send removals first; guarded by _subs_lock + self._removals_first = False + # topics resubscribe() asked to send again; guarded by _subs_lock + self._resend: Set[str] = set() # while a connection is open: its loop, and the event that wakes its # sender task (see _start_sender) self._wake: Optional[Tuple[asyncio.AbstractEventLoop, asyncio.Event]] = None @@ -350,11 +356,19 @@ async def _reconcile(self): if not self.schedule_resub: return desired = set(self.scheduled_subs) + removals_first, self._removals_first = self._removals_first, False + resend, self._resend = self._resend, set() self.schedule_resub = False logger.debug("reconciling: %s %s", self.subs, desired) + added = desired.difference(self.subs) | resend.intersection(desired) + removed = self.subs.difference(desired) try: - await self._subscribe(desired.difference(self.subs)) - await self._unsubscribe(self.subs.difference(desired)) + if removals_first: + await self._unsubscribe(removed) + await self._subscribe(added) + else: + await self._subscribe(added) + await self._unsubscribe(removed) except BaseException: # e.g. the connection closed: send it all on the next connection with self._subs_lock: @@ -423,6 +437,46 @@ def unsubscribe_all(self): self.scheduled_subs = set() self.schedule_resub = True + @_changes_subscriptions + def set_subscriptions(self, desired: Iterable[str]): + """ + Replace all subscriptions with ``desired``, in one step. Safe to call + from any thread. + + The client sends one unsubscribe message for the topics no longer + desired, then one subscribe message for the new ones, together with + any changes from ``subscribe()`` or ``unsubscribe()`` not sent yet. + Removals go first, so a client at the server's subscription limit + can swap topics; data that a removed and an added topic both cover + (e.g. ``T.AAPL`` replaced by ``T.*``) is not delivered in between. + Wildcards such as ``T.*`` are ordinary topics here. + + :param desired: Every topic to be subscribed to afterwards. Malformed + topics are logged and skipped. + """ + topics = {s for s in desired if self._parse_subscription(s)[0] is not None} + self.scheduled_subs = topics + self._removals_first = True + self.schedule_resub = True + + @_changes_subscriptions + def resubscribe(self, *topics: str): + """ + Send a subscribe message again for topics already subscribed, e.g. + ones the server never acknowledged. Safe to call from any thread. + + :param topics: Topics to send again (args). Malformed topics are + logged and skipped. + :raises ValueError: If a topic is not subscribed or scheduled to be; + nothing is sent then. + """ + again = {s for s in topics if self._parse_subscription(s)[0] is not None} + unknown = again.difference(self.scheduled_subs) + if unknown: + raise ValueError(f"not subscribed: {sorted(unknown)}") + self._resend |= again + self.schedule_resub = True + async def close(self): """ Close the websocket connection. diff --git a/test_websocket/test_set_subscriptions.py b/test_websocket/test_set_subscriptions.py new file mode 100644 index 00000000..3d4cbc21 --- /dev/null +++ b/test_websocket/test_set_subscriptions.py @@ -0,0 +1,55 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +import asyncio + + +def sent(conn): + # the subscribe and unsubscribe messages one connection received + return [ + (m["action"], set(m["params"].split(","))) + for m in conn + if m.get("action") in ("subscribe", "unsubscribe") + ] + + +class SetSubscriptionsTest(BaseTest): + async def connected(self, *subscriptions): + c = WebSocketClient( + api_key="", + feed=f"localhost:{port}", + secure=False, + subscriptions=list(subscriptions), + ) + task = asyncio.create_task(c.connect(lambda msgs: asyncio.sleep(0))) + await self.until(lambda: inbox and sent(inbox[0])) + return c, task + + async def test_set_subscriptions_sends_removals_first(self): + c, task = await self.connected("T.AAPL", "T.MSFT") + c.set_subscriptions(["T.AAPL", "T.NVDA"]) + await self.until(lambda: len(sent(inbox[0])) == 3) + self.assertEqual( + sent(inbox[0])[1:], + [("unsubscribe", {"T.MSFT"}), ("subscribe", {"T.NVDA"})], + ) + await c.close() + await task + + async def test_resubscribe_sends_again(self): + c, task = await self.connected("T.AAPL") + c.resubscribe("T.AAPL") + await self.until(lambda: len(sent(inbox[0])) == 2) + self.assertEqual(sent(inbox[0])[1], ("subscribe", {"T.AAPL"})) + await c.close() + await task + + async def test_resubscribe_unknown_topic_sends_nothing(self): + c, task = await self.connected("T.AAPL") + with self.assertRaises(ValueError): + c.resubscribe("T.AAPL", "T.MSFT") + c.subscribe("T.NVDA") + await self.until(lambda: len(sent(inbox[0])) == 2) + self.assertEqual(sent(inbox[0])[1], ("subscribe", {"T.NVDA"})) + await c.close() + await task From 217eec50b6b5b17e49332edefee1b7e2a379988c Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:22:08 -0600 Subject: [PATCH 18/22] feat: add opt-in WebSocket reconnect options connect() reconnects at once after a dropped connection, returns when the server closes the connection normally, retries a handshake error such as HTTP 404 forever, and counts every disconnect over the client's lifetime toward max_reconnects. A caller cannot change any of this. Add keyword arguments to WebSocketClient. Each defaults to today's behavior: - reconnect_backoff, max_reconnect_backoff: wait before reconnecting after an open connection closes. The wait doubles with each failure in a row, up to the cap, plus up to 20% jitter; at the cap it is drawn from [cap / 1.2, cap], never below reconnect_backoff. The constructor raises ValueError if reconnect_backoff is negative or greater than max_reconnect_backoff. - reconnect_on_close: also reconnect when the server closes normally. A close() by the caller while connected still ends connect(). - max_consecutive_failures, stable_uptime: limit failures in a row. A failure is an attempt that fails, or a connection that closes before it has been open for stable_uptime seconds. max_reconnects keeps its meaning. - raise_fatal_errors: use websockets' default process_exception, which raises errors that retrying will not fix. The reconnect loop is still async for ... in websockets' connect(). connect() now also accepts process_exception, which used to raise TypeError because the client passed its own. The new attribute max_connections_reached tells whether the server sent a max_connections status during the last handshake; the processor receives the same messages as before. --- massive/websocket/__init__.py | 112 ++++++++++++++++---- test_websocket/mock_server.py | 8 +- test_websocket/test_reconnect_options.py | 125 +++++++++++++++++++++++ 3 files changed, 225 insertions(+), 20 deletions(-) create mode 100644 test_websocket/test_reconnect_options.py diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 0f2d9610..5d2ebdbe 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -5,10 +5,11 @@ import logging import json import asyncio +import random import ssl import time from .models import * -from websockets.asyncio.client import connect, ClientConnection +from websockets.asyncio.client import connect, ClientConnection, process_exception from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError from ..certs import ca_bundle_path from ..logging import get_logger @@ -36,6 +37,12 @@ def __init__( secure: bool = True, custom_json: Optional[Any] = None, ca_certs: Optional[str] = None, + reconnect_backoff: float = 0.0, + max_reconnect_backoff: float = 120.0, + reconnect_on_close: bool = False, + max_consecutive_failures: Optional[int] = None, + stable_uptime: float = 60.0, + raise_fatal_errors: bool = False, **kwargs, ): """ @@ -49,8 +56,20 @@ def __init__( :param max_reconnects: How many times to reconnect on network outage before ending .connect event loop. :param custom_json: Optional module exposing loads/dumps functions (similar to Python's json module) to be used for JSON conversions. :param ca_certs: Path to a CA bundle to verify TLS with. Defaults to the SSL_CERT_FILE or REQUESTS_CA_BUNDLE environment variable, then certifi. + :param reconnect_backoff: Seconds to wait before reconnecting after an open connection closes. The wait doubles with each consecutive failure, up to max_reconnect_backoff, with random jitter. 0 (the default) reconnects at once. + :param max_reconnect_backoff: The longest wait before reconnecting, in seconds. + :param reconnect_on_close: Also reconnect when the server closes the connection normally (e.g. code 1000), counting toward max_reconnects. By default, .connect returns then. + :param max_consecutive_failures: How many failures in a row .connect allows before it raises the last error. A failure is a connection attempt that fails, or a connection that closes before it has been open for stable_uptime seconds. None (the default) allows any number. max_reconnects applies too. + :param stable_uptime: Seconds a connection must stay open to reset the failure count and the backoff. + :param raise_fatal_errors: Raise connection errors that retrying will not fix, such as an HTTP 404 during the handshake, instead of retrying them forever. Uses websockets' default process_exception. + :raises ValueError: If reconnect_backoff is negative or greater than max_reconnect_backoff. :return: A client. """ + if not 0 <= reconnect_backoff <= max_reconnect_backoff: + raise ValueError( + "need 0 <= reconnect_backoff <= max_reconnect_backoff, got " + f"{reconnect_backoff} and {max_reconnect_backoff}" + ) if api_key is None: raise AuthError( f"Must specify env var {env_key} or pass api_key in constructor" @@ -73,6 +92,15 @@ def __init__( self.subscribed = False self.subs: Set[str] = set() self.max_reconnects = max_reconnects + self.reconnect_backoff = reconnect_backoff + self.max_reconnect_backoff = max_reconnect_backoff + self.reconnect_on_close = reconnect_on_close + self.max_consecutive_failures = max_consecutive_failures + self.stable_uptime = stable_uptime + self.raise_fatal_errors = raise_fatal_errors + # whether the server sent a max_connections status during the last + # handshake: the account has too many connections open + self.max_connections_reached = False self.websocket: Optional[ClientConnection] = None if subscriptions is None: subscriptions = [] @@ -101,28 +129,45 @@ async def connect( :param processor: The callback to process messages. :param close_timeout: How long to wait for handshake when calling .close. + :param kwargs: Passed to websockets' connect(), e.g. process_exception. :raises AuthError: If invalid API key is supplied. """ # a new connection has no subscriptions, whatever an earlier call left self.subs = set() self.schedule_resub = True reconnects = 0 + # failed attempts and short-lived connections in a row + failures = 0 logger.debug("connect: %s", self.url) ssl_context = self._ssl_context() - last_exc = None + retry_or_raise = kwargs.pop( + "process_exception", + process_exception if self.raise_fatal_errors else lambda exc: None, + ) + + def on_connect_error(exc: Exception) -> Optional[Exception]: + nonlocal failures + failures += 1 + if self._too_many(failures, self.max_consecutive_failures): + return exc + return retry_or_raise(exc) + + last_exc: Optional[Exception] = None async for s in connect( self.url, close_timeout=close_timeout, ssl=ssl_context, - process_exception=lambda exc: None, + process_exception=on_connect_error, **kwargs, ): self.websocket = s + connected_at = None try: msg = await s.recv() logger.debug("connected: %s", msg) - self._log_server_statuses(self.json.loads(msg)) + msg_parsed = self.json.loads(msg) + self._log_server_statuses(msg_parsed) logger.debug("authing...") await s.send( self.json.dumps({"action": "auth", "params": self.api_key}) @@ -132,6 +177,11 @@ async def connect( logger.debug("authed: %s", auth_msg) if auth_msg_parsed[0]["status"] == "auth_failed": raise AuthError(auth_msg_parsed[0]["message"]) + self.max_connections_reached = any( + m.get("status") == "max_connections" + for m in msg_parsed + auth_msg_parsed + ) + connected_at = time.monotonic() # e.g. max_connections, which the server sends before closing self._log_server_statuses(auth_msg_parsed) self._flush_server_errors(force=True) @@ -172,27 +222,51 @@ async def connect( logger.debug("connection closed (OK): %s", e) # the server sends a status (e.g. slow_consumer) before closing self._flush_server_errors(force=True) - return + # rcvd_then_sent: the server closed it, rather than close() + if not (self.reconnect_on_close and e.rcvd_then_sent): + return + last_exc = e except ConnectionClosedError as e: last_exc = e logger.debug("connection closed (ERR): %s", e) self._flush_server_errors(force=True) - reconnects += 1 - # keep scheduled_subs, which may hold changes not sent yet, - # and subscribe to all of it on the next connection - self.subs = set() - self.schedule_resub = True - if self.max_reconnects is not None and reconnects > self.max_reconnects: - break - continue - - if ( - last_exc - and self.max_reconnects is not None - and reconnects > self.max_reconnects - ): + reconnects += 1 + # keep scheduled_subs, which may hold changes not sent yet, + # and subscribe to all of it on the next connection + self.subs = set() + self.schedule_resub = True + if ( + connected_at is not None + and time.monotonic() - connected_at >= self.stable_uptime + ): + failures = 0 + else: + failures += 1 + if self._too_many(reconnects, self.max_reconnects) or self._too_many( + failures, self.max_consecutive_failures + ): + break + if self.reconnect_backoff > 0: + delay = self._reconnect_delay(failures) + logger.debug("reconnecting in %.1f s", delay) + await asyncio.sleep(delay) + + if last_exc is not None: raise last_exc + @staticmethod + def _too_many(count: int, limit: Optional[int]) -> bool: + return limit is not None and count > limit + + def _reconnect_delay(self, failures: int) -> float: + # doubles with each failure in a row, up to the cap; jitter adds up + # to 20%, and at the cap draws from [max(base, cap / 1.2), cap] instead + base, cap = self.reconnect_backoff, self.max_reconnect_backoff + delay = min(base * 2.0 ** min(max(failures - 1, 0), 64), cap) + if delay < cap: + return random.uniform(delay, min(delay * 1.2, cap)) + return random.uniform(max(base, cap / 1.2), cap) + def _ssl_context(self) -> Optional[ssl.SSLContext]: # darwin needs some extra <3 if not self.url.startswith("wss://"): diff --git a/test_websocket/mock_server.py b/test_websocket/mock_server.py index db00e84a..882bb4ec 100644 --- a/test_websocket/mock_server.py +++ b/test_websocket/mock_server.py @@ -137,8 +137,14 @@ async def mock_server(websocket): ) +def process_request(connection, request): + if request.path.startswith("/404/"): + # emulate the server refusing the handshake + return connection.respond(404, "Not Found\n") + + async def run_mock_server(): - async with serve(mock_server, "localhost", port): + async with serve(mock_server, "localhost", port, process_request=process_request): await asyncio.Future() # run forever diff --git a/test_websocket/test_reconnect_options.py b/test_websocket/test_reconnect_options.py new file mode 100644 index 00000000..96c03b8b --- /dev/null +++ b/test_websocket/test_reconnect_options.py @@ -0,0 +1,125 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +from unittest import mock +from websockets.exceptions import ( + ConnectionClosedError, + ConnectionClosedOK, + InvalidStatus, +) +import asyncio + + +class RecordSleeps: + # asyncio, except that sleep() records the delay and returns at once + def __init__(self): + self.delays = [] + + def __getattr__(self, name): + return getattr(asyncio, name) + + async def sleep(self, delay): + self.delays.append(delay) + + +async def ignore(msgs): + pass + + +class ReconnectOptionsTest(BaseTest): + def client(self, *subscriptions, **kwargs): + return WebSocketClient( + api_key=kwargs.pop("api_key", ""), + feed=kwargs.pop("feed", f"localhost:{port}"), + secure=False, + subscriptions=list(subscriptions), + **kwargs, + ) + + async def drop_until_raised(self, c, exc=ConnectionClosedError): + # DROP.X makes the server drop every connection right away + sleeps = RecordSleeps() + with mock.patch("massive.websocket.asyncio", sleeps), mock.patch( + "massive.websocket.random" + ) as rnd: + rnd.uniform.side_effect = lambda a, b: a + with self.assertRaises(exc): + await asyncio.wait_for(c.connect(ignore), 5) + return sleeps.delays, rnd.uniform.call_args_list + + async def test_reconnects_at_once_by_default(self): + c = self.client("DROP.X", max_reconnects=2) + delays, _ = await self.drop_until_raised(c) + self.assertEqual(delays, []) + self.assertEqual(len(inbox), 3) + + async def test_backoff_doubles_up_to_the_cap(self): + c = self.client( + "DROP.X", max_reconnects=4, reconnect_backoff=1, max_reconnect_backoff=4 + ) + delays, uniform = await self.drop_until_raised(c) + at_cap = mock.call(4 / 1.2, 4) + self.assertEqual( + uniform, [mock.call(1, 1.2), mock.call(2, 2.4), at_cap, at_cap] + ) + self.assertEqual(delays, [1, 2, 4 / 1.2, 4 / 1.2]) + + async def test_consecutive_failures_are_limited(self): + c = self.client("DROP.X", max_reconnects=None, max_consecutive_failures=2) + await self.drop_until_raised(c) + self.assertEqual(len(inbox), 3) + + async def test_stable_connection_resets_failures(self): + c = self.client( + "DROP.X", max_reconnects=3, max_consecutive_failures=0, stable_uptime=0 + ) + await self.drop_until_raised(c) + self.assertEqual(len(inbox), 4) + + async def test_reconnect_on_close(self): + # SLOW.X makes the server close every connection normally + c = self.client("SLOW.X", max_reconnects=2, reconnect_on_close=True) + with self.assertLogs("WebSocketClient", level="WARNING"): + await self.drop_until_raised(c, ConnectionClosedOK) + self.assertEqual(len(inbox), 3) + + async def test_close_still_returns_with_reconnect_on_close(self): + c = self.client("T.AAPL", reconnect_on_close=True) + task = asyncio.create_task(c.connect(ignore)) + await self.until(lambda: inbox and len(inbox[0]) == 2) + await c.close() + await asyncio.wait_for(task, 5) + self.assertEqual(len(inbox), 1) + + async def test_raise_fatal_errors(self): + c = self.client(feed=f"localhost:{port}/404", raise_fatal_errors=True) + with self.assertRaises(InvalidStatus): + await asyncio.wait_for(c.connect(ignore), 5) + + async def test_handshake_failures_count(self): + c = self.client(feed=f"localhost:{port}/404", max_consecutive_failures=0) + with self.assertRaises(InvalidStatus): + await asyncio.wait_for(c.connect(ignore), 5) + + async def test_process_exception_is_passed_to_websockets(self): + c = self.client(feed=f"localhost:{port}/404") + with self.assertRaises(InvalidStatus): + await asyncio.wait_for( + c.connect(ignore, process_exception=lambda exc: exc), 5 + ) + + async def test_max_connections_reached(self): + processor = mock.AsyncMock() + c = self.client(api_key="MAX-CONNECTIONS", raw=True, max_reconnects=0) + self.assertFalse(c.max_connections_reached) + with self.assertLogs("WebSocketClient", level="WARNING"): + with self.assertRaises(ConnectionClosedError): + await asyncio.wait_for(c.connect(processor), 5) + self.assertTrue(c.max_connections_reached) + processor.assert_not_called() + + async def test_backoff_is_checked(self): + with self.assertRaises(ValueError): + self.client(reconnect_backoff=-1) + with self.assertRaises(ValueError): + self.client(reconnect_backoff=10, max_reconnect_backoff=5) From dbcc501134869a762eaf58aad9dcf4e2be12984d Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:24:22 -0600 Subject: [PATCH 19/22] feat: add WebSocketClient.request_close() close() is a coroutine that must run on connect()'s event loop. run() creates that loop itself, so another thread cannot stop a client started with run(): asyncio.run(client.close()) from another thread fails with "attached to a different loop". request_close() can be called from any thread and does not wait. It sets a flag and, while connect() runs, closes the connection through loop.call_soon_threadsafe(). connect() checks the flag before it reconnects and after a wait before reconnecting, so it returns instead, also with reconnect_on_close. An attempt to connect, or a wait before reconnecting, is not interrupted: connect() returns once it ends, without opening another connection. If connect() is not running, the next call returns at once. close() called while connect() runs now sets the same flag. Before, a close() during the wait before a reconnect (reconnect_backoff > 0) or during a reconnect handshake found no open connection to close, and connect() went on to reconnect. A close() before connect() starts is unchanged: the next connect() proceeds. With the default reconnect_backoff of 0 there is no wait, so the only difference is a close() made during a reconnect handshake. --- docs/source/WebSocket.rst | 5 ++ massive/websocket/__init__.py | 63 ++++++++++++++++++++++- test_websocket/test_request_close.py | 74 ++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 test_websocket/test_request_close.py diff --git a/docs/source/WebSocket.rst b/docs/source/WebSocket.rst index c624d9d2..e4a6b412 100644 --- a/docs/source/WebSocket.rst +++ b/docs/source/WebSocket.rst @@ -39,6 +39,11 @@ Close ============================ .. automethod:: massive.WebSocketClient.close +============================ +Request close +============================ +.. automethod:: massive.WebSocketClient.request_close + .. _Stocks getting started: https://massive.com/docs/stocks/ws_getting-started .. _Options getting started: https://massive.com/docs/options/ws_getting-started .. _Forex getting started: https://massive.com/docs/forex/ws_getting-started diff --git a/massive/websocket/__init__.py b/massive/websocket/__init__.py index 5d2ebdbe..e6703de4 100644 --- a/massive/websocket/__init__.py +++ b/massive/websocket/__init__.py @@ -7,6 +7,7 @@ import asyncio import random import ssl +import threading import time from .models import * from websockets.asyncio.client import connect, ClientConnection, process_exception @@ -113,6 +114,12 @@ def __init__( self.json = custom_json else: self.json = json + # set by request_close(), and by close() while connect() runs; + # connect() returns instead of reconnecting + self._close_requested = threading.Event() + # the event loop connect() runs on, while it runs + self._loop: Optional[asyncio.AbstractEventLoop] = None + self._closing: Optional[asyncio.Future] = None # https://websockets.readthedocs.io/en/stable/reference/client.html#opening-a-connection async def connect( @@ -132,6 +139,24 @@ async def connect( :param kwargs: Passed to websockets' connect(), e.g. process_exception. :raises AuthError: If invalid API key is supplied. """ + self._loop = asyncio.get_running_loop() + try: + await self._connect(processor, close_timeout, **kwargs) + finally: + self._loop = None + self._close_requested.clear() + + async def _connect( + self, + processor: Union[ + Callable[[List[WebSocketMessage]], Awaitable], + Callable[[Union[str, bytes]], Awaitable], + ], + close_timeout: int, + **kwargs, + ): + if self._close_requested.is_set(): + return # a new connection has no subscriptions, whatever an earlier call left self.subs = set() self.schedule_resub = True @@ -161,6 +186,9 @@ def on_connect_error(exc: Exception) -> Optional[Exception]: process_exception=on_connect_error, **kwargs, ): + if self._close_requested.is_set(): + await s.close() # requested while connecting + return self.websocket = s connected_at = None try: @@ -230,6 +258,8 @@ def on_connect_error(exc: Exception) -> Optional[Exception]: last_exc = e logger.debug("connection closed (ERR): %s", e) self._flush_server_errors(force=True) + if self._close_requested.is_set(): + return reconnects += 1 # keep scheduled_subs, which may hold changes not sent yet, # and subscribe to all of it on the next connection @@ -250,6 +280,8 @@ def on_connect_error(exc: Exception) -> Optional[Exception]: delay = self._reconnect_delay(failures) logger.debug("reconnecting in %.1f s", delay) await asyncio.sleep(delay) + if self._close_requested.is_set(): + return # requested during the wait if last_exc is not None: raise last_exc @@ -398,9 +430,13 @@ def unsubscribe_all(self): async def close(self): """ - Close the websocket connection. + Close the websocket connection. If ``connect()`` is running, it + returns instead of reconnecting, also during a wait before + reconnecting. """ logger.debug("closing") + if self._loop is not None: + self._close_requested.set() # connect() clears it when it returns self._flush_server_errors(force=True) if self.websocket: @@ -408,3 +444,28 @@ async def close(self): self.websocket = None else: logger.warning("no websocket open to close") + + def request_close(self): + """ + Close the websocket connection and make ``connect()`` return instead + of reconnecting. Unlike ``close()``, this is safe to call from any + thread, e.g. to stop ``run()``, and it does not wait. + + An attempt to connect, or a wait before reconnecting, is not + interrupted: ``connect()`` returns once it ends. If ``connect()`` is + not running, the next call returns at once. + """ + logger.debug("close requested") + self._close_requested.set() + loop = self._loop + if loop is None: + return + try: + loop.call_soon_threadsafe(self._close_soon) + except RuntimeError: + pass # the loop is closed, so connect() has returned + + def _close_soon(self): + # on connect()'s loop; recv() then raises and connect() returns + if self.websocket is not None: + self._closing = asyncio.ensure_future(self.websocket.close()) diff --git a/test_websocket/test_request_close.py b/test_websocket/test_request_close.py new file mode 100644 index 00000000..9d4cfdf7 --- /dev/null +++ b/test_websocket/test_request_close.py @@ -0,0 +1,74 @@ +from massive import WebSocketClient +from base_ws import BaseTest +from mock_server import inbox, port +import asyncio +import threading +from unittest import mock + + +class StopInSleep: + # asyncio, except that sleep() awaits stop() and returns at once + def __init__(self, stop): + self.stop = stop + + def __getattr__(self, name): + return getattr(asyncio, name) + + async def sleep(self, delay): + await self.stop() + + +class RequestCloseTest(BaseTest): + def client(self, *subscriptions, **kwargs): + return WebSocketClient( + api_key="", + feed=f"localhost:{port}", + secure=False, + subscriptions=list(subscriptions), + **kwargs, + ) + + async def test_stops_run_from_another_thread(self): + c = self.client("T.AAPL", reconnect_on_close=True) + thread = threading.Thread(target=c.run, args=(lambda msgs: None,)) + thread.start() + await self.until(lambda: inbox and len(inbox[0]) == 2) + c.request_close() + await asyncio.to_thread(thread.join, 5) + self.assertFalse(thread.is_alive()) + self.assertEqual(len(inbox), 1) + + async def test_stops_reconnecting(self): + # DROP.X makes the server drop the connection + c = self.client("DROP.X", max_reconnects=None) + + async def processor(msgs): + c.request_close() + + await asyncio.wait_for(c.connect(processor), 5) + self.assertEqual(len(inbox), 1) + + async def test_before_connect(self): + c = self.client("T.AAPL") + c.request_close() + await asyncio.wait_for(c.connect(lambda msgs: asyncio.sleep(0)), 5) + self.assertEqual(inbox, []) + # the request is used up + task = asyncio.create_task(c.connect(lambda msgs: asyncio.sleep(0))) + await self.until(lambda: inbox and len(inbox[0]) == 2) + await c.close() + await task + + async def stop_during_wait(self, stop): + # DROP.X makes the server drop the connection; stop() runs during + # the wait before reconnecting + c = self.client("DROP.X", max_reconnects=None, reconnect_backoff=1) + with mock.patch("massive.websocket.asyncio", StopInSleep(lambda: stop(c))): + await asyncio.wait_for(c.connect(lambda msgs: asyncio.sleep(0)), 5) + self.assertEqual(len(inbox), 1) + + async def test_stops_a_wait_before_reconnecting(self): + await self.stop_during_wait(lambda c: asyncio.to_thread(c.request_close)) + + async def test_close_stops_a_wait_before_reconnecting(self): + await self.stop_during_wait(lambda c: c.close()) From 9b1226d2988d9c9e95ce1dc5c955fe93ab8947e8 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:57:32 -0600 Subject: [PATCH 20/22] feat: add raise_on_status to RESTClient The client retries 413, 429, 499, 500, 502, 503 and 504. When the last retry still gets one of those statuses, urllib3 raises MaxRetryError, so code that catches BadResponse misses rate limits and server errors. Add a raise_on_status argument, passed to the client's Retry. It defaults to True, which keeps today's MaxRetryError. With raise_on_status=False, urllib3 returns the last response and _get raises BadResponse with its status and body. The number of attempts and the backoff do not change. A custom Retry can already be passed through connection_pool_kw, but it replaces the client's status list and backoff, and makes the retries argument a no-op. --- massive/rest/__init__.py | 6 +++ massive/rest/base.py | 3 ++ test_rest/test_bad_response.py | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/massive/rest/__init__.py b/massive/rest/__init__.py index 237ab84c..5fe653a3 100644 --- a/massive/rest/__init__.py +++ b/massive/rest/__init__.py @@ -66,6 +66,7 @@ def __init__( ca_certs: Optional[str] = None, proxy: Optional[str] = None, connection_pool_kw: Optional[Dict[str, Any]] = None, + raise_on_status: bool = True, ): """ :param maxsize: Connections kept open per host, for reuse across threads. @@ -75,6 +76,9 @@ def __init__( Environment proxy variables (HTTPS_PROXY etc.) are not used. :param connection_pool_kw: Other urllib3 PoolManager options. They override the client's defaults. + :param raise_on_status: When a retried status (413, 429, 499, 500, 502, 503, + 504) is still returned after the last retry: if True, urllib3 raises + MaxRetryError; if False, the client raises BadResponse with that status. """ # resolve once, so the main and vx clients share it and warn only once ca_certs = ca_certs or ca_bundle_path(logger) @@ -93,6 +97,7 @@ def __init__( ca_certs=ca_certs, proxy=proxy, connection_pool_kw=connection_pool_kw, + raise_on_status=raise_on_status, ) self.vx = VXClient( api_key=api_key, @@ -109,4 +114,5 @@ def __init__( ca_certs=ca_certs, proxy=proxy, connection_pool_kw=connection_pool_kw, + raise_on_status=raise_on_status, ) diff --git a/massive/rest/base.py b/massive/rest/base.py index 7b728685..859ff824 100644 --- a/massive/rest/base.py +++ b/massive/rest/base.py @@ -38,6 +38,7 @@ def __init__( ca_certs: Optional[str] = None, proxy: Optional[str] = None, connection_pool_kw: Optional[Dict[str, Any]] = None, + raise_on_status: bool = True, ): if api_key is None: raise AuthError( @@ -70,6 +71,8 @@ def __init__( 504, ], # default 413, 429, 503 backoff_factor=0.1, # [0.0s, 0.2s, 0.4s, 0.8s, 1.6s, ...] + # if False, return the last response so that _get raises BadResponse + raise_on_status=raise_on_status, ) # https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Timeout diff --git a/test_rest/test_bad_response.py b/test_rest/test_bad_response.py index 23c86e7b..9bbe79a3 100644 --- a/test_rest/test_bad_response.py +++ b/test_rest/test_bad_response.py @@ -1,3 +1,12 @@ +from http.server import BaseHTTPRequestHandler, HTTPServer +from unittest import mock +import threading +import unittest + +from urllib3.exceptions import MaxRetryError +from urllib3.util.retry import Retry + +from massive import RESTClient from massive.exceptions import BadResponse from base import BaseTest @@ -36,3 +45,67 @@ def test_status_does_not_change_message(self): self.assertEqual(exc.args, ("boom",)) self.assertEqual(str(exc), "boom") self.assertEqual(exc.status, 500) + + +class StatusServer(HTTPServer): + """Answers every GET with a 429 and counts the requests. + + pook replaces urllib3's urlopen, which is where retries happen, so the + raise_on_status tests need a real server. + """ + + def __init__(self): + self.requests = 0 + super().__init__(("127.0.0.1", 0), StatusHandler) + + +class StatusHandler(BaseHTTPRequestHandler): + server: StatusServer + + def do_GET(self): + self.server.requests += 1 + self.send_response(429) + self.send_header("Content-Length", "4") + self.end_headers() + self.wfile.write(b"slow") + + def log_message(self, format, *args): + pass + + +class RaiseOnStatusTest(unittest.TestCase): + def setUp(self): + # if an earlier class left pook on + if pook.isactive(): + pook.disable() + self.addCleanup(pook.activate) + self.server = StatusServer() + threading.Thread( + target=self.server.serve_forever, + kwargs={"poll_interval": 0.01}, + daemon=True, + ).start() + self.addCleanup(self.server.server_close) + self.addCleanup(self.server.shutdown) + + def get_error(self, error, **kwargs): + base = f"http://127.0.0.1:{self.server.server_port}" + c = RESTClient("key", base=base, retries=2, **kwargs) + with mock.patch.object(Retry, "sleep"): # skip the backoff + with self.assertRaises(error) as ctx: + c.get_market_status() + self.assertEqual(self.server.requests, 3) # first attempt + 2 retries + return ctx.exception + + def test_default_raises_max_retry_error(self): + self.get_error(MaxRetryError) + + def test_false_raises_bad_response(self): + exc = self.get_error(BadResponse, raise_on_status=False) + self.assertEqual(exc.status, 429) + self.assertEqual(str(exc), "slow") + + def test_reaches_vx_client(self): + c = RESTClient("key", raise_on_status=False) + for pool in (c.client, c.vx.client): + self.assertFalse(pool.connection_pool_kw["retries"].raise_on_status) From cc5cd77f7b11c41a603bc6996235d6911ab5b699 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 08:53:45 -0600 Subject: [PATCH 21/22] feat: overload REST methods on raw so callers get precise return types Every REST method is annotated as returning Union[Model, HTTPResponse] (or Union[Iterator[Model], HTTPResponse]), because raw=True returns the undecoded urllib3 response. A type checker cannot rule out HTTPResponse, so ordinary code fails: for t in client.list_tickers(): t.ticker # "HTTPResponse" has no attribute "ticker" client.get_aggs("AAPL", 1, "day", "2024-01-02", "2024-01-31")[0] # not indexable Add three overloads to each of the 94 methods that take raw: - raw: Literal[False] = False returns the model type, so the default call is precise. - *, raw: Literal[True] returns HTTPResponse. raw is keyword-only here because it follows parameters with defaults; giving it a default would overlap the first overload, which pyright reports. - raw: bool = False returns the full union, so a non-literal flag, or raw passed positionally, type-checks exactly as before. This commit is mechanical: the overloads were generated from each method's own signature and then formatted with black. They differ from the signature only in raw and the return type. The implementations, and the signatures that _get_params inspects at runtime, are unchanged. --- massive/rest/aggs.py | 225 +++- massive/rest/benzinga.py | 1308 ++++++++++++++++++-- massive/rest/economy.py | 429 ++++++- massive/rest/etf_global.py | 651 +++++++++- massive/rest/financials.py | 946 +++++++++++++- massive/rest/futures.py | 661 +++++++++- massive/rest/indicators.py | 252 +++- massive/rest/quotes.py | 138 ++- massive/rest/reference.py | 2397 +++++++++++++++++++++++++++++++----- massive/rest/snapshot.py | 293 ++++- massive/rest/summaries.py | 27 +- massive/rest/tmx.py | 174 ++- massive/rest/trades.py | 104 +- massive/rest/vX.py | 142 ++- 14 files changed, 7295 insertions(+), 452 deletions(-) diff --git a/massive/rest/aggs.py b/massive/rest/aggs.py index 1afa1f12..7f823e04 100644 --- a/massive/rest/aggs.py +++ b/massive/rest/aggs.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from .models import ( Agg, GroupedDailyAgg, @@ -15,6 +15,52 @@ class AggsClient(BaseClient): + @overload + def list_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Agg]: ... + @overload + def list_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Agg], HTTPResponse]: ... def list_aggs( self, ticker: str, @@ -60,6 +106,52 @@ def list_aggs( options=options, ) + @overload + def get_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[Agg]: ... + @overload + def get_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_aggs( + self, + ticker: str, + multiplier: int, + timespan: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[Agg], HTTPResponse]: ... def get_aggs( self, ticker: str, @@ -106,6 +198,44 @@ def get_aggs( options=options, ) + @overload + def get_grouped_daily_aggs( + self, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + locale: str = "us", + market_type: str = "stocks", + include_otc: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[GroupedDailyAgg]: ... + @overload + def get_grouped_daily_aggs( + self, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + locale: str = "us", + market_type: str = "stocks", + include_otc: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_grouped_daily_aggs( + self, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + locale: str = "us", + market_type: str = "stocks", + include_otc: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[GroupedDailyAgg], HTTPResponse]: ... + # TODO: next breaking change release move "market_type" to be 2nd mandatory # param def get_grouped_daily_aggs( @@ -139,6 +269,37 @@ def get_grouped_daily_aggs( options=options, ) + @overload + def get_daily_open_close_agg( + self, + ticker: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> DailyOpenCloseAgg: ... + @overload + def get_daily_open_close_agg( + self, + ticker: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_daily_open_close_agg( + self, + ticker: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[DailyOpenCloseAgg, HTTPResponse]: ... def get_daily_open_close_agg( self, ticker: str, @@ -168,6 +329,40 @@ def get_daily_open_close_agg( options=options, ) + @overload + def get_daily_open_close_crypto( + self, + from_: str, + to: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> DailyOpenCloseCrypto: ... + @overload + def get_daily_open_close_crypto( + self, + from_: str, + to: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_daily_open_close_crypto( + self, + from_: str, + to: str, + date: Union[str, date], + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[DailyOpenCloseCrypto, HTTPResponse]: ... def get_daily_open_close_crypto( self, # "from" is a keyword in python https://www.w3schools.com/python/python_ref_keywords.asp @@ -200,6 +395,34 @@ def get_daily_open_close_crypto( options=options, ) + @overload + def get_previous_close_agg( + self, + ticker: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[PreviousCloseAgg]: ... + @overload + def get_previous_close_agg( + self, + ticker: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_previous_close_agg( + self, + ticker: str, + adjusted: Optional[bool] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[PreviousCloseAgg], HTTPResponse]: ... def get_previous_close_agg( self, ticker: str, diff --git a/massive/rest/benzinga.py b/massive/rest/benzinga.py index fdd9d0b0..0e08d3e7 100644 --- a/massive/rest/benzinga.py +++ b/massive/rest/benzinga.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -24,6 +24,160 @@ class BenzingaClient(BaseClient): (aligned with the paths from /benzinga/v1/...) """ + @overload + def list_benzinga_analyst_insights( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + firm: Optional[str] = None, + firm_any_of: Optional[str] = None, + firm_gt: Optional[str] = None, + firm_gte: Optional[str] = None, + firm_lt: Optional[str] = None, + firm_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + benzinga_rating_id: Optional[str] = None, + benzinga_rating_id_any_of: Optional[str] = None, + benzinga_rating_id_gt: Optional[str] = None, + benzinga_rating_id_gte: Optional[str] = None, + benzinga_rating_id_lt: Optional[str] = None, + benzinga_rating_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaAnalystInsight]: ... + @overload + def list_benzinga_analyst_insights( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + firm: Optional[str] = None, + firm_any_of: Optional[str] = None, + firm_gt: Optional[str] = None, + firm_gte: Optional[str] = None, + firm_lt: Optional[str] = None, + firm_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + benzinga_rating_id: Optional[str] = None, + benzinga_rating_id_any_of: Optional[str] = None, + benzinga_rating_id_gt: Optional[str] = None, + benzinga_rating_id_gte: Optional[str] = None, + benzinga_rating_id_lt: Optional[str] = None, + benzinga_rating_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_analyst_insights( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + firm: Optional[str] = None, + firm_any_of: Optional[str] = None, + firm_gt: Optional[str] = None, + firm_gte: Optional[str] = None, + firm_lt: Optional[str] = None, + firm_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + benzinga_rating_id: Optional[str] = None, + benzinga_rating_id_any_of: Optional[str] = None, + benzinga_rating_id_gt: Optional[str] = None, + benzinga_rating_id_gte: Optional[str] = None, + benzinga_rating_id_lt: Optional[str] = None, + benzinga_rating_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaAnalystInsight], HTTPResponse]: ... def list_benzinga_analyst_insights( self, date: Optional[Union[str, date]] = None, @@ -86,6 +240,106 @@ def list_benzinga_analyst_insights( options=options, ) + @overload + def list_benzinga_analysts( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + firm_name: Optional[str] = None, + firm_name_any_of: Optional[str] = None, + firm_name_gt: Optional[str] = None, + firm_name_gte: Optional[str] = None, + firm_name_lt: Optional[str] = None, + firm_name_lte: Optional[str] = None, + full_name: Optional[str] = None, + full_name_any_of: Optional[str] = None, + full_name_gt: Optional[str] = None, + full_name_gte: Optional[str] = None, + full_name_lt: Optional[str] = None, + full_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaAnalyst]: ... + @overload + def list_benzinga_analysts( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + firm_name: Optional[str] = None, + firm_name_any_of: Optional[str] = None, + firm_name_gt: Optional[str] = None, + firm_name_gte: Optional[str] = None, + firm_name_lt: Optional[str] = None, + firm_name_lte: Optional[str] = None, + full_name: Optional[str] = None, + full_name_any_of: Optional[str] = None, + full_name_gt: Optional[str] = None, + full_name_gte: Optional[str] = None, + full_name_lt: Optional[str] = None, + full_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_analysts( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + firm_name: Optional[str] = None, + firm_name_any_of: Optional[str] = None, + firm_name_gt: Optional[str] = None, + firm_name_gte: Optional[str] = None, + firm_name_lt: Optional[str] = None, + firm_name_lte: Optional[str] = None, + full_name: Optional[str] = None, + full_name_any_of: Optional[str] = None, + full_name_gt: Optional[str] = None, + full_name_gte: Optional[str] = None, + full_name_lt: Optional[str] = None, + full_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaAnalyst], HTTPResponse]: ... def list_benzinga_analysts( self, benzinga_id: Optional[str] = None, @@ -130,6 +384,7 @@ def list_benzinga_analysts( options=options, ) + @overload def list_benzinga_consensus_ratings( self, ticker: str, @@ -140,22 +395,504 @@ def list_benzinga_consensus_ratings( date_lte: Optional[Union[str, date]] = None, limit: Optional[int] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False, + raw: Literal[False] = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[BenzingaConsensusRating], HTTPResponse]: - """ - Endpoint: GET /benzinga/v1/consensus-ratings/{ticker} - """ - url = f"/benzinga/v1/consensus-ratings/{ticker}" - return self._paginate( - path=url, - params=self._get_params(self.list_benzinga_consensus_ratings, locals()), - raw=raw, - deserializer=BenzingaConsensusRating.from_dict, - options=options, - ) - - def list_benzinga_earnings( + ) -> Iterator[BenzingaConsensusRating]: ... + @overload + def list_benzinga_consensus_ratings( + self, + ticker: str, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_consensus_ratings( + self, + ticker: str, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaConsensusRating], HTTPResponse]: ... + def list_benzinga_consensus_ratings( + self, + ticker: str, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaConsensusRating], HTTPResponse]: + """ + Endpoint: GET /benzinga/v1/consensus-ratings/{ticker} + """ + url = f"/benzinga/v1/consensus-ratings/{ticker}" + return self._paginate( + path=url, + params=self._get_params(self.list_benzinga_consensus_ratings, locals()), + raw=raw, + deserializer=BenzingaConsensusRating.from_dict, + options=options, + ) + + @overload + def list_benzinga_earnings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + date_status: Optional[str] = None, + date_status_any_of: Optional[str] = None, + date_status_gt: Optional[str] = None, + date_status_gte: Optional[str] = None, + date_status_lt: Optional[str] = None, + date_status_lte: Optional[str] = None, + eps_surprise_percent: Optional[float] = None, + eps_surprise_percent_any_of: Optional[str] = None, + eps_surprise_percent_gt: Optional[float] = None, + eps_surprise_percent_gte: Optional[float] = None, + eps_surprise_percent_lt: Optional[float] = None, + eps_surprise_percent_lte: Optional[float] = None, + revenue_surprise_percent: Optional[float] = None, + revenue_surprise_percent_any_of: Optional[str] = None, + revenue_surprise_percent_gt: Optional[float] = None, + revenue_surprise_percent_gte: Optional[float] = None, + revenue_surprise_percent_lt: Optional[float] = None, + revenue_surprise_percent_lte: Optional[float] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaEarning]: ... + @overload + def list_benzinga_earnings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + date_status: Optional[str] = None, + date_status_any_of: Optional[str] = None, + date_status_gt: Optional[str] = None, + date_status_gte: Optional[str] = None, + date_status_lt: Optional[str] = None, + date_status_lte: Optional[str] = None, + eps_surprise_percent: Optional[float] = None, + eps_surprise_percent_any_of: Optional[str] = None, + eps_surprise_percent_gt: Optional[float] = None, + eps_surprise_percent_gte: Optional[float] = None, + eps_surprise_percent_lt: Optional[float] = None, + eps_surprise_percent_lte: Optional[float] = None, + revenue_surprise_percent: Optional[float] = None, + revenue_surprise_percent_any_of: Optional[str] = None, + revenue_surprise_percent_gt: Optional[float] = None, + revenue_surprise_percent_gte: Optional[float] = None, + revenue_surprise_percent_lt: Optional[float] = None, + revenue_surprise_percent_lte: Optional[float] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_earnings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + date_status: Optional[str] = None, + date_status_any_of: Optional[str] = None, + date_status_gt: Optional[str] = None, + date_status_gte: Optional[str] = None, + date_status_lt: Optional[str] = None, + date_status_lte: Optional[str] = None, + eps_surprise_percent: Optional[float] = None, + eps_surprise_percent_any_of: Optional[str] = None, + eps_surprise_percent_gt: Optional[float] = None, + eps_surprise_percent_gte: Optional[float] = None, + eps_surprise_percent_lt: Optional[float] = None, + eps_surprise_percent_lte: Optional[float] = None, + revenue_surprise_percent: Optional[float] = None, + revenue_surprise_percent_any_of: Optional[str] = None, + revenue_surprise_percent_gt: Optional[float] = None, + revenue_surprise_percent_gte: Optional[float] = None, + revenue_surprise_percent_lt: Optional[float] = None, + revenue_surprise_percent_lte: Optional[float] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaEarning], HTTPResponse]: ... + def list_benzinga_earnings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + date_status: Optional[str] = None, + date_status_any_of: Optional[str] = None, + date_status_gt: Optional[str] = None, + date_status_gte: Optional[str] = None, + date_status_lt: Optional[str] = None, + date_status_lte: Optional[str] = None, + eps_surprise_percent: Optional[float] = None, + eps_surprise_percent_any_of: Optional[str] = None, + eps_surprise_percent_gt: Optional[float] = None, + eps_surprise_percent_gte: Optional[float] = None, + eps_surprise_percent_lt: Optional[float] = None, + eps_surprise_percent_lte: Optional[float] = None, + revenue_surprise_percent: Optional[float] = None, + revenue_surprise_percent_any_of: Optional[str] = None, + revenue_surprise_percent_gt: Optional[float] = None, + revenue_surprise_percent_gte: Optional[float] = None, + revenue_surprise_percent_lt: Optional[float] = None, + revenue_surprise_percent_lte: Optional[float] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaEarning], HTTPResponse]: + """ + Endpoint: GET /benzinga/v1/earnings + """ + url = "/benzinga/v1/earnings" + return self._paginate( + path=url, + params=self._get_params(self.list_benzinga_earnings, locals()), + raw=raw, + deserializer=BenzingaEarning.from_dict, + options=options, + ) + + @overload + def list_benzinga_firms( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaFirm]: ... + @overload + def list_benzinga_firms( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_firms( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaFirm], HTTPResponse]: ... + def list_benzinga_firms( + self, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaFirm], HTTPResponse]: + """ + Endpoint: GET /benzinga/v1/firms + """ + url = "/benzinga/v1/firms" + return self._paginate( + path=url, + params=self._get_params(self.list_benzinga_firms, locals()), + raw=raw, + deserializer=BenzingaFirm.from_dict, + options=options, + ) + + @overload + def list_benzinga_guidance( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + positioning: Optional[str] = None, + positioning_any_of: Optional[str] = None, + positioning_gt: Optional[str] = None, + positioning_gte: Optional[str] = None, + positioning_lt: Optional[str] = None, + positioning_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaGuidance]: ... + @overload + def list_benzinga_guidance( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + positioning: Optional[str] = None, + positioning_any_of: Optional[str] = None, + positioning_gt: Optional[str] = None, + positioning_gte: Optional[str] = None, + positioning_lt: Optional[str] = None, + positioning_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + fiscal_year: Optional[int] = None, + fiscal_year_any_of: Optional[str] = None, + fiscal_year_gt: Optional[int] = None, + fiscal_year_gte: Optional[int] = None, + fiscal_year_lt: Optional[int] = None, + fiscal_year_lte: Optional[int] = None, + fiscal_period: Optional[str] = None, + fiscal_period_any_of: Optional[str] = None, + fiscal_period_gt: Optional[str] = None, + fiscal_period_gte: Optional[str] = None, + fiscal_period_lt: Optional[str] = None, + fiscal_period_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_guidance( self, date: Optional[Union[str, date]] = None, date_any_of: Optional[str] = None, @@ -169,6 +906,12 @@ def list_benzinga_earnings( ticker_gte: Optional[str] = None, ticker_lt: Optional[str] = None, ticker_lte: Optional[str] = None, + positioning: Optional[str] = None, + positioning_any_of: Optional[str] = None, + positioning_gt: Optional[str] = None, + positioning_gte: Optional[str] = None, + positioning_lt: Optional[str] = None, + positioning_lte: Optional[str] = None, importance: Optional[int] = None, importance_any_of: Optional[str] = None, importance_gt: Optional[int] = None, @@ -181,24 +924,6 @@ def list_benzinga_earnings( last_updated_gte: Optional[str] = None, last_updated_lt: Optional[str] = None, last_updated_lte: Optional[str] = None, - date_status: Optional[str] = None, - date_status_any_of: Optional[str] = None, - date_status_gt: Optional[str] = None, - date_status_gte: Optional[str] = None, - date_status_lt: Optional[str] = None, - date_status_lte: Optional[str] = None, - eps_surprise_percent: Optional[float] = None, - eps_surprise_percent_any_of: Optional[str] = None, - eps_surprise_percent_gt: Optional[float] = None, - eps_surprise_percent_gte: Optional[float] = None, - eps_surprise_percent_lt: Optional[float] = None, - eps_surprise_percent_lte: Optional[float] = None, - revenue_surprise_percent: Optional[float] = None, - revenue_surprise_percent_any_of: Optional[str] = None, - revenue_surprise_percent_gt: Optional[float] = None, - revenue_surprise_percent_gte: Optional[float] = None, - revenue_surprise_percent_lt: Optional[float] = None, - revenue_surprise_percent_lte: Optional[float] = None, fiscal_year: Optional[int] = None, fiscal_year_any_of: Optional[str] = None, fiscal_year_gt: Optional[int] = None, @@ -216,45 +941,7 @@ def list_benzinga_earnings( params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[BenzingaEarning], HTTPResponse]: - """ - Endpoint: GET /benzinga/v1/earnings - """ - url = "/benzinga/v1/earnings" - return self._paginate( - path=url, - params=self._get_params(self.list_benzinga_earnings, locals()), - raw=raw, - deserializer=BenzingaEarning.from_dict, - options=options, - ) - - def list_benzinga_firms( - self, - benzinga_id: Optional[str] = None, - benzinga_id_any_of: Optional[str] = None, - benzinga_id_gt: Optional[str] = None, - benzinga_id_gte: Optional[str] = None, - benzinga_id_lt: Optional[str] = None, - benzinga_id_lte: Optional[str] = None, - limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[BenzingaFirm], HTTPResponse]: - """ - Endpoint: GET /benzinga/v1/firms - """ - url = "/benzinga/v1/firms" - return self._paginate( - path=url, - params=self._get_params(self.list_benzinga_firms, locals()), - raw=raw, - deserializer=BenzingaFirm.from_dict, - options=options, - ) - + ) -> Union[Iterator[BenzingaGuidance], HTTPResponse]: ... def list_benzinga_guidance( self, date: Optional[Union[str, date]] = None, @@ -317,6 +1004,115 @@ def list_benzinga_guidance( options=options, ) + @overload + def list_benzinga_news( + self, + published: Optional[str] = None, + published_any_of: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaNews]: ... + @overload + def list_benzinga_news( + self, + published: Optional[str] = None, + published_any_of: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_news( + self, + published: Optional[str] = None, + published_any_of: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaNews], HTTPResponse]: ... def list_benzinga_news( self, published: Optional[str] = None, @@ -364,6 +1160,103 @@ def list_benzinga_news( options=options, ) + @overload + def list_benzinga_news_v2( + self, + published: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + stocks: Optional[str] = None, + stocks_all_of: Optional[str] = None, + stocks_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaNews]: ... + @overload + def list_benzinga_news_v2( + self, + published: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + stocks: Optional[str] = None, + stocks_all_of: Optional[str] = None, + stocks_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_news_v2( + self, + published: Optional[str] = None, + published_gt: Optional[str] = None, + published_gte: Optional[str] = None, + published_lt: Optional[str] = None, + published_lte: Optional[str] = None, + channels: Optional[str] = None, + channels_all_of: Optional[str] = None, + channels_any_of: Optional[str] = None, + tags: Optional[str] = None, + tags_all_of: Optional[str] = None, + tags_any_of: Optional[str] = None, + author: Optional[str] = None, + author_any_of: Optional[str] = None, + author_gt: Optional[str] = None, + author_gte: Optional[str] = None, + author_lt: Optional[str] = None, + author_lte: Optional[str] = None, + stocks: Optional[str] = None, + stocks_all_of: Optional[str] = None, + stocks_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaNews], HTTPResponse]: ... def list_benzinga_news_v2( self, published: Optional[str] = None, @@ -407,6 +1300,196 @@ def list_benzinga_news_v2( options=options, ) + @overload + def list_benzinga_ratings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + price_target_action: Optional[str] = None, + price_target_action_any_of: Optional[str] = None, + price_target_action_gt: Optional[str] = None, + price_target_action_gte: Optional[str] = None, + price_target_action_lt: Optional[str] = None, + price_target_action_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_analyst_id: Optional[str] = None, + benzinga_analyst_id_any_of: Optional[str] = None, + benzinga_analyst_id_gt: Optional[str] = None, + benzinga_analyst_id_gte: Optional[str] = None, + benzinga_analyst_id_lt: Optional[str] = None, + benzinga_analyst_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaRating]: ... + @overload + def list_benzinga_ratings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + price_target_action: Optional[str] = None, + price_target_action_any_of: Optional[str] = None, + price_target_action_gt: Optional[str] = None, + price_target_action_gte: Optional[str] = None, + price_target_action_lt: Optional[str] = None, + price_target_action_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_analyst_id: Optional[str] = None, + benzinga_analyst_id_any_of: Optional[str] = None, + benzinga_analyst_id_gt: Optional[str] = None, + benzinga_analyst_id_gte: Optional[str] = None, + benzinga_analyst_id_lt: Optional[str] = None, + benzinga_analyst_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_ratings( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + importance: Optional[int] = None, + importance_any_of: Optional[str] = None, + importance_gt: Optional[int] = None, + importance_gte: Optional[int] = None, + importance_lt: Optional[int] = None, + importance_lte: Optional[int] = None, + last_updated: Optional[str] = None, + last_updated_any_of: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + rating_action: Optional[str] = None, + rating_action_any_of: Optional[str] = None, + rating_action_gt: Optional[str] = None, + rating_action_gte: Optional[str] = None, + rating_action_lt: Optional[str] = None, + rating_action_lte: Optional[str] = None, + price_target_action: Optional[str] = None, + price_target_action_any_of: Optional[str] = None, + price_target_action_gt: Optional[str] = None, + price_target_action_gte: Optional[str] = None, + price_target_action_lt: Optional[str] = None, + price_target_action_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + benzinga_analyst_id: Optional[str] = None, + benzinga_analyst_id_any_of: Optional[str] = None, + benzinga_analyst_id_gt: Optional[str] = None, + benzinga_analyst_id_gte: Optional[str] = None, + benzinga_analyst_id_lt: Optional[str] = None, + benzinga_analyst_id_lte: Optional[str] = None, + benzinga_firm_id: Optional[str] = None, + benzinga_firm_id_any_of: Optional[str] = None, + benzinga_firm_id_gt: Optional[str] = None, + benzinga_firm_id_gte: Optional[str] = None, + benzinga_firm_id_lt: Optional[str] = None, + benzinga_firm_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaRating], HTTPResponse]: ... def list_benzinga_ratings( self, date: Optional[Union[str, date]] = None, @@ -481,6 +1564,85 @@ def list_benzinga_ratings( options=options, ) + @overload + def list_benzinga_bulls_bears_say( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[BenzingaBullsBearsSay]: ... + @overload + def list_benzinga_bulls_bears_say( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_benzinga_bulls_bears_say( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaBullsBearsSay], HTTPResponse]: ... def list_benzinga_bulls_bears_say( self, ticker: Optional[str] = None, diff --git a/massive/rest/economy.py b/massive/rest/economy.py index bcb81f92..2ad06852 100644 --- a/massive/rest/economy.py +++ b/massive/rest/economy.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -22,6 +22,55 @@ class EconomyClient(BaseClient): (aligned with the paths from /fed/v1/...) """ + @overload + def list_treasury_yields( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: 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: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[TreasuryYield]: ... + @overload + def list_treasury_yields( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: 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: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_treasury_yields( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[TreasuryYield], HTTPResponse]: ... def list_treasury_yields( self, date: Optional[str] = None, @@ -65,6 +114,52 @@ def list_treasury_yields( options=options, ) + @overload + def list_inflation( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FedInflation]: ... + @overload + def list_inflation( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_inflation( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedInflation], HTTPResponse]: ... def list_inflation( self, date: Optional[Union[str, date]] = None, @@ -91,6 +186,52 @@ def list_inflation( options=options, ) + @overload + def list_inflation_expectations( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FedInflationExpectations]: ... + @overload + def list_inflation_expectations( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_inflation_expectations( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedInflationExpectations], HTTPResponse]: ... def list_inflation_expectations( self, date: Optional[Union[str, date]] = None, @@ -132,6 +273,52 @@ def list_inflation_expectations( options=options, ) + @overload + def list_labor_market_indicators( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FedLaborMarket]: ... + @overload + def list_labor_market_indicators( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_labor_market_indicators( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedLaborMarket], HTTPResponse]: ... def list_labor_market_indicators( self, date: Optional[str] = None, @@ -172,6 +359,49 @@ def list_labor_market_indicators( options=options, ) + @overload + def list_funding_conditions( + self, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FedFundingConditions]: ... + @overload + def list_funding_conditions( + self, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_funding_conditions( + self, + date: Optional[Union[str, date]] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedFundingConditions], HTTPResponse]: ... def list_funding_conditions( self, date: Optional[Union[str, date]] = None, @@ -211,6 +441,103 @@ def list_funding_conditions( options=options, ) + @overload + def list_eu_merchant_aggregates( + self, + transaction_date: Optional[Union[str, date]] = None, + transaction_date_gt: Optional[Union[str, date]] = None, + transaction_date_gte: Optional[Union[str, date]] = None, + transaction_date_lt: Optional[Union[str, date]] = None, + transaction_date_lte: Optional[Union[str, date]] = None, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + user_country: Optional[str] = None, + user_country_any_of: Optional[str] = None, + channel: Optional[str] = None, + channel_any_of: Optional[str] = None, + consumer_type: Optional[str] = None, + consumer_type_any_of: Optional[str] = None, + parent_name: Optional[str] = None, + parent_name_any_of: Optional[str] = None, + parent_name_gt: Optional[str] = None, + parent_name_gte: Optional[str] = None, + parent_name_lt: Optional[str] = None, + parent_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EUMerchantAggregate]: ... + @overload + def list_eu_merchant_aggregates( + self, + transaction_date: Optional[Union[str, date]] = None, + transaction_date_gt: Optional[Union[str, date]] = None, + transaction_date_gte: Optional[Union[str, date]] = None, + transaction_date_lt: Optional[Union[str, date]] = None, + transaction_date_lte: Optional[Union[str, date]] = None, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + user_country: Optional[str] = None, + user_country_any_of: Optional[str] = None, + channel: Optional[str] = None, + channel_any_of: Optional[str] = None, + consumer_type: Optional[str] = None, + consumer_type_any_of: Optional[str] = None, + parent_name: Optional[str] = None, + parent_name_any_of: Optional[str] = None, + parent_name_gt: Optional[str] = None, + parent_name_gte: Optional[str] = None, + parent_name_lt: Optional[str] = None, + parent_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_eu_merchant_aggregates( + self, + transaction_date: Optional[Union[str, date]] = None, + transaction_date_gt: Optional[Union[str, date]] = None, + transaction_date_gte: Optional[Union[str, date]] = None, + transaction_date_lt: Optional[Union[str, date]] = None, + transaction_date_lte: Optional[Union[str, date]] = None, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + user_country: Optional[str] = None, + user_country_any_of: Optional[str] = None, + channel: Optional[str] = None, + channel_any_of: Optional[str] = None, + consumer_type: Optional[str] = None, + consumer_type_any_of: Optional[str] = None, + parent_name: Optional[str] = None, + parent_name_any_of: Optional[str] = None, + parent_name_gt: Optional[str] = None, + parent_name_gte: Optional[str] = None, + parent_name_lt: Optional[str] = None, + parent_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EUMerchantAggregate], HTTPResponse]: ... def list_eu_merchant_aggregates( self, transaction_date: Optional[Union[str, date]] = None, @@ -261,6 +588,106 @@ def list_eu_merchant_aggregates( options=options, ) + @overload + def list_eu_merchant_hierarchy( + self, + lookup_name: Optional[str] = None, + lookup_name_any_of: Optional[str] = None, + lookup_name_gt: Optional[str] = None, + lookup_name_gte: Optional[str] = None, + lookup_name_lt: Optional[str] = None, + lookup_name_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + listing_status: Optional[str] = None, + listing_status_any_of: Optional[str] = None, + active_from: Optional[Union[str, date]] = None, + active_from_gt: Optional[Union[str, date]] = None, + active_from_gte: Optional[Union[str, date]] = None, + active_from_lt: Optional[Union[str, date]] = None, + active_from_lte: Optional[Union[str, date]] = None, + active_to: Optional[Union[str, date]] = None, + active_to_gt: Optional[Union[str, date]] = None, + active_to_gte: Optional[Union[str, date]] = None, + active_to_lt: Optional[Union[str, date]] = None, + active_to_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EUMerchantHierarchy]: ... + @overload + def list_eu_merchant_hierarchy( + self, + lookup_name: Optional[str] = None, + lookup_name_any_of: Optional[str] = None, + lookup_name_gt: Optional[str] = None, + lookup_name_gte: Optional[str] = None, + lookup_name_lt: Optional[str] = None, + lookup_name_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + listing_status: Optional[str] = None, + listing_status_any_of: Optional[str] = None, + active_from: Optional[Union[str, date]] = None, + active_from_gt: Optional[Union[str, date]] = None, + active_from_gte: Optional[Union[str, date]] = None, + active_from_lt: Optional[Union[str, date]] = None, + active_from_lte: Optional[Union[str, date]] = None, + active_to: Optional[Union[str, date]] = None, + active_to_gt: Optional[Union[str, date]] = None, + active_to_gte: Optional[Union[str, date]] = None, + active_to_lt: Optional[Union[str, date]] = None, + active_to_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_eu_merchant_hierarchy( + self, + lookup_name: Optional[str] = None, + lookup_name_any_of: Optional[str] = None, + lookup_name_gt: Optional[str] = None, + lookup_name_gte: Optional[str] = None, + lookup_name_lt: Optional[str] = None, + lookup_name_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + listing_status: Optional[str] = None, + listing_status_any_of: Optional[str] = None, + active_from: Optional[Union[str, date]] = None, + active_from_gt: Optional[Union[str, date]] = None, + active_from_gte: Optional[Union[str, date]] = None, + active_from_lt: Optional[Union[str, date]] = None, + active_from_lte: Optional[Union[str, date]] = None, + active_to: Optional[Union[str, date]] = None, + active_to_gt: Optional[Union[str, date]] = None, + active_to_gte: Optional[Union[str, date]] = None, + active_to_lt: Optional[Union[str, date]] = None, + active_to_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EUMerchantHierarchy], HTTPResponse]: ... def list_eu_merchant_hierarchy( self, lookup_name: Optional[str] = None, diff --git a/massive/rest/etf_global.py b/massive/rest/etf_global.py index 9da19539..ac3360a7 100644 --- a/massive/rest/etf_global.py +++ b/massive/rest/etf_global.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -20,6 +20,7 @@ class EtfGlobalClient(BaseClient): (aligned with the paths from /etf-global/v1/...) """ + @overload def get_etf_global_analytics( self, composite_ticker: Optional[str] = None, @@ -92,21 +93,415 @@ def get_etf_global_analytics( limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EtfGlobalAnalytics]: ... + @overload + def get_etf_global_analytics( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + risk_total_score: Optional[float] = None, + risk_total_score_gt: Optional[float] = None, + risk_total_score_gte: Optional[float] = None, + risk_total_score_lt: Optional[float] = None, + risk_total_score_lte: Optional[float] = None, + reward_score: Optional[float] = None, + reward_score_gt: Optional[float] = None, + reward_score_gte: Optional[float] = None, + reward_score_lt: Optional[float] = None, + reward_score_lte: Optional[float] = None, + quant_total_score: Optional[float] = None, + quant_total_score_gt: Optional[float] = None, + quant_total_score_gte: Optional[float] = None, + quant_total_score_lt: Optional[float] = None, + quant_total_score_lte: Optional[float] = None, + quant_grade: Optional[str] = None, + quant_grade_any_of: Optional[str] = None, + quant_grade_gt: Optional[str] = None, + quant_grade_gte: Optional[str] = None, + quant_grade_lt: Optional[str] = None, + quant_grade_lte: Optional[str] = None, + quant_composite_technical: Optional[float] = None, + quant_composite_technical_gt: Optional[float] = None, + quant_composite_technical_gte: Optional[float] = None, + quant_composite_technical_lt: Optional[float] = None, + quant_composite_technical_lte: Optional[float] = None, + quant_composite_sentiment: Optional[float] = None, + quant_composite_sentiment_gt: Optional[float] = None, + quant_composite_sentiment_gte: Optional[float] = None, + quant_composite_sentiment_lt: Optional[float] = None, + quant_composite_sentiment_lte: Optional[float] = None, + quant_composite_behavioral: Optional[float] = None, + quant_composite_behavioral_gt: Optional[float] = None, + quant_composite_behavioral_gte: Optional[float] = None, + quant_composite_behavioral_lt: Optional[float] = None, + quant_composite_behavioral_lte: Optional[float] = None, + quant_composite_fundamental: Optional[float] = None, + quant_composite_fundamental_gt: Optional[float] = None, + quant_composite_fundamental_gte: Optional[float] = None, + quant_composite_fundamental_lt: Optional[float] = None, + quant_composite_fundamental_lte: Optional[float] = None, + quant_composite_global: Optional[float] = None, + quant_composite_global_gt: Optional[float] = None, + quant_composite_global_gte: Optional[float] = None, + quant_composite_global_lt: Optional[float] = None, + quant_composite_global_lte: Optional[float] = None, + quant_composite_quality: Optional[float] = None, + quant_composite_quality_gt: Optional[float] = None, + quant_composite_quality_gte: Optional[float] = None, + quant_composite_quality_lt: Optional[float] = None, + quant_composite_quality_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def get_etf_global_analytics( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + risk_total_score: Optional[float] = None, + risk_total_score_gt: Optional[float] = None, + risk_total_score_gte: Optional[float] = None, + risk_total_score_lt: Optional[float] = None, + risk_total_score_lte: Optional[float] = None, + reward_score: Optional[float] = None, + reward_score_gt: Optional[float] = None, + reward_score_gte: Optional[float] = None, + reward_score_lt: Optional[float] = None, + reward_score_lte: Optional[float] = None, + quant_total_score: Optional[float] = None, + quant_total_score_gt: Optional[float] = None, + quant_total_score_gte: Optional[float] = None, + quant_total_score_lt: Optional[float] = None, + quant_total_score_lte: Optional[float] = None, + quant_grade: Optional[str] = None, + quant_grade_any_of: Optional[str] = None, + quant_grade_gt: Optional[str] = None, + quant_grade_gte: Optional[str] = None, + quant_grade_lt: Optional[str] = None, + quant_grade_lte: Optional[str] = None, + quant_composite_technical: Optional[float] = None, + quant_composite_technical_gt: Optional[float] = None, + quant_composite_technical_gte: Optional[float] = None, + quant_composite_technical_lt: Optional[float] = None, + quant_composite_technical_lte: Optional[float] = None, + quant_composite_sentiment: Optional[float] = None, + quant_composite_sentiment_gt: Optional[float] = None, + quant_composite_sentiment_gte: Optional[float] = None, + quant_composite_sentiment_lt: Optional[float] = None, + quant_composite_sentiment_lte: Optional[float] = None, + quant_composite_behavioral: Optional[float] = None, + quant_composite_behavioral_gt: Optional[float] = None, + quant_composite_behavioral_gte: Optional[float] = None, + quant_composite_behavioral_lt: Optional[float] = None, + quant_composite_behavioral_lte: Optional[float] = None, + quant_composite_fundamental: Optional[float] = None, + quant_composite_fundamental_gt: Optional[float] = None, + quant_composite_fundamental_gte: Optional[float] = None, + quant_composite_fundamental_lt: Optional[float] = None, + quant_composite_fundamental_lte: Optional[float] = None, + quant_composite_global: Optional[float] = None, + quant_composite_global_gt: Optional[float] = None, + quant_composite_global_gte: Optional[float] = None, + quant_composite_global_lt: Optional[float] = None, + quant_composite_global_lte: Optional[float] = None, + quant_composite_quality: Optional[float] = None, + quant_composite_quality_gt: Optional[float] = None, + quant_composite_quality_gte: Optional[float] = None, + quant_composite_quality_lt: Optional[float] = None, + quant_composite_quality_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EtfGlobalAnalytics], HTTPResponse]: ... + def get_etf_global_analytics( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + risk_total_score: Optional[float] = None, + risk_total_score_gt: Optional[float] = None, + risk_total_score_gte: Optional[float] = None, + risk_total_score_lt: Optional[float] = None, + risk_total_score_lte: Optional[float] = None, + reward_score: Optional[float] = None, + reward_score_gt: Optional[float] = None, + reward_score_gte: Optional[float] = None, + reward_score_lt: Optional[float] = None, + reward_score_lte: Optional[float] = None, + quant_total_score: Optional[float] = None, + quant_total_score_gt: Optional[float] = None, + quant_total_score_gte: Optional[float] = None, + quant_total_score_lt: Optional[float] = None, + quant_total_score_lte: Optional[float] = None, + quant_grade: Optional[str] = None, + quant_grade_any_of: Optional[str] = None, + quant_grade_gt: Optional[str] = None, + quant_grade_gte: Optional[str] = None, + quant_grade_lt: Optional[str] = None, + quant_grade_lte: Optional[str] = None, + quant_composite_technical: Optional[float] = None, + quant_composite_technical_gt: Optional[float] = None, + quant_composite_technical_gte: Optional[float] = None, + quant_composite_technical_lt: Optional[float] = None, + quant_composite_technical_lte: Optional[float] = None, + quant_composite_sentiment: Optional[float] = None, + quant_composite_sentiment_gt: Optional[float] = None, + quant_composite_sentiment_gte: Optional[float] = None, + quant_composite_sentiment_lt: Optional[float] = None, + quant_composite_sentiment_lte: Optional[float] = None, + quant_composite_behavioral: Optional[float] = None, + quant_composite_behavioral_gt: Optional[float] = None, + quant_composite_behavioral_gte: Optional[float] = None, + quant_composite_behavioral_lt: Optional[float] = None, + quant_composite_behavioral_lte: Optional[float] = None, + quant_composite_fundamental: Optional[float] = None, + quant_composite_fundamental_gt: Optional[float] = None, + quant_composite_fundamental_gte: Optional[float] = None, + quant_composite_fundamental_lt: Optional[float] = None, + quant_composite_fundamental_lte: Optional[float] = None, + quant_composite_global: Optional[float] = None, + quant_composite_global_gt: Optional[float] = None, + quant_composite_global_gte: Optional[float] = None, + quant_composite_global_lt: Optional[float] = None, + quant_composite_global_lte: Optional[float] = None, + quant_composite_quality: Optional[float] = None, + quant_composite_quality_gt: Optional[float] = None, + quant_composite_quality_gte: Optional[float] = None, + quant_composite_quality_lt: Optional[float] = None, + quant_composite_quality_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EtfGlobalAnalytics], HTTPResponse]: + """ + Endpoint: GET /etf-global/v1/analytics + """ + url = "/etf-global/v1/analytics" + return self._paginate( + path=url, + params=self._get_params(self.get_etf_global_analytics, locals()), + raw=raw, + deserializer=EtfGlobalAnalytics.from_dict, + options=options, + ) + + @overload + def get_etf_global_constituents( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + constituent_ticker: Optional[str] = None, + constituent_ticker_any_of: Optional[str] = None, + constituent_ticker_gt: Optional[str] = None, + constituent_ticker_gte: Optional[str] = None, + constituent_ticker_lt: Optional[str] = None, + constituent_ticker_lte: Optional[str] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + us_code: Optional[str] = None, + us_code_any_of: Optional[str] = None, + us_code_gt: Optional[str] = None, + us_code_gte: Optional[str] = None, + us_code_lt: Optional[str] = None, + us_code_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + figi: Optional[str] = None, + figi_any_of: Optional[str] = None, + figi_gt: Optional[str] = None, + figi_gte: Optional[str] = None, + figi_lt: Optional[str] = None, + figi_lte: Optional[str] = None, + sedol: Optional[str] = None, + sedol_any_of: Optional[str] = None, + sedol_gt: Optional[str] = None, + sedol_gte: Optional[str] = None, + sedol_lt: Optional[str] = None, + sedol_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EtfGlobalConstituent]: ... + @overload + def get_etf_global_constituents( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + constituent_ticker: Optional[str] = None, + constituent_ticker_any_of: Optional[str] = None, + constituent_ticker_gt: Optional[str] = None, + constituent_ticker_gte: Optional[str] = None, + constituent_ticker_lt: Optional[str] = None, + constituent_ticker_lte: Optional[str] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + us_code: Optional[str] = None, + us_code_any_of: Optional[str] = None, + us_code_gt: Optional[str] = None, + us_code_gte: Optional[str] = None, + us_code_lt: Optional[str] = None, + us_code_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + figi: Optional[str] = None, + figi_any_of: Optional[str] = None, + figi_gt: Optional[str] = None, + figi_gte: Optional[str] = None, + figi_lt: Optional[str] = None, + figi_lte: Optional[str] = None, + sedol: Optional[str] = None, + sedol_any_of: Optional[str] = None, + sedol_gt: Optional[str] = None, + sedol_gte: Optional[str] = None, + sedol_lt: Optional[str] = None, + sedol_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def get_etf_global_constituents( + self, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + constituent_ticker: Optional[str] = None, + constituent_ticker_any_of: Optional[str] = None, + constituent_ticker_gt: Optional[str] = None, + constituent_ticker_gte: Optional[str] = None, + constituent_ticker_lt: Optional[str] = None, + constituent_ticker_lte: Optional[str] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + us_code: Optional[str] = None, + us_code_any_of: Optional[str] = None, + us_code_gt: Optional[str] = None, + us_code_gte: Optional[str] = None, + us_code_lt: Optional[str] = None, + us_code_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + figi: Optional[str] = None, + figi_any_of: Optional[str] = None, + figi_gt: Optional[str] = None, + figi_gte: Optional[str] = None, + figi_lt: Optional[str] = None, + figi_lte: Optional[str] = None, + sedol: Optional[str] = None, + sedol_any_of: Optional[str] = None, + sedol_gt: Optional[str] = None, + sedol_gte: Optional[str] = None, + sedol_lt: Optional[str] = None, + sedol_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[EtfGlobalAnalytics], HTTPResponse]: - """ - Endpoint: GET /etf-global/v1/analytics - """ - url = "/etf-global/v1/analytics" - return self._paginate( - path=url, - params=self._get_params(self.get_etf_global_analytics, locals()), - raw=raw, - deserializer=EtfGlobalAnalytics.from_dict, - options=options, - ) - + ) -> Union[Iterator[EtfGlobalConstituent], HTTPResponse]: ... def get_etf_global_constituents( self, composite_ticker: Optional[str] = None, @@ -173,6 +568,82 @@ def get_etf_global_constituents( options=options, ) + @overload + def get_etf_global_fund_flows( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EtfGlobalFundFlow]: ... + @overload + def get_etf_global_fund_flows( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def get_etf_global_fund_flows( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EtfGlobalFundFlow], HTTPResponse]: ... def get_etf_global_fund_flows( self, processed_date: Optional[Union[str, date]] = None, @@ -209,6 +680,82 @@ def get_etf_global_fund_flows( options=options, ) + @overload + def get_etf_global_profiles( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EtfGlobalProfile]: ... + @overload + def get_etf_global_profiles( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def get_etf_global_profiles( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EtfGlobalProfile], HTTPResponse]: ... def get_etf_global_profiles( self, processed_date: Optional[Union[str, date]] = None, @@ -245,6 +792,82 @@ def get_etf_global_profiles( options=options, ) + @overload + def get_etf_global_taxonomies( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[EtfGlobalTaxonomy]: ... + @overload + def get_etf_global_taxonomies( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def get_etf_global_taxonomies( + self, + processed_date: Optional[Union[str, date]] = None, + processed_date_gt: Optional[Union[str, date]] = None, + processed_date_gte: Optional[Union[str, date]] = None, + processed_date_lt: Optional[Union[str, date]] = None, + processed_date_lte: Optional[Union[str, date]] = None, + effective_date: Optional[Union[str, date]] = None, + effective_date_gt: Optional[Union[str, date]] = None, + effective_date_gte: Optional[Union[str, date]] = None, + effective_date_lt: Optional[Union[str, date]] = None, + effective_date_lte: Optional[Union[str, date]] = None, + composite_ticker: Optional[str] = None, + composite_ticker_any_of: Optional[str] = None, + composite_ticker_gt: Optional[str] = None, + composite_ticker_gte: Optional[str] = None, + composite_ticker_lt: Optional[str] = None, + composite_ticker_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EtfGlobalTaxonomy], HTTPResponse]: ... def get_etf_global_taxonomies( self, processed_date: Optional[Union[str, date]] = None, diff --git a/massive/rest/financials.py b/massive/rest/financials.py index 6138258a..9c6475ec 100644 --- a/massive/rest/financials.py +++ b/massive/rest/financials.py @@ -1,5 +1,5 @@ # financials.py -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -21,6 +21,139 @@ class FinancialsClient(BaseClient): (aligned with the paths from /stocks/financials/v1/...) """ + @overload + def list_financials_balance_sheets( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FinancialBalanceSheet]: ... + @overload + def list_financials_balance_sheets( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_financials_balance_sheets( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialBalanceSheet], HTTPResponse]: ... def list_financials_balance_sheets( self, cik: Optional[str] = None, @@ -76,6 +209,139 @@ def list_financials_balance_sheets( options=options, ) + @overload + def list_financials_cash_flow_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FinancialCashFlowStatement]: ... + @overload + def list_financials_cash_flow_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_financials_cash_flow_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialCashFlowStatement], HTTPResponse]: ... def list_financials_cash_flow_statements( self, cik: Optional[str] = None, @@ -116,78 +382,575 @@ def list_financials_cash_flow_statements( limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[FinancialCashFlowStatement], HTTPResponse]: - """ - Endpoint: GET /stocks/financials/v1/cash-flow-statements - """ - url = "/stocks/financials/v1/cash-flow-statements" - return self._paginate( - path=url, - params=self._get_params( - self.list_financials_cash_flow_statements, locals() - ), - raw=raw, - deserializer=FinancialCashFlowStatement.from_dict, - options=options, - ) - - def list_financials_income_statements( + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialCashFlowStatement], HTTPResponse]: + """ + Endpoint: GET /stocks/financials/v1/cash-flow-statements + """ + url = "/stocks/financials/v1/cash-flow-statements" + return self._paginate( + path=url, + params=self._get_params( + self.list_financials_cash_flow_statements, locals() + ), + raw=raw, + deserializer=FinancialCashFlowStatement.from_dict, + options=options, + ) + + @overload + def list_financials_income_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FinancialIncomeStatement]: ... + @overload + def list_financials_income_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_financials_income_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialIncomeStatement], HTTPResponse]: ... + def list_financials_income_statements( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + fiscal_year: Optional[float] = None, + fiscal_year_gt: Optional[float] = None, + fiscal_year_gte: Optional[float] = None, + fiscal_year_lt: Optional[float] = None, + fiscal_year_lte: Optional[float] = None, + fiscal_quarter: Optional[float] = None, + fiscal_quarter_gt: Optional[float] = None, + fiscal_quarter_gte: Optional[float] = None, + fiscal_quarter_lt: Optional[float] = None, + fiscal_quarter_lte: Optional[float] = None, + timeframe: Optional[str] = None, + timeframe_any_of: Optional[str] = None, + timeframe_gt: Optional[str] = None, + timeframe_gte: Optional[str] = None, + timeframe_lt: Optional[str] = None, + timeframe_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialIncomeStatement], HTTPResponse]: + """ + Endpoint: GET /stocks/financials/v1/income-statements + """ + url = "/stocks/financials/v1/income-statements" + return self._paginate( + path=url, + params=self._get_params(self.list_financials_income_statements, locals()), + raw=raw, + deserializer=FinancialIncomeStatement.from_dict, + options=options, + ) + + @overload + def list_financials_ratios( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + price: Optional[float] = None, + price_gt: Optional[float] = None, + price_gte: Optional[float] = None, + price_lt: Optional[float] = None, + price_lte: Optional[float] = None, + average_volume: Optional[float] = None, + average_volume_gt: Optional[float] = None, + average_volume_gte: Optional[float] = None, + average_volume_lt: Optional[float] = None, + average_volume_lte: Optional[float] = None, + market_cap: Optional[float] = None, + market_cap_gt: Optional[float] = None, + market_cap_gte: Optional[float] = None, + market_cap_lt: Optional[float] = None, + market_cap_lte: Optional[float] = None, + earnings_per_share: Optional[float] = None, + earnings_per_share_gt: Optional[float] = None, + earnings_per_share_gte: Optional[float] = None, + earnings_per_share_lt: Optional[float] = None, + earnings_per_share_lte: Optional[float] = None, + price_to_earnings: Optional[float] = None, + price_to_earnings_gt: Optional[float] = None, + price_to_earnings_gte: Optional[float] = None, + price_to_earnings_lt: Optional[float] = None, + price_to_earnings_lte: Optional[float] = None, + price_to_book: Optional[float] = None, + price_to_book_gt: Optional[float] = None, + price_to_book_gte: Optional[float] = None, + price_to_book_lt: Optional[float] = None, + price_to_book_lte: Optional[float] = None, + price_to_sales: Optional[float] = None, + price_to_sales_gt: Optional[float] = None, + price_to_sales_gte: Optional[float] = None, + price_to_sales_lt: Optional[float] = None, + price_to_sales_lte: Optional[float] = None, + price_to_cash_flow: Optional[float] = None, + price_to_cash_flow_gt: Optional[float] = None, + price_to_cash_flow_gte: Optional[float] = None, + price_to_cash_flow_lt: Optional[float] = None, + price_to_cash_flow_lte: Optional[float] = None, + price_to_free_cash_flow: Optional[float] = None, + price_to_free_cash_flow_gt: Optional[float] = None, + price_to_free_cash_flow_gte: Optional[float] = None, + price_to_free_cash_flow_lt: Optional[float] = None, + price_to_free_cash_flow_lte: Optional[float] = None, + dividend_yield: Optional[float] = None, + dividend_yield_gt: Optional[float] = None, + dividend_yield_gte: Optional[float] = None, + dividend_yield_lt: Optional[float] = None, + dividend_yield_lte: Optional[float] = None, + return_on_assets: Optional[float] = None, + return_on_assets_gt: Optional[float] = None, + return_on_assets_gte: Optional[float] = None, + return_on_assets_lt: Optional[float] = None, + return_on_assets_lte: Optional[float] = None, + return_on_equity: Optional[float] = None, + return_on_equity_gt: Optional[float] = None, + return_on_equity_gte: Optional[float] = None, + return_on_equity_lt: Optional[float] = None, + return_on_equity_lte: Optional[float] = None, + debt_to_equity: Optional[float] = None, + debt_to_equity_gt: Optional[float] = None, + debt_to_equity_gte: Optional[float] = None, + debt_to_equity_lt: Optional[float] = None, + debt_to_equity_lte: Optional[float] = None, + current: Optional[float] = None, + current_gt: Optional[float] = None, + current_gte: Optional[float] = None, + current_lt: Optional[float] = None, + current_lte: Optional[float] = None, + quick: Optional[float] = None, + quick_gt: Optional[float] = None, + quick_gte: Optional[float] = None, + quick_lt: Optional[float] = None, + quick_lte: Optional[float] = None, + cash: Optional[float] = None, + cash_gt: Optional[float] = None, + cash_gte: Optional[float] = None, + cash_lt: Optional[float] = None, + cash_lte: Optional[float] = None, + ev_to_sales: Optional[float] = None, + ev_to_sales_gt: Optional[float] = None, + ev_to_sales_gte: Optional[float] = None, + ev_to_sales_lt: Optional[float] = None, + ev_to_sales_lte: Optional[float] = None, + ev_to_ebitda: Optional[float] = None, + ev_to_ebitda_gt: Optional[float] = None, + ev_to_ebitda_gte: Optional[float] = None, + ev_to_ebitda_lt: Optional[float] = None, + ev_to_ebitda_lte: Optional[float] = None, + enterprise_value: Optional[float] = None, + enterprise_value_gt: Optional[float] = None, + enterprise_value_gte: Optional[float] = None, + enterprise_value_lt: Optional[float] = None, + enterprise_value_lte: Optional[float] = None, + free_cash_flow: Optional[float] = None, + free_cash_flow_gt: Optional[float] = None, + free_cash_flow_gte: Optional[float] = None, + free_cash_flow_lt: Optional[float] = None, + free_cash_flow_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FinancialRatio]: ... + @overload + def list_financials_ratios( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + price: Optional[float] = None, + price_gt: Optional[float] = None, + price_gte: Optional[float] = None, + price_lt: Optional[float] = None, + price_lte: Optional[float] = None, + average_volume: Optional[float] = None, + average_volume_gt: Optional[float] = None, + average_volume_gte: Optional[float] = None, + average_volume_lt: Optional[float] = None, + average_volume_lte: Optional[float] = None, + market_cap: Optional[float] = None, + market_cap_gt: Optional[float] = None, + market_cap_gte: Optional[float] = None, + market_cap_lt: Optional[float] = None, + market_cap_lte: Optional[float] = None, + earnings_per_share: Optional[float] = None, + earnings_per_share_gt: Optional[float] = None, + earnings_per_share_gte: Optional[float] = None, + earnings_per_share_lt: Optional[float] = None, + earnings_per_share_lte: Optional[float] = None, + price_to_earnings: Optional[float] = None, + price_to_earnings_gt: Optional[float] = None, + price_to_earnings_gte: Optional[float] = None, + price_to_earnings_lt: Optional[float] = None, + price_to_earnings_lte: Optional[float] = None, + price_to_book: Optional[float] = None, + price_to_book_gt: Optional[float] = None, + price_to_book_gte: Optional[float] = None, + price_to_book_lt: Optional[float] = None, + price_to_book_lte: Optional[float] = None, + price_to_sales: Optional[float] = None, + price_to_sales_gt: Optional[float] = None, + price_to_sales_gte: Optional[float] = None, + price_to_sales_lt: Optional[float] = None, + price_to_sales_lte: Optional[float] = None, + price_to_cash_flow: Optional[float] = None, + price_to_cash_flow_gt: Optional[float] = None, + price_to_cash_flow_gte: Optional[float] = None, + price_to_cash_flow_lt: Optional[float] = None, + price_to_cash_flow_lte: Optional[float] = None, + price_to_free_cash_flow: Optional[float] = None, + price_to_free_cash_flow_gt: Optional[float] = None, + price_to_free_cash_flow_gte: Optional[float] = None, + price_to_free_cash_flow_lt: Optional[float] = None, + price_to_free_cash_flow_lte: Optional[float] = None, + dividend_yield: Optional[float] = None, + dividend_yield_gt: Optional[float] = None, + dividend_yield_gte: Optional[float] = None, + dividend_yield_lt: Optional[float] = None, + dividend_yield_lte: Optional[float] = None, + return_on_assets: Optional[float] = None, + return_on_assets_gt: Optional[float] = None, + return_on_assets_gte: Optional[float] = None, + return_on_assets_lt: Optional[float] = None, + return_on_assets_lte: Optional[float] = None, + return_on_equity: Optional[float] = None, + return_on_equity_gt: Optional[float] = None, + return_on_equity_gte: Optional[float] = None, + return_on_equity_lt: Optional[float] = None, + return_on_equity_lte: Optional[float] = None, + debt_to_equity: Optional[float] = None, + debt_to_equity_gt: Optional[float] = None, + debt_to_equity_gte: Optional[float] = None, + debt_to_equity_lt: Optional[float] = None, + debt_to_equity_lte: Optional[float] = None, + current: Optional[float] = None, + current_gt: Optional[float] = None, + current_gte: Optional[float] = None, + current_lt: Optional[float] = None, + current_lte: Optional[float] = None, + quick: Optional[float] = None, + quick_gt: Optional[float] = None, + quick_gte: Optional[float] = None, + quick_lt: Optional[float] = None, + quick_lte: Optional[float] = None, + cash: Optional[float] = None, + cash_gt: Optional[float] = None, + cash_gte: Optional[float] = None, + cash_lt: Optional[float] = None, + cash_lte: Optional[float] = None, + ev_to_sales: Optional[float] = None, + ev_to_sales_gt: Optional[float] = None, + ev_to_sales_gte: Optional[float] = None, + ev_to_sales_lt: Optional[float] = None, + ev_to_sales_lte: Optional[float] = None, + ev_to_ebitda: Optional[float] = None, + ev_to_ebitda_gt: Optional[float] = None, + ev_to_ebitda_gte: Optional[float] = None, + ev_to_ebitda_lt: Optional[float] = None, + ev_to_ebitda_lte: Optional[float] = None, + enterprise_value: Optional[float] = None, + enterprise_value_gt: Optional[float] = None, + enterprise_value_gte: Optional[float] = None, + enterprise_value_lt: Optional[float] = None, + enterprise_value_lte: Optional[float] = None, + free_cash_flow: Optional[float] = None, + free_cash_flow_gt: Optional[float] = None, + free_cash_flow_gte: Optional[float] = None, + free_cash_flow_lt: Optional[float] = None, + free_cash_flow_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_financials_ratios( self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, cik: Optional[str] = None, cik_any_of: Optional[str] = None, cik_gt: Optional[str] = None, cik_gte: Optional[str] = None, cik_lt: Optional[str] = None, cik_lte: Optional[str] = None, - tickers: Optional[str] = None, - tickers_all_of: Optional[str] = None, - tickers_any_of: Optional[str] = None, - period_end: Optional[Union[str, date]] = None, - period_end_gt: Optional[Union[str, date]] = None, - period_end_gte: Optional[Union[str, date]] = None, - period_end_lt: Optional[Union[str, date]] = None, - period_end_lte: Optional[Union[str, date]] = None, - filing_date: Optional[Union[str, date]] = None, - filing_date_gt: Optional[Union[str, date]] = None, - filing_date_gte: Optional[Union[str, date]] = None, - filing_date_lt: Optional[Union[str, date]] = None, - filing_date_lte: Optional[Union[str, date]] = None, - fiscal_year: Optional[float] = None, - fiscal_year_gt: Optional[float] = None, - fiscal_year_gte: Optional[float] = None, - fiscal_year_lt: Optional[float] = None, - fiscal_year_lte: Optional[float] = None, - fiscal_quarter: Optional[float] = None, - fiscal_quarter_gt: Optional[float] = None, - fiscal_quarter_gte: Optional[float] = None, - fiscal_quarter_lt: Optional[float] = None, - fiscal_quarter_lte: Optional[float] = None, - timeframe: Optional[str] = None, - timeframe_any_of: Optional[str] = None, - timeframe_gt: Optional[str] = None, - timeframe_gte: Optional[str] = None, - timeframe_lt: Optional[str] = None, - timeframe_lte: Optional[str] = None, + price: Optional[float] = None, + price_gt: Optional[float] = None, + price_gte: Optional[float] = None, + price_lt: Optional[float] = None, + price_lte: Optional[float] = None, + average_volume: Optional[float] = None, + average_volume_gt: Optional[float] = None, + average_volume_gte: Optional[float] = None, + average_volume_lt: Optional[float] = None, + average_volume_lte: Optional[float] = None, + market_cap: Optional[float] = None, + market_cap_gt: Optional[float] = None, + market_cap_gte: Optional[float] = None, + market_cap_lt: Optional[float] = None, + market_cap_lte: Optional[float] = None, + earnings_per_share: Optional[float] = None, + earnings_per_share_gt: Optional[float] = None, + earnings_per_share_gte: Optional[float] = None, + earnings_per_share_lt: Optional[float] = None, + earnings_per_share_lte: Optional[float] = None, + price_to_earnings: Optional[float] = None, + price_to_earnings_gt: Optional[float] = None, + price_to_earnings_gte: Optional[float] = None, + price_to_earnings_lt: Optional[float] = None, + price_to_earnings_lte: Optional[float] = None, + price_to_book: Optional[float] = None, + price_to_book_gt: Optional[float] = None, + price_to_book_gte: Optional[float] = None, + price_to_book_lt: Optional[float] = None, + price_to_book_lte: Optional[float] = None, + price_to_sales: Optional[float] = None, + price_to_sales_gt: Optional[float] = None, + price_to_sales_gte: Optional[float] = None, + price_to_sales_lt: Optional[float] = None, + price_to_sales_lte: Optional[float] = None, + price_to_cash_flow: Optional[float] = None, + price_to_cash_flow_gt: Optional[float] = None, + price_to_cash_flow_gte: Optional[float] = None, + price_to_cash_flow_lt: Optional[float] = None, + price_to_cash_flow_lte: Optional[float] = None, + price_to_free_cash_flow: Optional[float] = None, + price_to_free_cash_flow_gt: Optional[float] = None, + price_to_free_cash_flow_gte: Optional[float] = None, + price_to_free_cash_flow_lt: Optional[float] = None, + price_to_free_cash_flow_lte: Optional[float] = None, + dividend_yield: Optional[float] = None, + dividend_yield_gt: Optional[float] = None, + dividend_yield_gte: Optional[float] = None, + dividend_yield_lt: Optional[float] = None, + dividend_yield_lte: Optional[float] = None, + return_on_assets: Optional[float] = None, + return_on_assets_gt: Optional[float] = None, + return_on_assets_gte: Optional[float] = None, + return_on_assets_lt: Optional[float] = None, + return_on_assets_lte: Optional[float] = None, + return_on_equity: Optional[float] = None, + return_on_equity_gt: Optional[float] = None, + return_on_equity_gte: Optional[float] = None, + return_on_equity_lt: Optional[float] = None, + return_on_equity_lte: Optional[float] = None, + debt_to_equity: Optional[float] = None, + debt_to_equity_gt: Optional[float] = None, + debt_to_equity_gte: Optional[float] = None, + debt_to_equity_lt: Optional[float] = None, + debt_to_equity_lte: Optional[float] = None, + current: Optional[float] = None, + current_gt: Optional[float] = None, + current_gte: Optional[float] = None, + current_lt: Optional[float] = None, + current_lte: Optional[float] = None, + quick: Optional[float] = None, + quick_gt: Optional[float] = None, + quick_gte: Optional[float] = None, + quick_lt: Optional[float] = None, + quick_lte: Optional[float] = None, + cash: Optional[float] = None, + cash_gt: Optional[float] = None, + cash_gte: Optional[float] = None, + cash_lt: Optional[float] = None, + cash_lte: Optional[float] = None, + ev_to_sales: Optional[float] = None, + ev_to_sales_gt: Optional[float] = None, + ev_to_sales_gte: Optional[float] = None, + ev_to_sales_lt: Optional[float] = None, + ev_to_sales_lte: Optional[float] = None, + ev_to_ebitda: Optional[float] = None, + ev_to_ebitda_gt: Optional[float] = None, + ev_to_ebitda_gte: Optional[float] = None, + ev_to_ebitda_lt: Optional[float] = None, + ev_to_ebitda_lte: Optional[float] = None, + enterprise_value: Optional[float] = None, + enterprise_value_gt: Optional[float] = None, + enterprise_value_gte: Optional[float] = None, + enterprise_value_lt: Optional[float] = None, + enterprise_value_lte: Optional[float] = None, + free_cash_flow: Optional[float] = None, + free_cash_flow_gt: Optional[float] = None, + free_cash_flow_gte: Optional[float] = None, + free_cash_flow_lt: Optional[float] = None, + free_cash_flow_lte: Optional[float] = None, limit: Optional[int] = None, sort: Optional[Union[str, Sort]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[FinancialIncomeStatement], HTTPResponse]: - """ - Endpoint: GET /stocks/financials/v1/income-statements - """ - url = "/stocks/financials/v1/income-statements" - return self._paginate( - path=url, - params=self._get_params(self.list_financials_income_statements, locals()), - raw=raw, - deserializer=FinancialIncomeStatement.from_dict, - options=options, - ) - + ) -> Union[Iterator[FinancialRatio], HTTPResponse]: ... def list_financials_ratios( self, ticker: Optional[str] = None, @@ -320,6 +1083,67 @@ def list_financials_ratios( options=options, ) + @overload + def list_stocks_floats( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + free_float_percent: Optional[float] = None, + free_float_percent_gt: Optional[float] = None, + free_float_percent_gte: Optional[float] = None, + free_float_percent_lt: Optional[float] = None, + free_float_percent_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FinancialFloat]: ... + @overload + def list_stocks_floats( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + free_float_percent: Optional[float] = None, + free_float_percent_gt: Optional[float] = None, + free_float_percent_gte: Optional[float] = None, + free_float_percent_lt: Optional[float] = None, + free_float_percent_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_stocks_floats( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + free_float_percent: Optional[float] = None, + free_float_percent_gt: Optional[float] = None, + free_float_percent_gte: Optional[float] = None, + free_float_percent_lt: Optional[float] = None, + free_float_percent_lte: Optional[float] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FinancialFloat], HTTPResponse]: ... def list_stocks_floats( self, ticker: Optional[str] = None, diff --git a/massive/rest/futures.py b/massive/rest/futures.py index 8973c7af..6d6e9d90 100644 --- a/massive/rest/futures.py +++ b/massive/rest/futures.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -24,6 +24,55 @@ class FuturesClient(BaseClient): (aligned with the paths from /futures/v1/...) """ + @overload + def list_futures_aggregates( + self, + ticker: str, + resolution: Optional[str] = None, + window_start: Optional[str] = None, + window_start_lt: Optional[str] = None, + window_start_lte: Optional[str] = None, + window_start_gt: Optional[str] = None, + window_start_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesAgg]: ... + @overload + def list_futures_aggregates( + self, + ticker: str, + resolution: Optional[str] = None, + window_start: Optional[str] = None, + window_start_lt: Optional[str] = None, + window_start_lte: Optional[str] = None, + window_start_gt: Optional[str] = None, + window_start_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_aggregates( + self, + ticker: str, + resolution: Optional[str] = None, + window_start: Optional[str] = None, + window_start_lt: Optional[str] = None, + window_start_lte: Optional[str] = None, + window_start_gt: Optional[str] = None, + window_start_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesAgg], HTTPResponse]: ... def list_futures_aggregates( self, ticker: str, @@ -57,6 +106,124 @@ def list_futures_aggregates( options=options, ) + @overload + def list_futures_contracts( + self, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + active: Optional[bool] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + first_trade_date: Optional[str] = None, + first_trade_date_gt: Optional[str] = None, + first_trade_date_gte: Optional[str] = None, + first_trade_date_lt: Optional[str] = None, + first_trade_date_lte: Optional[str] = None, + last_trade_date: Optional[str] = None, + last_trade_date_gt: Optional[str] = None, + last_trade_date_gte: Optional[str] = None, + last_trade_date_lt: Optional[str] = None, + last_trade_date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesContract]: ... + @overload + def list_futures_contracts( + self, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + active: Optional[bool] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + first_trade_date: Optional[str] = None, + first_trade_date_gt: Optional[str] = None, + first_trade_date_gte: Optional[str] = None, + first_trade_date_lt: Optional[str] = None, + first_trade_date_lte: Optional[str] = None, + last_trade_date: Optional[str] = None, + last_trade_date_gt: Optional[str] = None, + last_trade_date_gte: Optional[str] = None, + last_trade_date_lt: Optional[str] = None, + last_trade_date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_contracts( + self, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + active: Optional[bool] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + first_trade_date: Optional[str] = None, + first_trade_date_gt: Optional[str] = None, + first_trade_date_gte: Optional[str] = None, + first_trade_date_lt: Optional[str] = None, + first_trade_date_lte: Optional[str] = None, + last_trade_date: Optional[str] = None, + last_trade_date_gt: Optional[str] = None, + last_trade_date_gte: Optional[str] = None, + last_trade_date_lt: Optional[str] = None, + last_trade_date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesContract], HTTPResponse]: ... def list_futures_contracts( self, date: Optional[str] = None, @@ -109,6 +276,49 @@ def list_futures_contracts( options=options, ) + @overload + def list_futures_products( + self, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + sector: Optional[str] = None, + sector_any_of: Optional[str] = None, + sub_sector: Optional[str] = None, + sub_sector_any_of: Optional[str] = None, + asset_class: Optional[str] = None, + asset_class_any_of: Optional[str] = None, + asset_sub_class: Optional[str] = None, + asset_sub_class_any_of: Optional[str] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesProduct]: ... + @overload def list_futures_products( self, name: Optional[str] = None, @@ -145,25 +355,170 @@ def list_futures_products( type: Optional[str] = None, type_any_of: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[str] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_products( + self, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + sector: Optional[str] = None, + sector_any_of: Optional[str] = None, + sub_sector: Optional[str] = None, + sub_sector_any_of: Optional[str] = None, + asset_class: Optional[str] = None, + asset_class_any_of: Optional[str] = None, + asset_sub_class: Optional[str] = None, + asset_sub_class_any_of: Optional[str] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesProduct], HTTPResponse]: ... + def list_futures_products( + self, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + sector: Optional[str] = None, + sector_any_of: Optional[str] = None, + sub_sector: Optional[str] = None, + sub_sector_any_of: Optional[str] = None, + asset_class: Optional[str] = None, + asset_class_any_of: Optional[str] = None, + asset_sub_class: Optional[str] = None, + asset_sub_class_any_of: Optional[str] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesProduct], HTTPResponse]: + """ + Endpoint: GET /futures/v1/products + + Returns a list of futures products (including combos). + """ + url = "/futures/v1/products" + return self._paginate( + path=url, + params=self._get_params(self.list_futures_products, locals()), + raw=raw, + deserializer=FuturesProduct.from_dict, + options=options, + ) + + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesQuote]: ... + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[FuturesProduct], HTTPResponse]: - """ - Endpoint: GET /futures/v1/products - - Returns a list of futures products (including combos). - """ - url = "/futures/v1/products" - return self._paginate( - path=url, - params=self._get_params(self.list_futures_products, locals()), - raw=raw, - deserializer=FuturesProduct.from_dict, - options=options, - ) - + ) -> Union[Iterator[FuturesQuote], HTTPResponse]: ... def list_futures_quotes( self, ticker: str, @@ -197,6 +552,67 @@ def list_futures_quotes( options=options, ) + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesTrade]: ... + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_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, + session_end_date: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesTrade], HTTPResponse]: ... def list_futures_trades( self, ticker: str, @@ -230,6 +646,85 @@ def list_futures_trades( options=options, ) + @overload + def list_futures_schedules( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + session_end_date: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesSchedule]: ... + @overload + def list_futures_schedules( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + session_end_date: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_schedules( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + session_end_date: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesSchedule], HTTPResponse]: ... def list_futures_schedules( self, product_code: Optional[str] = None, @@ -270,6 +765,49 @@ def list_futures_schedules( options=options, ) + @overload + def list_futures_market_statuses( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesMarketStatus]: ... + @overload + def list_futures_market_statuses( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_market_statuses( + self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesMarketStatus], HTTPResponse]: ... def list_futures_market_statuses( self, product_code: Optional[str] = None, @@ -292,6 +830,70 @@ def list_futures_market_statuses( options=options, ) + @overload + def get_futures_snapshot( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesSnapshot]: ... + @overload + def get_futures_snapshot( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_futures_snapshot( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesSnapshot], HTTPResponse]: ... def get_futures_snapshot( self, ticker: Optional[str] = None, @@ -321,6 +923,31 @@ def get_futures_snapshot( options=options, ) + @overload + def list_futures_exchanges( + self, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FuturesExchange]: ... + @overload + def list_futures_exchanges( + self, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_futures_exchanges( + self, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FuturesExchange], HTTPResponse]: ... def list_futures_exchanges( self, limit: Optional[int] = None, diff --git a/massive/rest/indicators.py b/massive/rest/indicators.py index 88746f62..bdc392b0 100644 --- a/massive/rest/indicators.py +++ b/massive/rest/indicators.py @@ -6,7 +6,7 @@ MACDIndicatorResults, ) from .base import BaseClient -from typing import Optional, Any, Dict, List, Union +from typing import Optional, Any, Dict, List, Union, Literal, overload from .models import Order from urllib3 import HTTPResponse from datetime import datetime, date @@ -15,6 +15,67 @@ class IndicatorsClient(BaseClient): + @overload + def get_sma( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> SMAIndicatorResults: ... + @overload + def get_sma( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_sma( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[SMAIndicatorResults, HTTPResponse]: ... def get_sma( self, ticker: str, @@ -70,6 +131,67 @@ def get_sma( options=options, ) + @overload + def get_ema( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> EMAIndicatorResults: ... + @overload + def get_ema( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_ema( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[EMAIndicatorResults, HTTPResponse]: ... def get_ema( self, ticker: str, @@ -125,6 +247,67 @@ def get_ema( options=options, ) + @overload + def get_rsi( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> RSIIndicatorResults: ... + @overload + def get_rsi( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_rsi( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[RSIIndicatorResults, HTTPResponse]: ... def get_rsi( self, ticker: str, @@ -180,6 +363,73 @@ def get_rsi( options=options, ) + @overload + def get_macd( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + short_window: Optional[int] = None, + long_window: Optional[int] = None, + signal_window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> MACDIndicatorResults: ... + @overload + def get_macd( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + short_window: Optional[int] = None, + long_window: Optional[int] = None, + signal_window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_macd( + self, + ticker: str, + 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, + timespan: Optional[str] = None, + short_window: Optional[int] = None, + long_window: Optional[int] = None, + signal_window: Optional[int] = None, + adjusted: Optional[bool] = None, + expand_underlying: Optional[bool] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + params: Optional[Dict[str, Any]] = None, + series_type: Optional[Union[str, SeriesType]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[MACDIndicatorResults, HTTPResponse]: ... def get_macd( self, ticker: str, diff --git a/massive/rest/quotes.py b/massive/rest/quotes.py index 353c21e1..48285aeb 100644 --- a/massive/rest/quotes.py +++ b/massive/rest/quotes.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, Union, Iterator +from typing import Optional, Any, Dict, Union, Iterator, Literal, overload from .models import ( Quote, LastQuote, @@ -17,6 +17,55 @@ # https://massive.com/docs/stocks class QuotesClient(BaseClient): + @overload + def list_quotes( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Quote]: ... + @overload + def list_quotes( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_quotes( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Quote], HTTPResponse]: ... def list_quotes( self, ticker: str, @@ -58,6 +107,31 @@ def list_quotes( options=options, ) + @overload + def get_last_quote( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> LastQuote: ... + @overload + def get_last_quote( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_last_quote( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[LastQuote, HTTPResponse]: ... def get_last_quote( self, ticker: str, @@ -84,6 +158,34 @@ def get_last_quote( options=options, ) + @overload + def get_last_forex_quote( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> LastForexQuote: ... + @overload + def get_last_forex_quote( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_last_forex_quote( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[LastForexQuote, HTTPResponse]: ... def get_last_forex_quote( self, from_: str, @@ -111,6 +213,40 @@ def get_last_forex_quote( options=options, ) + @overload + def get_real_time_currency_conversion( + self, + from_: str, + to: str, + amount: Optional[float] = None, + precision: Union[int, Precision] = 2, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> RealTimeCurrencyConversion: ... + @overload + def get_real_time_currency_conversion( + self, + from_: str, + to: str, + amount: Optional[float] = None, + precision: Union[int, Precision] = 2, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_real_time_currency_conversion( + self, + from_: str, + to: str, + amount: Optional[float] = None, + precision: Union[int, Precision] = 2, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[RealTimeCurrencyConversion, HTTPResponse]: ... def get_real_time_currency_conversion( self, from_: str, diff --git a/massive/rest/reference.py b/massive/rest/reference.py index 12525548..c31a8cdc 100644 --- a/massive/rest/reference.py +++ b/massive/rest/reference.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from .models import ( MarketHoliday, MarketStatus, @@ -44,6 +44,18 @@ class MarketsClient(BaseClient): + @overload + def get_market_holidays( + self, params: Optional[Dict[str, Any]] = None, raw: Literal[False] = False + ) -> List[MarketHoliday]: ... + @overload + def get_market_holidays( + self, params: Optional[Dict[str, Any]] = None, *, raw: Literal[True] + ) -> HTTPResponse: ... + @overload + def get_market_holidays( + self, params: Optional[Dict[str, Any]] = None, raw: bool = False + ) -> Union[List[MarketHoliday], HTTPResponse]: ... def get_market_holidays( self, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[List[MarketHoliday], HTTPResponse]: @@ -64,6 +76,18 @@ def get_market_holidays( result_key="", ) + @overload + def get_market_status( + self, params: Optional[Dict[str, Any]] = None, raw: Literal[False] = False + ) -> MarketStatus: ... + @overload + def get_market_status( + self, params: Optional[Dict[str, Any]] = None, *, raw: Literal[True] + ) -> HTTPResponse: ... + @overload + def get_market_status( + self, params: Optional[Dict[str, Any]] = None, raw: bool = False + ) -> Union[MarketStatus, HTTPResponse]: ... def get_market_status( self, params: Optional[Dict[str, Any]] = None, raw: bool = False ) -> Union[MarketStatus, HTTPResponse]: @@ -82,6 +106,76 @@ def get_market_status( class TickersClient(BaseClient): + @overload + 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[Union[int, str]] = None, + cik: Optional[int] = None, + date: Optional[str] = None, + active: Optional[bool] = None, + search: Optional[str] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = "ticker", + order: Optional[Union[str, Order]] = "asc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Ticker]: ... + @overload + 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[Union[int, str]] = None, + cik: Optional[int] = None, + date: Optional[str] = None, + active: Optional[bool] = None, + search: Optional[str] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = "ticker", + order: Optional[Union[str, Order]] = "asc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + 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[Union[int, str]] = None, + cik: Optional[int] = None, + date: Optional[str] = None, + active: Optional[bool] = None, + search: Optional[str] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = "ticker", + order: Optional[Union[str, Order]] = "asc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Ticker], HTTPResponse]: ... def list_tickers( self, ticker: Optional[str] = None, @@ -137,6 +231,34 @@ def list_tickers( options=options, ) + @overload + def get_ticker_details( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> TickerDetails: ... + @overload + def get_ticker_details( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_ticker_details( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[TickerDetails, HTTPResponse]: ... def get_ticker_details( self, ticker: Optional[str] = None, @@ -165,6 +287,34 @@ def get_ticker_details( options=options, ) + @overload + def get_ticker_events( + self, + ticker: str, + types: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> TickerChangeResults: ... + @overload + def get_ticker_events( + self, + ticker: str, + types: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_ticker_events( + self, + ticker: str, + types: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[TickerChangeResults, HTTPResponse]: ... def get_ticker_events( self, ticker: str, @@ -191,6 +341,67 @@ def get_ticker_events( options=options, ) + @overload + def list_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, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[TickerNews]: ... + @overload + def list_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, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_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, + 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[TickerNews], HTTPResponse]: ... def list_ticker_news( self, ticker: Optional[str] = None, @@ -232,6 +443,34 @@ def list_ticker_news( options=options, ) + @overload + def get_ticker_types( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[TickerTypes]: ... + @overload + def get_ticker_types( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_ticker_types( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[TickerTypes], HTTPResponse]: ... def get_ticker_types( self, asset_class: Optional[Union[str, AssetClass]] = None, @@ -260,6 +499,31 @@ def get_ticker_types( options=options, ) + @overload + def get_related_companies( + self, + ticker: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> RelatedCompany: ... + @overload + def get_related_companies( + self, + ticker: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_related_companies( + self, + ticker: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[RelatedCompany, HTTPResponse]: ... def get_related_companies( self, ticker: Optional[str] = None, @@ -288,6 +552,70 @@ def get_related_companies( class SplitsClient(BaseClient): + @overload + 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[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, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Split]: ... + @overload + 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[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, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + 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[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, + order: Optional[Union[str, Order]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Split], HTTPResponse]: ... def list_splits( self, ticker: Optional[str] = None, @@ -341,6 +669,7 @@ def list_splits( class DividendsClient(BaseClient): + @overload def list_dividends( self, ticker: Optional[str] = None, @@ -379,14 +708,140 @@ def list_dividends( sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False, + raw: Literal[False] = False, options: Optional[RequestOptionBuilder] = None, - ) -> 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. + ) -> Iterator[Dividend]: ... + @overload + 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[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, + cash_amount_lte: Optional[float] = None, + cash_amount_gt: Optional[float] = None, + cash_amount_gte: Optional[float] = None, + dividend_type: Optional[Union[str, 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: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + 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[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, + cash_amount_lte: Optional[float] = None, + cash_amount_gt: Optional[float] = None, + cash_amount_gte: Optional[float] = None, + dividend_type: Optional[Union[str, 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Dividend], HTTPResponse]: ... + 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[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, + cash_amount_lte: Optional[float] = None, + cash_amount_gt: Optional[float] = None, + cash_amount_gte: Optional[float] = None, + dividend_type: Optional[Union[str, 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, + options: Optional[RequestOptionBuilder] = None, + ) -> 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. @@ -432,6 +887,49 @@ def list_dividends( class ConditionsClient(BaseClient): + @overload + 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: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Condition]: ... + @overload + 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: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Condition], HTTPResponse]: ... def list_conditions( self, asset_class: Optional[Union[str, AssetClass]] = None, @@ -471,6 +969,34 @@ def list_conditions( class ExchangesClient(BaseClient): + @overload + def get_exchanges( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[Exchange]: ... + @overload + def get_exchanges( + self, + asset_class: Optional[Union[str, AssetClass]] = None, + locale: Optional[Union[str, Locale]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[Exchange], HTTPResponse]: ... def get_exchanges( self, asset_class: Optional[Union[str, AssetClass]] = None, @@ -501,6 +1027,34 @@ def get_exchanges( class ContractsClient(BaseClient): + @overload + def get_options_contract( + self, + ticker: str, + as_of: Optional[Union[str, date]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> OptionsContract: ... + @overload + def get_options_contract( + self, + ticker: str, + as_of: Optional[Union[str, date]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_options_contract( + self, + ticker: str, + as_of: Optional[Union[str, date]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[OptionsContract, HTTPResponse]: ... def get_options_contract( self, ticker: str, @@ -529,6 +1083,7 @@ def get_options_contract( options=options, ) + @overload def list_options_contracts( self, underlying_ticker: Optional[str] = None, @@ -553,66 +1108,229 @@ def list_options_contracts( sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False, + raw: Literal[False] = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[OptionsContract], HTTPResponse]: - """ - List historical options contracts. - - :param underlying_ticker: Query for contracts relating to an underlying stock ticker. - :param contract_type: Query by the type of contract. - :param expiration_date: Query by contract expiration with date format YYYY-MM-DD. - :param as_of: Specify a point in time for contracts as of this date with format YYYY-MM-DD. - :param strike_price: Query by strike price of a contract. - :param expired: Query for expired contracts. - :param limit: Limit the number of results returned per-page, 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 options contracts. - """ - url = "/v3/reference/options/contracts" - - return self._paginate( - path=url, - params=self._get_params(self.list_options_contracts, locals()), - raw=raw, - deserializer=OptionsContract.from_dict, - options=options, - ) - - def list_short_interest( + ) -> Iterator[OptionsContract]: ... + @overload + def list_options_contracts( self, - ticker: Optional[str] = None, - days_to_cover: Optional[str] = None, - days_to_cover_lt: Optional[str] = None, - days_to_cover_lte: Optional[str] = None, - days_to_cover_gt: Optional[str] = None, - days_to_cover_gte: Optional[str] = None, - settlement_date: Optional[str] = None, - settlement_date_lt: Optional[str] = None, - settlement_date_lte: Optional[str] = None, - settlement_date_gt: Optional[str] = None, - settlement_date_gte: Optional[str] = None, - avg_daily_volume: Optional[str] = None, - avg_daily_volume_lt: Optional[str] = None, - avg_daily_volume_lte: Optional[str] = None, - avg_daily_volume_gt: Optional[str] = None, - avg_daily_volume_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, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[ShortInterest], HTTPResponse]: - """ - Retrieve short interest data for stocks. - - :param ticker: Filter by the primary ticker symbol. - :param days_to_cover: Filter by the days to cover value. - :param days_to_cover_lt: Filter for days to cover dates less than the provided date. + underlying_ticker: Optional[str] = None, + underlying_ticker_lt: Optional[str] = None, + underlying_ticker_lte: Optional[str] = None, + underlying_ticker_gt: Optional[str] = None, + underlying_ticker_gte: Optional[str] = None, + contract_type: Optional[str] = None, + expiration_date: Optional[Union[str, date]] = None, + expiration_date_lt: Optional[Union[str, date]] = None, + expiration_date_lte: Optional[Union[str, date]] = None, + expiration_date_gt: Optional[Union[str, date]] = None, + expiration_date_gte: Optional[Union[str, date]] = None, + as_of: Optional[Union[str, date]] = None, + strike_price: Optional[float] = None, + strike_price_lt: Optional[float] = None, + strike_price_lte: Optional[float] = None, + strike_price_gt: Optional[float] = None, + strike_price_gte: Optional[float] = None, + expired: 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: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_options_contracts( + self, + underlying_ticker: Optional[str] = None, + underlying_ticker_lt: Optional[str] = None, + underlying_ticker_lte: Optional[str] = None, + underlying_ticker_gt: Optional[str] = None, + underlying_ticker_gte: Optional[str] = None, + contract_type: Optional[str] = None, + expiration_date: Optional[Union[str, date]] = None, + expiration_date_lt: Optional[Union[str, date]] = None, + expiration_date_lte: Optional[Union[str, date]] = None, + expiration_date_gt: Optional[Union[str, date]] = None, + expiration_date_gte: Optional[Union[str, date]] = None, + as_of: Optional[Union[str, date]] = None, + strike_price: Optional[float] = None, + strike_price_lt: Optional[float] = None, + strike_price_lte: Optional[float] = None, + strike_price_gt: Optional[float] = None, + strike_price_gte: Optional[float] = None, + expired: 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[OptionsContract], HTTPResponse]: ... + def list_options_contracts( + self, + underlying_ticker: Optional[str] = None, + underlying_ticker_lt: Optional[str] = None, + underlying_ticker_lte: Optional[str] = None, + underlying_ticker_gt: Optional[str] = None, + underlying_ticker_gte: Optional[str] = None, + contract_type: Optional[str] = None, + expiration_date: Optional[Union[str, date]] = None, + expiration_date_lt: Optional[Union[str, date]] = None, + expiration_date_lte: Optional[Union[str, date]] = None, + expiration_date_gt: Optional[Union[str, date]] = None, + expiration_date_gte: Optional[Union[str, date]] = None, + as_of: Optional[Union[str, date]] = None, + strike_price: Optional[float] = None, + strike_price_lt: Optional[float] = None, + strike_price_lte: Optional[float] = None, + strike_price_gt: Optional[float] = None, + strike_price_gte: Optional[float] = None, + expired: 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[OptionsContract], HTTPResponse]: + """ + List historical options contracts. + + :param underlying_ticker: Query for contracts relating to an underlying stock ticker. + :param contract_type: Query by the type of contract. + :param expiration_date: Query by contract expiration with date format YYYY-MM-DD. + :param as_of: Specify a point in time for contracts as of this date with format YYYY-MM-DD. + :param strike_price: Query by strike price of a contract. + :param expired: Query for expired contracts. + :param limit: Limit the number of results returned per-page, 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 options contracts. + """ + url = "/v3/reference/options/contracts" + + return self._paginate( + path=url, + params=self._get_params(self.list_options_contracts, locals()), + raw=raw, + deserializer=OptionsContract.from_dict, + options=options, + ) + + @overload + def list_short_interest( + self, + ticker: Optional[str] = None, + days_to_cover: Optional[str] = None, + days_to_cover_lt: Optional[str] = None, + days_to_cover_lte: Optional[str] = None, + days_to_cover_gt: Optional[str] = None, + days_to_cover_gte: Optional[str] = None, + settlement_date: Optional[str] = None, + settlement_date_lt: Optional[str] = None, + settlement_date_lte: Optional[str] = None, + settlement_date_gt: Optional[str] = None, + settlement_date_gte: Optional[str] = None, + avg_daily_volume: Optional[str] = None, + avg_daily_volume_lt: Optional[str] = None, + avg_daily_volume_lte: Optional[str] = None, + avg_daily_volume_gt: Optional[str] = None, + avg_daily_volume_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: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[ShortInterest]: ... + @overload + def list_short_interest( + self, + ticker: Optional[str] = None, + days_to_cover: Optional[str] = None, + days_to_cover_lt: Optional[str] = None, + days_to_cover_lte: Optional[str] = None, + days_to_cover_gt: Optional[str] = None, + days_to_cover_gte: Optional[str] = None, + settlement_date: Optional[str] = None, + settlement_date_lt: Optional[str] = None, + settlement_date_lte: Optional[str] = None, + settlement_date_gt: Optional[str] = None, + settlement_date_gte: Optional[str] = None, + avg_daily_volume: Optional[str] = None, + avg_daily_volume_lt: Optional[str] = None, + avg_daily_volume_lte: Optional[str] = None, + avg_daily_volume_gt: Optional[str] = None, + avg_daily_volume_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: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_short_interest( + self, + ticker: Optional[str] = None, + days_to_cover: Optional[str] = None, + days_to_cover_lt: Optional[str] = None, + days_to_cover_lte: Optional[str] = None, + days_to_cover_gt: Optional[str] = None, + days_to_cover_gte: Optional[str] = None, + settlement_date: Optional[str] = None, + settlement_date_lt: Optional[str] = None, + settlement_date_lte: Optional[str] = None, + settlement_date_gt: Optional[str] = None, + settlement_date_gte: Optional[str] = None, + avg_daily_volume: Optional[str] = None, + avg_daily_volume_lt: Optional[str] = None, + avg_daily_volume_lte: Optional[str] = None, + avg_daily_volume_gt: Optional[str] = None, + avg_daily_volume_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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[ShortInterest], HTTPResponse]: ... + def list_short_interest( + self, + ticker: Optional[str] = None, + days_to_cover: Optional[str] = None, + days_to_cover_lt: Optional[str] = None, + days_to_cover_lte: Optional[str] = None, + days_to_cover_gt: Optional[str] = None, + days_to_cover_gte: Optional[str] = None, + settlement_date: Optional[str] = None, + settlement_date_lt: Optional[str] = None, + settlement_date_lte: Optional[str] = None, + settlement_date_gt: Optional[str] = None, + settlement_date_gte: Optional[str] = None, + avg_daily_volume: Optional[str] = None, + avg_daily_volume_lt: Optional[str] = None, + avg_daily_volume_lte: Optional[str] = None, + avg_daily_volume_gt: Optional[str] = None, + avg_daily_volume_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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[ShortInterest], HTTPResponse]: + """ + Retrieve short interest data for stocks. + + :param ticker: Filter by the primary ticker symbol. + :param days_to_cover: Filter by the days to cover value. + :param days_to_cover_lt: Filter for days to cover dates less than the provided date. :param days_to_cover_lte: Filter for days to cover dates less than or equal to the provided date. :param days_to_cover_gt: Filter for days to cover dates greater than the provided date. :param days_to_cover_gte: Filter for days to cover dates greater than or equal to the provided date. @@ -645,6 +1363,7 @@ def list_short_interest( options=options, ) + @overload def list_short_volume( self, ticker: Optional[str] = None, @@ -667,61 +1386,206 @@ def list_short_volume( sort: Optional[Union[str, Sort]] = None, order: Optional[Union[str, Order]] = None, params: Optional[Dict[str, Any]] = None, - raw: bool = False, + raw: Literal[False] = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[ShortVolume], HTTPResponse]: - """ - Retrieve short volume data for stocks. - - :param ticker: Filter by the primary ticker symbol. - :param date: Filter by the date of trade activity (YYYY-MM-DD). - :param date_lt: Filter for dates less than the provided date. - :param date_lte: Filter for dates less than or equal to the provided date. - :param date_gt: Filter for dates greater than the provided date. - :param date_gte: Filter for dates greater than or equal to the provided date. - :param short_volume_ratio: Filter by short volume ratio. - :param short_volume_ratio_lt: Filter for short volume ratio less than the provided date. - :param short_volume_ratio_lte: Filter for short volume ratio less than or equal to the provided date. - :param short_volume_ratio_gt: Filter for short volume ratio greater than the provided date. - :param short_volume_ratio_gte: Filter for short volume ratio greater than or equal to the provided date. - :param total_volume: Filter by total volume. - :param total_volume_lt: Filter for total volume less than the provided date. - :param total_volume_lte: Filter for total volume less than or equal to the provided date. - :param total_volume_gt: Filter for total volume greater than the provided date. - :param total_volume_gte: Filter for total volume greater than or equal to the provided date. - :param limit: Limit the number of results returned. Default 10, max 50000. - :param sort: Field to sort by (e.g., "ticker"). - :param order: Order results based on the sort field ("asc" or "desc"). Default "desc". - :param params: Additional query parameters. - :param raw: Return raw HTTPResponse object if True, else return List[ShortVolume]. - :param options: RequestOptionBuilder for additional headers or params. - :return: An iterator of ShortVolume objects or HTTPResponse if raw=True. - """ - url = "/stocks/v1/short-volume" - - return self._paginate( - path=url, - params=self._get_params(self.list_short_volume, locals()), - deserializer=ShortVolume.from_dict, - raw=raw, - result_key="results", - options=options, - ) - - # Add these functions to financials.py in the FinancialsClient class - - def list_stocks_splits( + ) -> Iterator[ShortVolume]: ... + @overload + def list_short_volume( self, ticker: Optional[str] = None, - ticker_any_of: Optional[str] = None, - ticker_gt: Optional[str] = None, - ticker_gte: Optional[str] = None, - ticker_lt: Optional[str] = None, - ticker_lte: Optional[str] = None, - execution_date: Optional[Union[str, date]] = None, - execution_date_gt: Optional[Union[str, date]] = None, - execution_date_gte: Optional[Union[str, date]] = None, - execution_date_lt: Optional[Union[str, date]] = None, + date: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + short_volume_ratio: Optional[str] = None, + short_volume_ratio_lt: Optional[str] = None, + short_volume_ratio_lte: Optional[str] = None, + short_volume_ratio_gt: Optional[str] = None, + short_volume_ratio_gte: Optional[str] = None, + total_volume: Optional[str] = None, + total_volume_lt: Optional[str] = None, + total_volume_lte: Optional[str] = None, + total_volume_gt: Optional[str] = None, + total_volume_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: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_short_volume( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + short_volume_ratio: Optional[str] = None, + short_volume_ratio_lt: Optional[str] = None, + short_volume_ratio_lte: Optional[str] = None, + short_volume_ratio_gt: Optional[str] = None, + short_volume_ratio_gte: Optional[str] = None, + total_volume: Optional[str] = None, + total_volume_lt: Optional[str] = None, + total_volume_lte: Optional[str] = None, + total_volume_gt: Optional[str] = None, + total_volume_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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[ShortVolume], HTTPResponse]: ... + def list_short_volume( + self, + ticker: Optional[str] = None, + date: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + short_volume_ratio: Optional[str] = None, + short_volume_ratio_lt: Optional[str] = None, + short_volume_ratio_lte: Optional[str] = None, + short_volume_ratio_gt: Optional[str] = None, + short_volume_ratio_gte: Optional[str] = None, + total_volume: Optional[str] = None, + total_volume_lt: Optional[str] = None, + total_volume_lte: Optional[str] = None, + total_volume_gt: Optional[str] = None, + total_volume_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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[ShortVolume], HTTPResponse]: + """ + Retrieve short volume data for stocks. + + :param ticker: Filter by the primary ticker symbol. + :param date: Filter by the date of trade activity (YYYY-MM-DD). + :param date_lt: Filter for dates less than the provided date. + :param date_lte: Filter for dates less than or equal to the provided date. + :param date_gt: Filter for dates greater than the provided date. + :param date_gte: Filter for dates greater than or equal to the provided date. + :param short_volume_ratio: Filter by short volume ratio. + :param short_volume_ratio_lt: Filter for short volume ratio less than the provided date. + :param short_volume_ratio_lte: Filter for short volume ratio less than or equal to the provided date. + :param short_volume_ratio_gt: Filter for short volume ratio greater than the provided date. + :param short_volume_ratio_gte: Filter for short volume ratio greater than or equal to the provided date. + :param total_volume: Filter by total volume. + :param total_volume_lt: Filter for total volume less than the provided date. + :param total_volume_lte: Filter for total volume less than or equal to the provided date. + :param total_volume_gt: Filter for total volume greater than the provided date. + :param total_volume_gte: Filter for total volume greater than or equal to the provided date. + :param limit: Limit the number of results returned. Default 10, max 50000. + :param sort: Field to sort by (e.g., "ticker"). + :param order: Order results based on the sort field ("asc" or "desc"). Default "desc". + :param params: Additional query parameters. + :param raw: Return raw HTTPResponse object if True, else return List[ShortVolume]. + :param options: RequestOptionBuilder for additional headers or params. + :return: An iterator of ShortVolume objects or HTTPResponse if raw=True. + """ + url = "/stocks/v1/short-volume" + + return self._paginate( + path=url, + params=self._get_params(self.list_short_volume, locals()), + deserializer=ShortVolume.from_dict, + raw=raw, + result_key="results", + options=options, + ) + + # Add these functions to financials.py in the FinancialsClient class + + @overload + def list_stocks_splits( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + execution_date: Optional[Union[str, date]] = None, + execution_date_gt: Optional[Union[str, date]] = None, + execution_date_gte: Optional[Union[str, date]] = None, + execution_date_lt: Optional[Union[str, date]] = None, + execution_date_lte: Optional[Union[str, date]] = None, + adjustment_type: Optional[str] = None, + adjustment_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[StockSplit]: ... + @overload + def list_stocks_splits( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + execution_date: Optional[Union[str, date]] = None, + execution_date_gt: Optional[Union[str, date]] = None, + execution_date_gte: Optional[Union[str, date]] = None, + execution_date_lt: Optional[Union[str, date]] = None, + execution_date_lte: Optional[Union[str, date]] = None, + adjustment_type: Optional[str] = None, + adjustment_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_splits( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + execution_date: Optional[Union[str, date]] = None, + execution_date_gt: Optional[Union[str, date]] = None, + execution_date_gte: Optional[Union[str, date]] = None, + execution_date_lt: Optional[Union[str, date]] = None, + execution_date_lte: Optional[Union[str, date]] = None, + adjustment_type: Optional[str] = None, + adjustment_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[StockSplit], HTTPResponse]: ... + def list_stocks_splits( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + execution_date: Optional[Union[str, date]] = None, + execution_date_gt: Optional[Union[str, date]] = None, + execution_date_gte: Optional[Union[str, date]] = None, + execution_date_lt: Optional[Union[str, date]] = None, execution_date_lte: Optional[Union[str, date]] = None, adjustment_type: Optional[str] = None, adjustment_type_any_of: Optional[str] = None, @@ -743,6 +1607,88 @@ def list_stocks_splits( options=options, ) + @overload + def list_stocks_dividends( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ex_dividend_date: Optional[Union[str, date]] = None, + ex_dividend_date_gt: Optional[Union[str, date]] = None, + ex_dividend_date_gte: Optional[Union[str, date]] = None, + ex_dividend_date_lt: Optional[Union[str, date]] = None, + ex_dividend_date_lte: Optional[Union[str, date]] = None, + frequency: Optional[int] = None, + frequency_gt: Optional[int] = None, + frequency_gte: Optional[int] = None, + frequency_lt: Optional[int] = None, + frequency_lte: Optional[int] = None, + distribution_type: Optional[str] = None, + distribution_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[StockDividend]: ... + @overload + def list_stocks_dividends( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ex_dividend_date: Optional[Union[str, date]] = None, + ex_dividend_date_gt: Optional[Union[str, date]] = None, + ex_dividend_date_gte: Optional[Union[str, date]] = None, + ex_dividend_date_lt: Optional[Union[str, date]] = None, + ex_dividend_date_lte: Optional[Union[str, date]] = None, + frequency: Optional[int] = None, + frequency_gt: Optional[int] = None, + frequency_gte: Optional[int] = None, + frequency_lt: Optional[int] = None, + frequency_lte: Optional[int] = None, + distribution_type: Optional[str] = None, + distribution_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_dividends( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ex_dividend_date: Optional[Union[str, date]] = None, + ex_dividend_date_gt: Optional[Union[str, date]] = None, + ex_dividend_date_gte: Optional[Union[str, date]] = None, + ex_dividend_date_lt: Optional[Union[str, date]] = None, + ex_dividend_date_lte: Optional[Union[str, date]] = None, + frequency: Optional[int] = None, + frequency_gt: Optional[int] = None, + frequency_gte: Optional[int] = None, + frequency_lt: Optional[int] = None, + frequency_lte: Optional[int] = None, + distribution_type: Optional[str] = None, + distribution_type_any_of: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[StockDividend], HTTPResponse]: ... def list_stocks_dividends( self, ticker: Optional[str] = None, @@ -781,172 +1727,802 @@ def list_stocks_dividends( options=options, ) + @overload def list_stocks_filings_risk_factors( self, filing_date: Optional[Union[str, date]] = None, - filing_date_any_of: Optional[str] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[RiskFactor]: ... + @overload + def list_stocks_filings_risk_factors( + self, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_risk_factors( + self, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[RiskFactor], HTTPResponse]: ... + def list_stocks_filings_risk_factors( + self, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[RiskFactor], HTTPResponse]: + """ + Get categorized risk factors extracted from 10-K filings (with supporting_text). + """ + url = "/stocks/filings/vX/risk-factors" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_risk_factors, locals()), + result_key="results", + deserializer=RiskFactor.from_dict, + raw=raw, + options=options, + ) + + @overload + def list_stocks_taxonomies_risk_factors( + self, + taxonomy: Optional[float] = None, + taxonomy_gt: Optional[float] = None, + taxonomy_gte: Optional[float] = None, + taxonomy_lt: Optional[float] = None, + taxonomy_lte: Optional[float] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[RiskFactorTaxonomy]: ... + @overload + def list_stocks_taxonomies_risk_factors( + self, + taxonomy: Optional[float] = None, + taxonomy_gt: Optional[float] = None, + taxonomy_gte: Optional[float] = None, + taxonomy_lt: Optional[float] = None, + taxonomy_lte: Optional[float] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_taxonomies_risk_factors( + self, + taxonomy: Optional[float] = None, + taxonomy_gt: Optional[float] = None, + taxonomy_gte: Optional[float] = None, + taxonomy_lt: Optional[float] = None, + taxonomy_lte: Optional[float] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[RiskFactorTaxonomy], HTTPResponse]: ... + def list_stocks_taxonomies_risk_factors( + self, + taxonomy: Optional[float] = None, + taxonomy_gt: Optional[float] = None, + taxonomy_gte: Optional[float] = None, + taxonomy_lt: Optional[float] = None, + taxonomy_lte: Optional[float] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[RiskFactorTaxonomy], HTTPResponse]: + """ + Get the taxonomy/categories used to classify risk factors (kept old name for backward compatibility). + """ + url = "/stocks/taxonomies/vX/risk-factors" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_taxonomies_risk_factors, locals()), + result_key="results", + deserializer=RiskFactorTaxonomy.from_dict, + raw=raw, + options=options, + ) + + @overload + def list_stocks_filings_8k_disclosures( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tertiary_category: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Disclosure]: ... + @overload + def list_stocks_filings_8k_disclosures( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tertiary_category: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_8k_disclosures( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tertiary_category: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Disclosure], HTTPResponse]: ... + def list_stocks_filings_8k_disclosures( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tertiary_category: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Disclosure], HTTPResponse]: + """ + SEC 8-K filing disclosure categorization. A single 8-K filing can produce + multiple rows when it covers multiple disclosure types, each classified into + primary, secondary, and tertiary categories with a supporting text excerpt. + The full classification list is available at /stocks/taxonomies/vX/disclosures. + """ + url = "/stocks/filings/8-K/vX/disclosures" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_8k_disclosures, locals()), + result_key="results", + deserializer=Disclosure.from_dict, + raw=raw, + options=options, + ) + + @overload + def list_stocks_taxonomies_disclosures( + self, + taxonomy: Optional[str] = None, + taxonomy_any_of: Optional[str] = None, + taxonomy_gt: Optional[str] = None, + taxonomy_gte: Optional[str] = None, + taxonomy_lt: Optional[str] = None, + taxonomy_lte: Optional[str] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[DisclosureTaxonomy]: ... + @overload + def list_stocks_taxonomies_disclosures( + self, + taxonomy: Optional[str] = None, + taxonomy_any_of: Optional[str] = None, + taxonomy_gt: Optional[str] = None, + taxonomy_gte: Optional[str] = None, + taxonomy_lt: Optional[str] = None, + taxonomy_lte: Optional[str] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_taxonomies_disclosures( + self, + taxonomy: Optional[str] = None, + taxonomy_any_of: Optional[str] = None, + taxonomy_gt: Optional[str] = None, + taxonomy_gte: Optional[str] = None, + taxonomy_lt: Optional[str] = None, + taxonomy_lte: Optional[str] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[DisclosureTaxonomy], HTTPResponse]: ... + def list_stocks_taxonomies_disclosures( + self, + taxonomy: Optional[str] = None, + taxonomy_any_of: Optional[str] = None, + taxonomy_gt: Optional[str] = None, + taxonomy_gte: Optional[str] = None, + taxonomy_lt: Optional[str] = None, + taxonomy_lte: Optional[str] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[DisclosureTaxonomy], HTTPResponse]: + """ + The complete list of 8-K disclosure classifications used in the 8-K + disclosures endpoint. + """ + url = "/stocks/taxonomies/vX/disclosures" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_taxonomies_disclosures, locals()), + result_key="results", + deserializer=DisclosureTaxonomy.from_dict, + raw=raw, + options=options, + ) + + @overload + def list_stocks_filings_10k_sections( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + section: Optional[str] = None, + section_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "period_end.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FilingSection]: ... + @overload + def list_stocks_filings_10k_sections( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + section: Optional[str] = None, + section_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "period_end.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_10k_sections( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + section: Optional[str] = None, + section_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "period_end.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingSection], HTTPResponse]: ... + def list_stocks_filings_10k_sections( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + section: Optional[str] = None, + section_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "period_end.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingSection], HTTPResponse]: + """ + Get raw text sections from 10-K/10-Q filings (business, risk_factors, etc.). + """ + url = "/stocks/filings/10-K/vX/sections" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_10k_sections, locals()), + result_key="results", + deserializer=FilingSection.from_dict, + raw=raw, + options=options, + ) + + @overload + def list_stocks_filings_8k_text( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, filing_date_gt: Optional[Union[str, date]] = None, filing_date_gte: Optional[Union[str, date]] = None, filing_date_lt: Optional[Union[str, date]] = None, filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Filing8K]: ... + @overload + def list_stocks_filings_8k_text( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, ticker: Optional[str] = None, ticker_any_of: Optional[str] = None, ticker_gt: Optional[str] = None, ticker_gte: Optional[str] = None, ticker_lt: Optional[str] = None, ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_8k_text( + self, cik: Optional[str] = None, cik_any_of: Optional[str] = None, cik_gt: Optional[str] = None, cik_gte: Optional[str] = None, cik_lt: Optional[str] = None, cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, limit: Optional[int] = 100, sort: Optional[Union[str, Sort]] = "filing_date.desc", params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[RiskFactor], HTTPResponse]: - """ - Get categorized risk factors extracted from 10-K filings (with supporting_text). - """ - url = "/stocks/filings/vX/risk-factors" - return self._paginate( - path=url, - params=self._get_params(self.list_stocks_filings_risk_factors, locals()), - result_key="results", - deserializer=RiskFactor.from_dict, - raw=raw, - options=options, - ) - - def list_stocks_taxonomies_risk_factors( - self, - taxonomy: Optional[float] = None, - taxonomy_gt: Optional[float] = None, - taxonomy_gte: Optional[float] = None, - taxonomy_lt: Optional[float] = None, - taxonomy_lte: Optional[float] = None, - primary_category: Optional[str] = None, - primary_category_any_of: Optional[str] = None, - primary_category_gt: Optional[str] = None, - primary_category_gte: Optional[str] = None, - primary_category_lt: Optional[str] = None, - primary_category_lte: Optional[str] = None, - secondary_category: Optional[str] = None, - secondary_category_any_of: Optional[str] = None, - secondary_category_gt: Optional[str] = None, - secondary_category_gte: Optional[str] = None, - secondary_category_lt: Optional[str] = None, - secondary_category_lte: Optional[str] = None, - tertiary_category: Optional[str] = None, - tertiary_category_any_of: Optional[str] = None, - tertiary_category_gt: Optional[str] = None, - tertiary_category_gte: Optional[str] = None, - tertiary_category_lt: Optional[str] = None, - tertiary_category_lte: Optional[str] = None, - limit: Optional[int] = 200, - sort: Optional[Union[str, Sort]] = "taxonomy.desc", - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[RiskFactorTaxonomy], HTTPResponse]: - """ - Get the taxonomy/categories used to classify risk factors (kept old name for backward compatibility). - """ - url = "/stocks/taxonomies/vX/risk-factors" - return self._paginate( - path=url, - params=self._get_params(self.list_stocks_taxonomies_risk_factors, locals()), - result_key="results", - deserializer=RiskFactorTaxonomy.from_dict, - raw=raw, - options=options, - ) - - def list_stocks_filings_8k_disclosures( + ) -> Union[Iterator[Filing8K], HTTPResponse]: ... + def list_stocks_filings_8k_text( self, cik: Optional[str] = None, cik_any_of: Optional[str] = None, - tickers: Optional[str] = None, - tickers_all_of: Optional[str] = None, - tickers_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, filing_date: Optional[Union[str, date]] = None, - filing_date_any_of: Optional[str] = None, filing_date_gt: Optional[Union[str, date]] = None, filing_date_gte: Optional[Union[str, date]] = None, filing_date_lt: Optional[Union[str, date]] = None, filing_date_lte: Optional[Union[str, date]] = None, - tertiary_category: Optional[str] = None, limit: Optional[int] = 100, sort: Optional[Union[str, Sort]] = "filing_date.desc", params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[Disclosure], HTTPResponse]: - """ - SEC 8-K filing disclosure categorization. A single 8-K filing can produce - multiple rows when it covers multiple disclosure types, each classified into - primary, secondary, and tertiary categories with a supporting text excerpt. - The full classification list is available at /stocks/taxonomies/vX/disclosures. - """ - url = "/stocks/filings/8-K/vX/disclosures" - return self._paginate( - path=url, - params=self._get_params(self.list_stocks_filings_8k_disclosures, locals()), - result_key="results", - deserializer=Disclosure.from_dict, - raw=raw, - options=options, - ) - - def list_stocks_taxonomies_disclosures( - self, - taxonomy: Optional[str] = None, - taxonomy_any_of: Optional[str] = None, - taxonomy_gt: Optional[str] = None, - taxonomy_gte: Optional[str] = None, - taxonomy_lt: Optional[str] = None, - taxonomy_lte: Optional[str] = None, - primary_category: Optional[str] = None, - primary_category_any_of: Optional[str] = None, - primary_category_gt: Optional[str] = None, - primary_category_gte: Optional[str] = None, - primary_category_lt: Optional[str] = None, - primary_category_lte: Optional[str] = None, - secondary_category: Optional[str] = None, - secondary_category_any_of: Optional[str] = None, - secondary_category_gt: Optional[str] = None, - secondary_category_gte: Optional[str] = None, - secondary_category_lt: Optional[str] = None, - secondary_category_lte: Optional[str] = None, - tertiary_category: Optional[str] = None, - tertiary_category_any_of: Optional[str] = None, - tertiary_category_gt: Optional[str] = None, - tertiary_category_gte: Optional[str] = None, - tertiary_category_lt: Optional[str] = None, - tertiary_category_lte: Optional[str] = None, - limit: Optional[int] = 200, - sort: Optional[Union[str, Sort]] = "taxonomy.desc", - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[DisclosureTaxonomy], HTTPResponse]: + ) -> Union[Iterator[Filing8K], HTTPResponse]: """ - The complete list of 8-K disclosure classifications used in the 8-K - disclosures endpoint. + Get parsed 8-K filings (earnings, acquisitions, executive changes, etc.). """ - url = "/stocks/taxonomies/vX/disclosures" + url = "/stocks/filings/8-K/vX/text" return self._paginate( path=url, - params=self._get_params(self.list_stocks_taxonomies_disclosures, locals()), + params=self._get_params(self.list_stocks_filings_8k_text, locals()), result_key="results", - deserializer=DisclosureTaxonomy.from_dict, + deserializer=Filing8K.from_dict, raw=raw, options=options, ) - def list_stocks_filings_10k_sections( + @overload + def list_stocks_filings_index( self, cik: Optional[str] = None, cik_any_of: Optional[str] = None, @@ -960,38 +2536,58 @@ def list_stocks_filings_10k_sections( ticker_gte: Optional[str] = None, ticker_lt: Optional[str] = None, ticker_lte: Optional[str] = None, - section: Optional[str] = None, - section_any_of: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, filing_date: Optional[Union[str, date]] = None, filing_date_gt: Optional[Union[str, date]] = None, filing_date_gte: Optional[Union[str, date]] = None, filing_date_lt: Optional[Union[str, date]] = None, filing_date_lte: Optional[Union[str, date]] = None, - period_end: Optional[Union[str, date]] = None, - period_end_gt: Optional[Union[str, date]] = None, - period_end_gte: Optional[Union[str, date]] = None, - period_end_lt: Optional[Union[str, date]] = None, - period_end_lte: Optional[Union[str, date]] = None, - limit: Optional[int] = 100, - sort: Optional[Union[str, Sort]] = "period_end.desc", + limit: Optional[int] = 1000, + sort: Optional[Union[str, Sort]] = "filing_date.desc", params: Optional[Dict[str, Any]] = None, - raw: bool = False, + raw: Literal[False] = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[FilingSection], HTTPResponse]: - """ - Get raw text sections from 10-K/10-Q filings (business, risk_factors, etc.). - """ - url = "/stocks/filings/10-K/vX/sections" - return self._paginate( - path=url, - params=self._get_params(self.list_stocks_filings_10k_sections, locals()), - result_key="results", - deserializer=FilingSection.from_dict, - raw=raw, - options=options, - ) - - def list_stocks_filings_8k_text( + ) -> Iterator[FilingIndex]: ... + @overload + def list_stocks_filings_index( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 1000, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_index( self, cik: Optional[str] = None, cik_any_of: Optional[str] = None, @@ -1016,25 +2612,12 @@ def list_stocks_filings_8k_text( filing_date_gte: Optional[Union[str, date]] = None, filing_date_lt: Optional[Union[str, date]] = None, filing_date_lte: Optional[Union[str, date]] = None, - limit: Optional[int] = 100, + limit: Optional[int] = 1000, sort: Optional[Union[str, Sort]] = "filing_date.desc", params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[Filing8K], HTTPResponse]: - """ - Get parsed 8-K filings (earnings, acquisitions, executive changes, etc.). - """ - url = "/stocks/filings/8-K/vX/text" - return self._paginate( - path=url, - params=self._get_params(self.list_stocks_filings_8k_text, locals()), - result_key="results", - deserializer=Filing8K.from_dict, - raw=raw, - options=options, - ) - + ) -> Union[Iterator[FilingIndex], HTTPResponse]: ... def list_stocks_filings_index( self, cik: Optional[str] = None, @@ -1079,6 +2662,55 @@ def list_stocks_filings_index( options=options, ) + @overload + def list_stocks_filings_13f( + self, + filer_cik: Optional[str] = None, + filer_cik_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Filing13F]: ... + @overload + def list_stocks_filings_13f( + self, + filer_cik: Optional[str] = None, + filer_cik_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_13f( + self, + filer_cik: Optional[str] = None, + filer_cik_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Filing13F], HTTPResponse]: ... def list_stocks_filings_13f( self, filer_cik: Optional[str] = None, @@ -1110,6 +2742,109 @@ def list_stocks_filings_13f( options=options, ) + @overload + def list_stocks_filings_form_3( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FilingForm3]: ... + @overload + def list_stocks_filings_form_3( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_form_3( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingForm3], HTTPResponse]: ... def list_stocks_filings_form_3( self, issuer_cik: Optional[str] = None, @@ -1158,6 +2893,112 @@ def list_stocks_filings_form_3( options=options, ) + @overload + def list_stocks_filings_form_4( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + transaction_code: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[FilingForm4]: ... + @overload + def list_stocks_filings_form_4( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + transaction_code: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_stocks_filings_form_4( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + transaction_code: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingForm4], HTTPResponse]: ... def list_stocks_filings_form_4( self, issuer_cik: Optional[str] = None, diff --git a/massive/rest/snapshot.py b/massive/rest/snapshot.py index 1cf4e368..da1f7483 100644 --- a/massive/rest/snapshot.py +++ b/massive/rest/snapshot.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from .models import ( TickerSnapshot, Direction, @@ -24,6 +24,55 @@ def get_locale(market_type: Union[SnapshotMarketType, str]): class SnapshotClient(BaseClient): + @overload + def list_universal_snapshots( + self, + type: Optional[Union[str, SnapshotMarketType]] = None, + ticker_any_of: Optional[List[str]] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[UniversalSnapshot]: ... + @overload + def list_universal_snapshots( + self, + type: Optional[Union[str, SnapshotMarketType]] = None, + ticker_any_of: Optional[List[str]] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_universal_snapshots( + self, + type: Optional[Union[str, SnapshotMarketType]] = None, + ticker_any_of: Optional[List[str]] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = 10, + sort: Optional[Union[str, Sort]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[UniversalSnapshot], HTTPResponse]: ... def list_universal_snapshots( self, type: Optional[Union[str, SnapshotMarketType]] = None, @@ -72,6 +121,37 @@ def list_universal_snapshots( options=options, ) + @overload + def get_snapshot_all( + self, + market_type: Union[str, SnapshotMarketType], + tickers: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + include_otc: Optional[bool] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[TickerSnapshot]: ... + @overload + def get_snapshot_all( + self, + market_type: Union[str, SnapshotMarketType], + tickers: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + include_otc: Optional[bool] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_all( + self, + market_type: Union[str, SnapshotMarketType], + tickers: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + include_otc: Optional[bool] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[TickerSnapshot], HTTPResponse]: ... def get_snapshot_all( self, market_type: Union[str, SnapshotMarketType], @@ -104,6 +184,37 @@ def get_snapshot_all( options=options, ) + @overload + def get_snapshot_direction( + self, + market_type: Union[str, SnapshotMarketType], + direction: Union[str, Direction], + params: Optional[Dict[str, Any]] = None, + include_otc: Optional[bool] = False, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[TickerSnapshot]: ... + @overload + def get_snapshot_direction( + self, + market_type: Union[str, SnapshotMarketType], + direction: Union[str, Direction], + params: Optional[Dict[str, Any]] = None, + include_otc: Optional[bool] = False, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_direction( + self, + market_type: Union[str, SnapshotMarketType], + direction: Union[str, Direction], + params: Optional[Dict[str, Any]] = None, + include_otc: Optional[bool] = False, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[TickerSnapshot], HTTPResponse]: ... def get_snapshot_direction( self, market_type: Union[str, SnapshotMarketType], @@ -136,6 +247,34 @@ def get_snapshot_direction( options=options, ) + @overload + def get_snapshot_ticker( + self, + market_type: Union[str, SnapshotMarketType], + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> TickerSnapshot: ... + @overload + def get_snapshot_ticker( + self, + market_type: Union[str, SnapshotMarketType], + ticker: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_ticker( + self, + market_type: Union[str, SnapshotMarketType], + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[TickerSnapshot, HTTPResponse]: ... def get_snapshot_ticker( self, market_type: Union[str, SnapshotMarketType], @@ -164,6 +303,34 @@ def get_snapshot_ticker( options=options, ) + @overload + def get_snapshot_option( + self, + underlying_asset: str, + option_contract: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> OptionContractSnapshot: ... + @overload + def get_snapshot_option( + self, + underlying_asset: str, + option_contract: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_option( + self, + underlying_asset: str, + option_contract: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[OptionContractSnapshot, HTTPResponse]: ... def get_snapshot_option( self, underlying_asset: str, @@ -189,6 +356,31 @@ def get_snapshot_option( options=options, ) + @overload + def list_snapshot_options_chain( + self, + underlying_asset: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[OptionContractSnapshot]: ... + @overload + def list_snapshot_options_chain( + self, + underlying_asset: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_snapshot_options_chain( + self, + underlying_asset: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[OptionContractSnapshot], HTTPResponse]: ... def list_snapshot_options_chain( self, underlying_asset: str, @@ -212,6 +404,31 @@ def list_snapshot_options_chain( options=options, ) + @overload + def get_snapshot_crypto_book( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> SnapshotTickerFullBook: ... + @overload + def get_snapshot_crypto_book( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_crypto_book( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[SnapshotTickerFullBook, HTTPResponse]: ... def get_snapshot_crypto_book( self, ticker: str, @@ -237,6 +454,31 @@ def get_snapshot_crypto_book( options=options, ) + @overload + def get_snapshot_indices( + self, + ticker_any_of: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[IndicesSnapshot]: ... + @overload + def get_snapshot_indices( + self, + ticker_any_of: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_snapshot_indices( + self, + ticker_any_of: Optional[Union[str, List[str]]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[IndicesSnapshot], HTTPResponse]: ... def get_snapshot_indices( self, ticker_any_of: Optional[Union[str, List[str]]] = None, @@ -266,6 +508,55 @@ def get_snapshot_indices( options=options, ) + @overload + def list_snapshot_indices( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[Union[str, List[str]]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[IndicesSnapshot]: ... + @overload + def list_snapshot_indices( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[Union[str, List[str]]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_snapshot_indices( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[Union[str, List[str]]] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + order: Optional[Union[str, Order]] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[IndicesSnapshot], HTTPResponse]: ... def list_snapshot_indices( self, ticker: Optional[str] = None, diff --git a/massive/rest/summaries.py b/massive/rest/summaries.py index 6af960eb..33ed7ee7 100644 --- a/massive/rest/summaries.py +++ b/massive/rest/summaries.py @@ -1,12 +1,37 @@ from massive.rest.models.summaries import SummaryResult from .base import BaseClient -from typing import Optional, Any, Dict, List, Union +from typing import Optional, Any, Dict, List, Union, Literal, overload from urllib3 import HTTPResponse from .models.request import RequestOptionBuilder class SummariesClient(BaseClient): + @overload + def get_summaries( + self, + ticker_any_of: Optional[List[str]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> List[SummaryResult]: ... + @overload + def get_summaries( + self, + ticker_any_of: Optional[List[str]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_summaries( + self, + ticker_any_of: Optional[List[str]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[List[SummaryResult], HTTPResponse]: ... def get_summaries( self, ticker_any_of: Optional[List[str]] = None, diff --git a/massive/rest/tmx.py b/massive/rest/tmx.py index dd5687cd..bda13ea1 100644 --- a/massive/rest/tmx.py +++ b/massive/rest/tmx.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from urllib3 import HTTPResponse from datetime import datetime, date @@ -16,6 +16,178 @@ class TmxClient(BaseClient): (aligned with the paths from /tmx/v1/...) """ + @overload + def list_tmx_corporate_events( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + type_gt: Optional[str] = None, + type_gte: Optional[str] = None, + type_lt: Optional[str] = None, + type_lte: Optional[str] = None, + status: Optional[str] = None, + status_any_of: Optional[str] = None, + status_gt: Optional[str] = None, + status_gte: Optional[str] = None, + status_lt: Optional[str] = None, + status_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + tmx_company_id: Optional[int] = None, + tmx_company_id_any_of: Optional[str] = None, + tmx_company_id_gt: Optional[int] = None, + tmx_company_id_gte: Optional[int] = None, + tmx_company_id_lt: Optional[int] = None, + tmx_company_id_lte: Optional[int] = None, + tmx_record_id: Optional[str] = None, + tmx_record_id_any_of: Optional[str] = None, + tmx_record_id_gt: Optional[str] = None, + tmx_record_id_gte: Optional[str] = None, + tmx_record_id_lt: Optional[str] = None, + tmx_record_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[TmxCorporateEvent]: ... + @overload + def list_tmx_corporate_events( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + type_gt: Optional[str] = None, + type_gte: Optional[str] = None, + type_lt: Optional[str] = None, + type_lte: Optional[str] = None, + status: Optional[str] = None, + status_any_of: Optional[str] = None, + status_gt: Optional[str] = None, + status_gte: Optional[str] = None, + status_lt: Optional[str] = None, + status_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + tmx_company_id: Optional[int] = None, + tmx_company_id_any_of: Optional[str] = None, + tmx_company_id_gt: Optional[int] = None, + tmx_company_id_gte: Optional[int] = None, + tmx_company_id_lt: Optional[int] = None, + tmx_company_id_lte: Optional[int] = None, + tmx_record_id: Optional[str] = None, + tmx_record_id_any_of: Optional[str] = None, + tmx_record_id_gt: Optional[str] = None, + tmx_record_id_gte: Optional[str] = None, + tmx_record_id_lt: Optional[str] = None, + tmx_record_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_tmx_corporate_events( + self, + date: Optional[Union[str, date]] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[Union[str, date]] = None, + date_gte: Optional[Union[str, date]] = None, + date_lt: Optional[Union[str, date]] = None, + date_lte: Optional[Union[str, date]] = None, + type: Optional[str] = None, + type_any_of: Optional[str] = None, + type_gt: Optional[str] = None, + type_gte: Optional[str] = None, + type_lt: Optional[str] = None, + type_lte: Optional[str] = None, + status: Optional[str] = None, + status_any_of: Optional[str] = None, + status_gt: Optional[str] = None, + status_gte: Optional[str] = None, + status_lt: Optional[str] = None, + status_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + isin: Optional[str] = None, + isin_any_of: Optional[str] = None, + isin_gt: Optional[str] = None, + isin_gte: Optional[str] = None, + isin_lt: Optional[str] = None, + isin_lte: Optional[str] = None, + trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, + tmx_company_id: Optional[int] = None, + tmx_company_id_any_of: Optional[str] = None, + tmx_company_id_gt: Optional[int] = None, + tmx_company_id_gte: Optional[int] = None, + tmx_company_id_lt: Optional[int] = None, + tmx_company_id_lte: Optional[int] = None, + tmx_record_id: Optional[str] = None, + tmx_record_id_any_of: Optional[str] = None, + tmx_record_id_gt: Optional[str] = None, + tmx_record_id_gte: Optional[str] = None, + tmx_record_id_lt: Optional[str] = None, + tmx_record_id_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[TmxCorporateEvent], HTTPResponse]: ... def list_tmx_corporate_events( self, date: Optional[Union[str, date]] = None, diff --git a/massive/rest/trades.py b/massive/rest/trades.py index 3aad1d0e..e6bf2d9b 100644 --- a/massive/rest/trades.py +++ b/massive/rest/trades.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, Union, Iterator +from typing import Optional, Any, Dict, Union, Iterator, Literal, overload from .models import Trade, LastTrade, CryptoTrade, Sort, Order from urllib3 import HTTPResponse from datetime import datetime, date @@ -8,6 +8,55 @@ class TradesClient(BaseClient): + @overload + def list_trades( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[Trade]: ... + @overload + def list_trades( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def list_trades( + self, + ticker: str, + 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, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Trade], HTTPResponse]: ... def list_trades( self, ticker: str, @@ -49,6 +98,31 @@ def list_trades( options=options, ) + @overload + def get_last_trade( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> LastTrade: ... + @overload + def get_last_trade( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_last_trade( + self, + ticker: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[LastTrade, HTTPResponse]: ... def get_last_trade( self, ticker: str, @@ -75,6 +149,34 @@ def get_last_trade( options=options, ) + @overload + def get_last_crypto_trade( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + raw: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> CryptoTrade: ... + @overload + def get_last_crypto_trade( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + *, + raw: Literal[True], + options: Optional[RequestOptionBuilder] = None, + ) -> HTTPResponse: ... + @overload + def get_last_crypto_trade( + self, + from_: str, + to: str, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[CryptoTrade, HTTPResponse]: ... def get_last_crypto_trade( self, from_: str, diff --git a/massive/rest/vX.py b/massive/rest/vX.py index 91b1e782..dbedad1e 100644 --- a/massive/rest/vX.py +++ b/massive/rest/vX.py @@ -1,5 +1,5 @@ from .base import BaseClient -from typing import Optional, Any, Dict, List, Union, Iterator +from typing import Optional, Any, Dict, List, Union, Iterator, Literal, overload from .models import ( StockFinancial, IPOListing, @@ -13,6 +13,88 @@ class VXClient(BaseClient): + @overload + def list_stock_financials( + self, + ticker: Optional[str] = None, + cik: Optional[str] = None, + company_name: Optional[str] = None, + company_name_search: Optional[str] = None, + sic: Optional[str] = None, + filing_date: Optional[Union[str, int, datetime, date]] = None, + filing_date_lt: Optional[Union[str, int, datetime, date]] = None, + filing_date_lte: Optional[Union[str, int, datetime, date]] = None, + filing_date_gt: Optional[Union[str, int, datetime, date]] = None, + filing_date_gte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gte: Optional[Union[str, int, datetime, date]] = None, + timeframe: Optional[Union[str, Timeframe]] = None, + include_sources: 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: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[StockFinancial]: ... + @overload + def list_stock_financials( + self, + ticker: Optional[str] = None, + cik: Optional[str] = None, + company_name: Optional[str] = None, + company_name_search: Optional[str] = None, + sic: Optional[str] = None, + filing_date: Optional[Union[str, int, datetime, date]] = None, + filing_date_lt: Optional[Union[str, int, datetime, date]] = None, + filing_date_lte: Optional[Union[str, int, datetime, date]] = None, + filing_date_gt: Optional[Union[str, int, datetime, date]] = None, + filing_date_gte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gte: Optional[Union[str, int, datetime, date]] = None, + timeframe: Optional[Union[str, Timeframe]] = None, + include_sources: 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: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_stock_financials( + self, + ticker: Optional[str] = None, + cik: Optional[str] = None, + company_name: Optional[str] = None, + company_name_search: Optional[str] = None, + sic: Optional[str] = None, + filing_date: Optional[Union[str, int, datetime, date]] = None, + filing_date_lt: Optional[Union[str, int, datetime, date]] = None, + filing_date_lte: Optional[Union[str, int, datetime, date]] = None, + filing_date_gt: Optional[Union[str, int, datetime, date]] = None, + filing_date_gte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_lte: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gt: Optional[Union[str, int, datetime, date]] = None, + period_of_report_date_gte: Optional[Union[str, int, datetime, date]] = None, + timeframe: Optional[Union[str, Timeframe]] = None, + include_sources: 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[StockFinancial], HTTPResponse]: ... def list_stock_financials( self, ticker: Optional[str] = None, @@ -76,6 +158,64 @@ def list_stock_financials( options=options, ) + @overload + def list_ipos( + self, + ticker: Optional[str] = None, + us_code: Optional[str] = None, + isin: Optional[str] = None, + listing_date: Optional[str] = None, + listing_date_lt: Optional[str] = None, + listing_date_lte: Optional[str] = None, + listing_date_gt: Optional[str] = None, + listing_date_gte: Optional[str] = None, + ipo_status: 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: Literal[False] = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Iterator[IPOListing]: ... + @overload + def list_ipos( + self, + ticker: Optional[str] = None, + us_code: Optional[str] = None, + isin: Optional[str] = None, + listing_date: Optional[str] = None, + listing_date_lt: Optional[str] = None, + listing_date_lte: Optional[str] = None, + listing_date_gt: Optional[str] = None, + listing_date_gte: Optional[str] = None, + ipo_status: 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: Literal[True], + options: Optional[RequestOptionBuilder] = None + ) -> HTTPResponse: ... + @overload + def list_ipos( + self, + ticker: Optional[str] = None, + us_code: Optional[str] = None, + isin: Optional[str] = None, + listing_date: Optional[str] = None, + listing_date_lt: Optional[str] = None, + listing_date_lte: Optional[str] = None, + listing_date_gt: Optional[str] = None, + listing_date_gte: Optional[str] = None, + ipo_status: 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, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[IPOListing], HTTPResponse]: ... def list_ipos( self, ticker: Optional[str] = None, From b037345f4a67e628c073147ee82fa45ec9439ddc Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:05:19 -0600 Subject: [PATCH 22/22] test: type-check a strict user of the public API Add test_rest/typing_consumer.py, ordinary user code that is checked with mypy --strict but never run. It iterates list_* results, indexes get_* lists, checks that raw=True gives HTTPResponse and a plain bool gives the union, builds models with keyword arguments, pins each corrected hint with assert_type, and keeps code written for earlier releases (isinstance narrowing, an int CUSIP) to show it still checks. make static checks it from inside test_rest/, so massive resolves to the installed package as it does for users. assert_type comes from typing on 3.11+ and from typing_extensions on 3.10 only under mypy, which bundles its stubs; the file is never imported, so nothing new is needed at runtime. AGENTS.md now describes the overload pattern for new endpoints. --- AGENTS.md | 1 + Makefile | 3 + test_rest/typing_consumer.py | 160 +++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 test_rest/typing_consumer.py diff --git a/AGENTS.md b/AGENTS.md index 7da1d1bf..4431e94f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,6 +51,7 @@ The OpenAPI spec at https://api.massive.com/openapi is the source of truth for p - Single-object endpoints are named `get_<...>` and call `self._get(...)`. - Every query param is a keyword argument defaulting to `None`. Write range filters as `x_gt`, `x_gte`, `x_lt`, `x_lte`, `x_any_of`; `_get_params` turns them into `x.gt` and so on. - Always end the signature with `params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None`. + - Precede the method with three `@overload`s that copy its signature, so callers get the precise type for each value of `raw`: `raw: Literal[False] = False` returns the model type (`Iterator[Model]`, `List[Model]` or `Model`); `*, raw: Literal[True]` (keyword-only) returns `HTTPResponse`; and `raw: bool = False` returns the full `Union`. Copy an existing method, such as `list_aggs` in `massive/rest/aggs.py`. 4. **New domain only.** Create a `BaseClient` subclass and add it to `RESTClient`'s bases in `massive/rest/__init__.py`. 5. **Tests, examples, docs.** For core endpoints, add a fixture under `test_rest/mocks/.json`, a test in `test_rest/test_.py`, an example in `examples/rest/`, and an `automethod` entry in `docs/source/*.rst`. 6. Run `make lint` and `make test`. diff --git a/Makefile b/Makefile index b3732930..9173bef6 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ style: ## Check static types static: poetry run mypy massive test_* examples + @# From test_rest/, massive resolves to the installed package, as it does + @# for users, so this also fails if the package stops shipping py.typed. + cd test_rest && poetry run mypy --strict typing_consumer.py ## Check code style and static types lint: style static diff --git a/test_rest/typing_consumer.py b/test_rest/typing_consumer.py new file mode 100644 index 00000000..b640e930 --- /dev/null +++ b/test_rest/typing_consumer.py @@ -0,0 +1,160 @@ +"""Typical user code, checked with ``mypy --strict`` but never run. + +``make static`` checks this file from inside ``test_rest/``, so ``massive`` +resolves to the installed package, as it does for a user. The check fails if: + +- the package stops shipping ``py.typed`` or re-exporting a public name; +- a default call stops returning the model type, so using the result + needs an ``isinstance`` check; +- ``raw=True`` stops returning ``HTTPResponse``; +- a model constructor stops accepting its fields as keywords; +- a corrected hint regresses (``assert_type`` checks the exact type); +- code written for earlier releases, which narrows each result with + ``isinstance`` and passes an ``int`` CUSIP, stops type-checking. + +The file is named so that unittest discovery does not import it. +""" + +import sys +from typing import Iterator, List, Optional, Union + +from urllib3 import HTTPResponse + +if sys.version_info >= (3, 11): + from typing import assert_type +else: + from typing_extensions import assert_type + +from massive import AuthError, BadResponse, RESTClient, WebSocketClient +from massive.rest.models import ( + Agg, + DailyOpenCloseCrypto, + IPOListing, + LastTrade, + PreviousCloseAgg, + ShortInterest, + ShortVolume, + Ticker, +) +from massive.rest.models.economy import FedFundingConditions, TreasuryYield +from massive.websocket.models import CryptoQuote, IndexValue, WebSocketMessage + + +def ticker_symbols(client: RESTClient) -> List[str]: + # list_* yields models; no isinstance check is needed to read them. + return [t.ticker for t in client.list_tickers(market="stocks") if t.ticker] + + +def apple_tickers(client: RESTClient) -> List[Ticker]: + # A CUSIP is a string; an int is still accepted for backward compatibility. + return list(client.list_tickers(cusip="037833100")) + list( + client.list_tickers(cusip=37833100) + ) + + +def first_close(client: RESTClient) -> Optional[float]: + # get_* list endpoints can be indexed directly. + bars = client.get_aggs("AAPL", 1, "day", "2024-01-02", "2024-01-31") + assert_type(bars, List[Agg]) + return bars[0].close if bars else None + + +def previous_close(client: RESTClient) -> Optional[float]: + aggs = client.get_previous_close_agg("AAPL") + assert_type(aggs, List[PreviousCloseAgg]) + return aggs[0].close if aggs else None + + +def last_price(client: RESTClient) -> Optional[float]: + trade = client.get_last_trade("AAPL") + assert_type(trade, LastTrade) + return trade.price + + +def crypto_close(client: RESTClient) -> Optional[float]: + day = client.get_daily_open_close_crypto("BTC", "USD", "2024-01-02") + assert_type(day, DailyOpenCloseCrypto) + return day.close + + +def paginated(client: RESTClient) -> None: + assert_type( + client.list_aggs("AAPL", 1, "day", "2024-01-02", "2024-01-31"), Iterator[Agg] + ) + assert_type(client.list_treasury_yields(), Iterator[TreasuryYield]) + assert_type(client.list_funding_conditions(), Iterator[FedFundingConditions]) + assert_type(client.list_short_interest(ticker="AAPL"), Iterator[ShortInterest]) + assert_type(client.list_short_volume(ticker="AAPL"), Iterator[ShortVolume]) + assert_type(client.vx.list_ipos(), Iterator[IPOListing]) + + +def raw_status(client: RESTClient) -> int: + resp = client.get_aggs("AAPL", 1, "day", "2024-01-02", "2024-01-31", raw=True) + assert_type(resp, HTTPResponse) + assert_type(client.list_tickers(raw=True), HTTPResponse) + assert_type(client.get_last_trade("AAPL", raw=True), HTTPResponse) + return resp.status + + +def raw_flag(client: RESTClient, raw: bool) -> None: + # A non-literal flag gets the full union, as before. + assert_type(client.get_last_trade("AAPL", raw=raw), Union[LastTrade, HTTPResponse]) + assert_type(client.list_tickers(raw=raw), Union[Iterator[Ticker], HTTPResponse]) + + +def ticker_symbols_or_none(client: RESTClient) -> Optional[List[str]]: + try: + return ticker_symbols(client) + except (AuthError, BadResponse): + return None + + +def spread(q: CryptoQuote) -> Optional[float]: + assert_type(q.bid_price, Optional[float]) + assert_type(q.ask_price, Optional[float]) + assert_type(q.ask_size, Optional[float]) + if q.ask_price is None or q.bid_price is None: + return None + return q.ask_price - q.bid_price + + +def index_time_ms(v: IndexValue) -> Optional[int]: + assert_type(v.timestamp, Optional[int]) + return v.timestamp + + +def handle(msgs: List[WebSocketMessage]) -> None: + for m in msgs: + if isinstance(m, CryptoQuote): + spread(m) + elif isinstance(m, IndexValue): + index_time_ms(m) + + +def make_ws_client() -> WebSocketClient: + return WebSocketClient(api_key="key", subscriptions=["XQ.BTC-USD"]) + + +def build_models() -> List[object]: + # Model constructors accept their fields as keywords. + quote = CryptoQuote(pair="BTC-USD", bid_price=33052.79, ask_size=0.601) + value = IndexValue(ticker="I:SPX", value=3988.5, timestamp=1678220098130) + trade = LastTrade(ticker="AAPL", sequence_number=3135876) + return [quote, value, trade] + + +def written_for_earlier_releases(client: RESTClient, raw: bool) -> None: + # Code written when every REST method returned Union[Model, HTTPResponse] + # narrows the result itself. It must keep type-checking. + trade = client.get_last_trade("AAPL") + if isinstance(trade, LastTrade): + print(trade.price) + for t in client.list_tickers(cusip=37833100): + if isinstance(t, Ticker): + print(t.ticker) + resp = client.get_last_trade("AAPL", raw=True) + if isinstance(resp, HTTPResponse): + print(resp.status) + either: Union[LastTrade, HTTPResponse] = client.get_last_trade("AAPL", raw=raw) + tickers: Union[Iterator[Ticker], HTTPResponse] = client.list_tickers() + print(either, tickers)