Skip to content

Commit 9d32924

Browse files
authored
Support v3/snapshot (#444)
1 parent 86e2e06 commit 9d32924

File tree

8 files changed

+521
-6
lines changed

8 files changed

+521
-6
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,19 @@ Once installed run `poetry install` to install the required dependencies. This s
137137

138138
#### Makefile
139139

140-
Our Makefile has the common operations needed when developing on this repo. Running tests and linting can both be run through our Makefile. Just run `make help` to see the list of available commands.
140+
Our Makefile has the common operations needed when developing on this repo. Running tests and linting can both be
141+
run through our Makefile. Just run `make help` to see the list of available commands.
142+
143+
If you're using `pyenv` to manage active Python versions then you might need to launch a Poetry shell before running
144+
Make commands in order to actually use your chosen Python version. This is because Poetry uses the system Python version
145+
by default.
146+
147+
```shell
148+
poetry shell # start shell
149+
poetry install # install deps
150+
151+
make test # run your make commands
152+
```
141153

142154
## Release planning
143155
This client will attempt to follow the release cadence of our API.

docs/source/Models.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,36 @@
33
Models
44
==============================================================
55

6+
==============================================================
7+
Universal Snapshot
8+
==============================================================
9+
.. autoclass:: polygon.rest.models.UniversalSnapshot
10+
11+
==============================================================
12+
Universal Snapshot Session
13+
==============================================================
14+
.. autoclass:: polygon.rest.models.UniversalSnapshotSession
15+
16+
==============================================================
17+
Universal Snapshot Last Quote
18+
==============================================================
19+
.. autoclass:: polygon.rest.models.UniversalSnapshotLastQuote
20+
21+
==============================================================
22+
Universal Snapshot Last Trade
23+
==============================================================
24+
.. autoclass:: polygon.rest.models.UniversalSnapshotLastTrade
25+
26+
==============================================================
27+
Universal Snapshot Details
28+
==============================================================
29+
.. autoclass:: polygon.rest.models.UniversalSnapshotDetails
30+
31+
==============================================================
32+
Universal Snapshot Underlying Asset
33+
==============================================================
34+
.. autoclass:: polygon.rest.models.UniversalSnapshotUnderlyingAsset
35+
636
==============================================================
737
Agg
838
==============================================================

docs/source/Snapshot.rst

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,24 @@ Snapshot
44
=================================
55

66
=================================
7-
Get all snapshots
7+
Get snapshots for all asset types
88
=================================
99

1010
- `Stocks snapshot all tickers`_
11+
- `Options snapshot all tickers`_
1112
- `Forex snapshot all tickers`_
1213
- `Crypto snapshot all tickers`_
1314

15+
.. automethod:: polygon.RESTClient.list_universal_snapshots
16+
17+
=================================
18+
Get all snapshots
19+
=================================
20+
21+
- `Stocks snapshot all tickers (deprecated)`_
22+
- `Forex snapshot all tickers (deprecated)`_
23+
- `Crypto snapshot all tickers (deprecated)`_
24+
1425
.. automethod:: polygon.RESTClient.get_snapshot_all
1526

1627
=================================
@@ -49,9 +60,14 @@ Get crypto L2 book snapshot
4960

5061
.. automethod:: polygon.RESTClient.get_snapshot_crypto_book
5162

52-
.. _Stocks snapshot all tickers: https://polygon.io/docs/stocks/get_v2_snapshot_locale_us_markets_stocks_tickers
53-
.. _Forex snapshot all tickers: https://polygon.io/docs/forex/get_v2_snapshot_locale_global_markets_forex_tickers
54-
.. _Crypto snapshot all tickers: https://polygon.io/docs/crypto/get_v2_snapshot_locale_global_markets_crypto_tickers
63+
.. _Stocks snapshot all tickers: https://polygon.io/docs/stocks/get_v3_snapshot
64+
.. _Options snapshot all tickers: https://polygon.io/docs/options/get_v3_snapshot
65+
.. _Forex snapshot all tickers: https://polygon.io/docs/forex/get_v3_snapshot
66+
.. _Crypto snapshot all tickers:: https://polygon.io/docs/crypto/get_v3_snapshot
67+
.. _Stocks snapshot all tickers (deprecated): https://polygon.io/docs/stocks/get_v2_snapshot_locale_us_markets_stocks_tickers
68+
.. _Options snapshot all tickers (deprecated): https://polygon.io/docs/options/get_v2_snapshot_locale_us_markets_stocks_tickers
69+
.. _Forex snapshot all tickers (deprecated): https://polygon.io/docs/forex/get_v2_snapshot_locale_global_markets_forex_tickers
70+
.. _Crypto snapshot all tickers (deprecated):: https://polygon.io/docs/crypto/get_v2_snapshot_locale_global_markets_crypto_tickers
5571
.. _Stocks snapshot gainers/losers: https://polygon.io/docs/stocks/get_v2_snapshot_locale_us_markets_stocks__direction
5672
.. _Forex snapshot gainers/losers: https://polygon.io/docs/forex/get_v2_snapshot_locale_global_markets_forex__direction
5773
.. _Crypto snapshot gainers/losers: https://polygon.io/docs/crypto/get_v2_snapshot_locale_global_markets_crypto__direction

examples/rest/universal-snapshot.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from typing import cast, Iterator, Union
2+
3+
from urllib3 import HTTPResponse
4+
5+
from polygon import RESTClient
6+
from polygon.rest.models import UniversalSnapshot, SnapshotMarketType
7+
8+
# docs
9+
# https://polygon.io/docs/stocks/get_v3_snapshot
10+
# https://polygon-api-client.readthedocs.io/en/latest/Snapshot.html
11+
12+
# client = RESTClient("XXXXXX") # hardcoded api_key is used
13+
client = RESTClient() # POLYGON_API_KEY environment variable is used
14+
15+
16+
def print_snapshots(iterator: Union[Iterator[UniversalSnapshot], HTTPResponse]):
17+
snapshots = [s for s in iterator]
18+
19+
print(f"count: {len(snapshots)}")
20+
21+
for item in snapshots:
22+
print(item)
23+
24+
25+
# it = client.list_universal_snapshots() # all tickers for all assets types in lexicographical order
26+
27+
it = client.list_universal_snapshots(
28+
ticker_any_of=[
29+
"AAPL",
30+
"O:AAPL230519C00055000",
31+
"DOES_NOT_EXIST",
32+
"X:1INCHUSD",
33+
"C:AEDAUD",
34+
]
35+
)
36+
print_snapshots(it)
37+
38+
it = client.list_universal_snapshots(
39+
market_type=SnapshotMarketType.STOCKS, ticker_gt="A", ticker_lt="AAPL"
40+
)
41+
print_snapshots(it)
42+
43+
it = client.list_universal_snapshots(
44+
market_type=SnapshotMarketType.STOCKS, ticker_gte="AAPL", ticker_lte="ABB"
45+
)
46+
print_snapshots(it)

polygon/rest/models/snapshot.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,145 @@ def from_dict(d):
277277
spread=d.get("spread", None),
278278
updated=d.get("updated", None),
279279
)
280+
281+
282+
@modelclass
283+
class UniversalSnapshotSession:
284+
"""Contains data about the most recent trading session for an asset."""
285+
286+
price: Optional[float] = None
287+
change: Optional[float] = None
288+
change_percent: Optional[float] = None
289+
early_trading_change: Optional[float] = None
290+
early_trading_change_percent: Optional[float] = None
291+
late_trading_change: Optional[float] = None
292+
late_trading_change_percent: Optional[float] = None
293+
open: Optional[float] = None
294+
close: Optional[float] = None
295+
high: Optional[float] = None
296+
low: Optional[float] = None
297+
previous_close: Optional[float] = None
298+
volume: Optional[float] = None
299+
300+
@staticmethod
301+
def from_dict(d):
302+
return UniversalSnapshotSession(**d)
303+
304+
305+
@modelclass
306+
class UniversalSnapshotLastQuote:
307+
"""Contains the most recent quote for an asset."""
308+
309+
ask: Optional[float] = None
310+
ask_size: Optional[float] = None
311+
bid: Optional[float] = None
312+
bid_size: Optional[float] = None
313+
midpoint: Optional[float] = None
314+
exchange: Optional[int] = None
315+
timeframe: Optional[str] = None
316+
last_updated: Optional[int] = None
317+
318+
@staticmethod
319+
def from_dict(d):
320+
return UniversalSnapshotLastQuote(**d)
321+
322+
323+
@modelclass
324+
class UniversalSnapshotLastTrade:
325+
"""Contains the most recent trade for an asset."""
326+
327+
id: Optional[int] = None
328+
price: Optional[float] = None
329+
size: Optional[int] = None
330+
exchange: Optional[int] = None
331+
conditions: Optional[List[int]] = None
332+
timeframe: Optional[str] = None
333+
last_updated: Optional[int] = None
334+
participant_timestamp: Optional[int] = None
335+
sip_timestamp: Optional[int] = None
336+
337+
@staticmethod
338+
def from_dict(d):
339+
return UniversalSnapshotLastTrade(**d)
340+
341+
342+
@modelclass
343+
class UniversalSnapshotUnderlyingAsset:
344+
"""Contains data for the underlying stock in an options contract."""
345+
346+
ticker: Optional[str] = None
347+
price: Optional[float] = None
348+
value: Optional[float] = None
349+
change_to_break_even: Optional[float] = None
350+
timeframe: Optional[str] = None
351+
last_updated: Optional[int] = None
352+
353+
@staticmethod
354+
def from_dict(d):
355+
return UniversalSnapshotUnderlyingAsset(**d)
356+
357+
358+
@modelclass
359+
class UniversalSnapshotDetails:
360+
"""Contains details for an options contract."""
361+
362+
contract_type: Optional[str] = None
363+
exercise_style: Optional[str] = None
364+
expiration_date: Optional[str] = None
365+
shares_per_contract: Optional[float] = None
366+
strike_price: Optional[float] = None
367+
368+
@staticmethod
369+
def from_dict(d):
370+
return UniversalSnapshotDetails(**d)
371+
372+
373+
@modelclass
374+
class UniversalSnapshot:
375+
"""Contains snapshot data for an asset."""
376+
377+
ticker: Optional[str] = None
378+
type: Optional[str] = None
379+
session: Optional[UniversalSnapshotSession] = None
380+
last_quote: Optional[UniversalSnapshotLastQuote] = None
381+
last_trade: Optional[UniversalSnapshotLastTrade] = None
382+
greeks: Optional[Greeks] = None
383+
underlying_asset: Optional[UniversalSnapshotUnderlyingAsset] = None
384+
details: Optional[UniversalSnapshotDetails] = None
385+
break_even_price: Optional[float] = None
386+
implied_volatility: Optional[float] = None
387+
open_interest: Optional[float] = None
388+
market_status: Optional[str] = None
389+
name: Optional[str] = None
390+
error: Optional[str] = None
391+
message: Optional[str] = None
392+
393+
@staticmethod
394+
def from_dict(d):
395+
return UniversalSnapshot(
396+
ticker=d.get("ticker", None),
397+
type=d.get("type", None),
398+
session=None
399+
if "session" not in d
400+
else UniversalSnapshotSession.from_dict(d["session"]),
401+
last_quote=None
402+
if "last_quote" not in d
403+
else UniversalSnapshotLastQuote.from_dict(d["last_quote"]),
404+
last_trade=None
405+
if "last_trade" not in d
406+
else UniversalSnapshotLastTrade.from_dict(d["last_trade"]),
407+
greeks=None if "greeks" not in d else Greeks.from_dict(d["greeks"]),
408+
underlying_asset=None
409+
if "underlying_asset" not in d
410+
else UniversalSnapshotUnderlyingAsset.from_dict(d["underlying_asset"]),
411+
details=None
412+
if "details" not in d
413+
else UniversalSnapshotDetails.from_dict(d["details"]),
414+
break_even_price=d.get("break_even_price", None),
415+
implied_volatility=d.get("implied_volatility", None),
416+
open_interest=d.get("open_interest", None),
417+
market_status=d.get("market_status", None),
418+
name=d.get("name", None),
419+
error=d.get("error", None),
420+
message=d.get("message", None),
421+
)

