Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edge headers #343

Merged
merged 19 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Requires Python >= 3.8.
See the [Getting Started](https://polygon-api-client.readthedocs.io/en/latest/Getting-Started.html)
section in our docs or view the [examples](./examples) directory.

#### Launchpad Usage

Users of the Launchpad product will need to pass in certain headers in order to make API requests.
Example can be found [here](./examples/launchpad).

## Contributing

If you found a bug or have an idea for a new feature, please first discuss it with us by
Expand Down
49 changes: 49 additions & 0 deletions examples/launchpad/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Launchpad

Users of the Launchpad product will need to pass in certain headers in order to make API requests.

```python

# import RESTClient
from polygon import RESTClient
from polygon.rest.models.request import RequestOptionBuilder

# create client
c = RESTClient(api_key="API_KEY")

# create request options
options = RequestOptionBuilder().edge_headers(
edge_id="YOUR_EDGE_ID", # required
edge_ip_address="IP_ADDRESS", # required
)
# get response
res = c.get_aggs("AAPL", 1, "day", "2022-04-04", "2022-04-04", options=options)

# do something with response

```
Launchpad users can also provide the optional User Agent value describing their Edge User's origination request.

```python

# import RESTClient
from polygon import RESTClient
from polygon.rest.models.request import RequestOptionBuilder

# create client
c = RESTClient(api_key="API_KEY")

# create request options
options = RequestOptionBuilder().edge_headers(
edge_id="YOUR_EDGE_ID", # required
edge_ip_address="IP_ADDRESS" # required
).update_edge_header(
edge_user="EDGE_USER" # optional
)

# get response
res = c.get_aggs("AAPL", 1, "day", "2022-04-04", "2022-04-04", options=options)

# do something with response

```
31 changes: 31 additions & 0 deletions examples/launchpad/launchpad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from polygon import RESTClient
from polygon.rest.models.request import RequestOptionBuilder


def get_list_trades_launchpad():
client = RESTClient()

"""
set headers example:
options = RequestOptionBuilder()
.edge_headers(edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS")
antdjohns marked this conversation as resolved.
Show resolved Hide resolved

update headers example:
options = options.update_edge_header(edge_ip_address="NEW_IP")
"""
antdjohns marked this conversation as resolved.
Show resolved Hide resolved
options = RequestOptionBuilder().edge_headers(
edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS", edge_user="EDGE_USER"
)

trades = []
for t in client.list_trades("AAA", "2022-04-04", limit=5, options=options):
trades.append(t)
print(trades)


def main():
get_list_trades_launchpad()


if __name__ == "__main__":
main()
9 changes: 8 additions & 1 deletion examples/rest/simple-get.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from polygon import RESTClient
from polygon.rest import models

client = RESTClient()

aggs = client.get_aggs("AAPL", 1, "day", "2022-04-04", "2022-04-04")
aggs = client.get_aggs(
"AAPL",
1,
"day",
"2022-04-04",
"2022-04-04",
)
print(aggs)
10 changes: 10 additions & 0 deletions polygon/rest/aggs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from urllib3 import HTTPResponse
from datetime import datetime, date

from .models.request import RequestOptionBuilder


class AggsClient(BaseClient):
def get_aggs(
Expand All @@ -19,6 +21,7 @@ def get_aggs(
limit: Optional[int] = None,
params: Optional[Dict[str, Any]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[List[Agg], HTTPResponse]:
"""
Get aggregate bars for a ticker over a given date range in custom time window sizes.
Expand Down Expand Up @@ -48,6 +51,7 @@ def get_aggs(
result_key="results",
deserializer=Agg.from_dict,
raw=raw,
options=options,
)

# TODO: next breaking change release move "market_type" to be 2nd mandatory
Expand All @@ -60,6 +64,7 @@ def get_grouped_daily_aggs(
raw: bool = False,
market_type: str = "stocks",
include_otc: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[List[GroupedDailyAgg], HTTPResponse]:
"""
Get the daily open, high, low, and close (OHLC) for the entire market.
Expand All @@ -78,6 +83,7 @@ def get_grouped_daily_aggs(
result_key="results",
deserializer=GroupedDailyAgg.from_dict,
raw=raw,
options=options,
)

def get_daily_open_close_agg(
Expand All @@ -87,6 +93,7 @@ def get_daily_open_close_agg(
adjusted: Optional[bool] = None,
params: Optional[Dict[str, Any]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[DailyOpenCloseAgg, HTTPResponse]:
"""
Get the open, close and afterhours prices of a stock symbol on a certain date.
Expand All @@ -105,6 +112,7 @@ def get_daily_open_close_agg(
params=self._get_params(self.get_daily_open_close_agg, locals()),
deserializer=DailyOpenCloseAgg.from_dict,
raw=raw,
options=options,
)

def get_previous_close_agg(
Expand All @@ -113,6 +121,7 @@ def get_previous_close_agg(
adjusted: Optional[bool] = None,
params: Optional[Dict[str, Any]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[PreviousCloseAgg, HTTPResponse]:
"""
Get the previous day's open, high, low, and close (OHLC) for the specified stock ticker.
Expand All @@ -131,4 +140,5 @@ def get_previous_close_agg(
result_key="results",
deserializer=PreviousCloseAgg.from_dict,
raw=raw,
options=options,
)
33 changes: 28 additions & 5 deletions polygon/rest/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Optional, Any, Dict
from datetime import datetime
import pkg_resources # part of setuptools
from .models.request import RequestOptionBuilder
from ..logging import get_logger
import logging
from ..exceptions import AuthError, BadResponse, NoResultsError
Expand Down Expand Up @@ -34,20 +35,24 @@ def __init__(
raise AuthError(
f"Must specify env var POLYGON_API_KEY or pass api_key in constructor"
)

self.API_KEY = api_key
self.BASE = base

self.headers = {
"Authorization": "Bearer " + self.API_KEY,
"User-Agent": f"Polygon.io PythonClient/{version}",
}

# https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html
# https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool
self.client = urllib3.PoolManager(
num_pools=num_pools,
headers={
"Authorization": "Bearer " + self.API_KEY,
"User-Agent": f"Polygon.io PythonClient/{version}",
},
headers=self.headers, # default headers sent with each request.
ca_certs=certifi.where(),
cert_reqs="CERT_REQUIRED",
)

self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout)
self.retries = retries
if verbose:
Expand All @@ -67,16 +72,21 @@ def _get(
result_key: Optional[str] = None,
deserializer=None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Any:
if params is None:
params = {}
params = {str(k): str(v) for k, v in params.items() if v is not None}
logger.debug("_get %s params %s", path, params)

option = options if options is not None else RequestOptionBuilder()

resp = self.client.request(
"GET",
self.BASE + path,
fields=params,
retries=self.retries,
headers=self._concat_headers(option.headers),
)

if resp.status != 200:
Expand Down Expand Up @@ -147,12 +157,18 @@ def _get_params(

return params

def _concat_headers(self, headers: Optional[Dict[str, str]]) -> Dict[str, str]:
if headers is None:
return {**self.headers}
antdjohns marked this conversation as resolved.
Show resolved Hide resolved
return {**headers, **self.headers}

def _paginate_iter(
self,
path: str,
params: dict,
deserializer,
result_key: str = "results",
options: Optional[RequestOptionBuilder] = None,
):
while True:
resp = self._get(
Expand All @@ -161,6 +177,7 @@ def _paginate_iter(
deserializer=deserializer,
result_key=result_key,
raw=True,
options=options,
)
decoded = self._decode(resp)
for t in decoded[result_key]:
Expand All @@ -178,15 +195,21 @@ def _paginate(
raw: bool,
deserializer,
result_key: str = "results",
options: Optional[RequestOptionBuilder] = None,
):
if raw:
return self._get(
path=path, params=params, deserializer=deserializer, raw=True
path=path,
params=params,
deserializer=deserializer,
raw=True,
options=options,
)

return self._paginate_iter(
path=path,
params=params,
deserializer=deserializer,
result_key=result_key,
options=options,
)
10 changes: 10 additions & 0 deletions polygon/rest/indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from urllib3 import HTTPResponse
from datetime import datetime, date

from .models.request import RequestOptionBuilder


class IndicatorsClient(BaseClient):
def get_sma(
Expand All @@ -29,6 +31,7 @@ def get_sma(
params: Optional[Dict[str, Any]] = None,
series_type: Optional[Union[str, SeriesType]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[SMAIndicatorResults, HTTPResponse]:
"""
Get SMA values for a given ticker over a given range with the specified parameters
Expand Down Expand Up @@ -62,6 +65,7 @@ def get_sma(
result_key="results",
deserializer=SMAIndicatorResults.from_dict,
raw=raw,
options=options,
)

def get_ema(
Expand All @@ -80,6 +84,7 @@ def get_ema(
params: Optional[Dict[str, Any]] = None,
series_type: Optional[Union[str, SeriesType]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[EMAIndicatorResults, HTTPResponse]:
"""
Get EMA values for a given ticker over a given range with the specified parameters
Expand Down Expand Up @@ -113,6 +118,7 @@ def get_ema(
result_key="results",
deserializer=EMAIndicatorResults.from_dict,
raw=raw,
options=options,
)

def get_rsi(
Expand All @@ -131,6 +137,7 @@ def get_rsi(
params: Optional[Dict[str, Any]] = None,
series_type: Optional[Union[str, SeriesType]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[RSIIndicatorResults, HTTPResponse]:
"""
Get RSI values for a given ticker over a given range with the specified parameters
Expand Down Expand Up @@ -164,6 +171,7 @@ def get_rsi(
result_key="results",
deserializer=RSIIndicatorResults.from_dict,
raw=raw,
options=options,
)

def get_macd(
Expand All @@ -184,6 +192,7 @@ def get_macd(
params: Optional[Dict[str, Any]] = None,
series_type: Optional[Union[str, SeriesType]] = None,
raw: bool = False,
options: Optional[RequestOptionBuilder] = None,
) -> Union[MACDIndicatorResults, HTTPResponse]:
"""
Get MACD values for a given ticker over a given range with the specified parameters
Expand Down Expand Up @@ -218,4 +227,5 @@ def get_macd(
result_key="results",
deserializer=MACDIndicatorResults.from_dict,
raw=raw,
options=options,
)
6 changes: 6 additions & 0 deletions polygon/rest/models/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,9 @@ class SeriesType(Enum):
CLOSE = "close"
HIGH = "high"
LOW = "low"


class LaunchPadOptions(Enum):
X_POLYGON_EDGE_ID = "X-Polygon-Edge-ID"
X_POLYGON_IP_ADDRESS = "X-Polygon-Edge-IP-Address"
X_POLYGON_EDGE_USER_AGENT = "X-Polygon-Edge-User-Agent"
Loading