polygon/rest/snapshot.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
OptionContractSnapshot,
77
SnapshotMarketType,
88
SnapshotTickerFullBook,
9+
UniversalSnapshot,
910
IndicesSnapshot,
1011
)
1112
from urllib3 import HTTPResponse
@@ -21,6 +22,48 @@ def get_locale(market_type: Union[SnapshotMarketType, str]):
2122

2223

2324
class SnapshotClient(BaseClient):
25+
def list_universal_snapshots(
26+
self,
27+
market_type: Optional[Union[str, SnapshotMarketType]] = None,
28+
ticker_any_of: Optional[List[str]] = None,
29+
ticker_lt: Optional[str] = None,
30+
ticker_lte: Optional[str] = None,
31+
ticker_gt: Optional[str] = None,
32+
ticker_gte: Optional[str] = None,
33+
params: Optional[Dict[str, Any]] = None,
34+
raw: bool = False,
35+
options: Optional[RequestOptionBuilder] = None,
36+
) -> Union[Iterator[UniversalSnapshot], HTTPResponse]:
37+
"""
38+
Get snapshots for assets of all types
39+
- https://polygon.io/docs/stocks/get_v3_snapshot
40+
- https://polygon.io/docs/options/get_v3_snapshot
41+
- https://polygon.io/docs/indices/get_v3_snapshot
42+
- https://polygon.io/docs/forex/get_v3_snapshot
43+
- https://polygon.io/docs/crypto/get_v3_snapshot
44+
45+
:param market_type: the type of the asset
46+
:param ticker_any_of: Comma-separated list of tickers, up to a maximum of 250. If no tickers are passed then all
47+
results will be returned in a paginated manner. Warning: The maximum number of characters allowed in a URL
48+
are subject to your technology stack.
49+
:param ticker_lt search for tickers less than
50+
:param ticker_lte search for tickers less than or equal to
51+
:param ticker_gt search for tickers greater than
52+
:param ticker_gte search for tickers greater than or equal to
53+
:param raw: returns the raw HTTP response if true, else the response is deserialized into a structured object
54+
:param options: request options
55+
:return: list of Snapshots
56+
"""
57+
url = f"/v3/snapshot"
58+
return self._paginate(
59+
path=url,
60+
params=self._get_params(self.list_universal_snapshots, locals()),
61+
result_key="results",
62+
deserializer=UniversalSnapshot.from_dict,
63+
raw=raw,
64+
options=options,
65+
)
66+
2467
def get_snapshot_all(
2568
self,
2669
market_type: Union[str, SnapshotMarketType],

0 commit comments

Comments
 (0)