summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanglewood <85772166+deeleeramone@users.noreply.github.com>2024-03-18 14:38:34 -0700
committerGitHub <noreply@github.com>2024-03-18 21:38:34 +0000
commit9dcad4472b1df380af6e4b78976e5603ddcb8790 (patch)
tree9ba4e613c2775ddba3b22d7fb040317530fd0726
parentc5c7adeef19e357911f21dea0601219dcb2f9e24 (diff)
[Feature] Add Intrinio to `obb.equity.market_snapshots()` (#6232)
* add intrinio to equity market snapshots * field definitions * map date * static files * black * date check * test cassette * pylint --------- Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
-rw-r--r--openbb_platform/extensions/equity/integration/test_equity_api.py3
-rw-r--r--openbb_platform/extensions/equity/integration/test_equity_python.py3
-rw-r--r--openbb_platform/openbb/assets/reference.json85
-rw-r--r--openbb_platform/openbb/package/equity.py40
-rw-r--r--openbb_platform/openbb/package/equity_price.py8
-rw-r--r--openbb_platform/providers/intrinio/openbb_intrinio/__init__.py2
-rw-r--r--openbb_platform/providers/intrinio/openbb_intrinio/models/market_snapshots.py255
-rw-r--r--openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_market_snapshots_fetcher.yaml4380
-rw-r--r--openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py16
9 files changed, 4775 insertions, 17 deletions
diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py
index afe8fdeb22d..9b60930f4b5 100644
--- a/openbb_platform/extensions/equity/integration/test_equity_api.py
+++ b/openbb_platform/extensions/equity/integration/test_equity_api.py
@@ -1663,7 +1663,8 @@ def test_equity_darkpool_otc(params, headers):
"params",
[
({"provider": "fmp", "market": "euronext"}),
- # ({"provider": "polygon"}), # premium endpoint
+ ({"provider": "polygon"}),
+ ({"provider": "intrinio", "date": "2022-06-30"}),
],
)
@pytest.mark.integration
diff --git a/openbb_platform/extensions/equity/integration/test_equity_python.py b/openbb_platform/extensions/equity/integration/test_equity_python.py
index 71400e8409a..68f8daffef2 100644
--- a/openbb_platform/extensions/equity/integration/test_equity_python.py
+++ b/openbb_platform/extensions/equity/integration/test_equity_python.py
@@ -1559,7 +1559,8 @@ def test_equity_darkpool_otc(params, obb):
"params",
[
({"provider": "fmp", "market": "euronext"}),
- # ({"provider": "polygon"}), # premium endpoint
+ ({"provider": "polygon"}),
+ ({"provider": "intrinio", "date": "2022-06-30"}),
],
)
@pytest.mark.integration
diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json
index fd9de6d9d5d..96162f453bf 100644
--- a/openbb_platform/openbb/assets/reference.json
+++ b/openbb_platform/openbb/assets/reference.json
@@ -18912,7 +18912,7 @@
"standard": [
{
"name": "provider",
- "type": "Literal['fmp', 'polygon']",
+ "type": "Literal['fmp', 'intrinio', 'polygon']",
"description": "The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default.",
"default": "fmp",
"optional": true
@@ -18927,6 +18927,15 @@
"optional": true
}
],
+ "intrinio": [
+ {
+ "name": "date",
+ "type": "Union[Union[date, datetime, str], str]",
+ "description": "The date of the data. Can be a datetime or an ISO datetime string. Historical data appears to go back to mid-June 2022. Example: '2024-03-08T12:15:00+0400'",
+ "default": null,
+ "optional": true
+ }
+ ],
"polygon": []
},
"returns": {
@@ -18938,7 +18947,7 @@
},
{
"name": "provider",
- "type": "Optional[Literal['fmp', 'polygon']]",
+ "type": "Optional[Literal['fmp', 'intrinio', 'polygon']]",
"description": "Provider name."
},
{
@@ -19124,6 +19133,78 @@
"optional": true
}
],
+ "intrinio": [
+ {
+ "name": "last_price",
+ "type": "float",
+ "description": "The last trade price.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "last_size",
+ "type": "int",
+ "description": "The last trade size.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "last_volume",
+ "type": "int",
+ "description": "The last trade volume.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "last_trade_timestamp",
+ "type": "datetime",
+ "description": "The timestamp of the last trade.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "bid_size",
+ "type": "int",
+ "description": "The size of the last bid price. Bid price and size is not always available.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "bid_price",
+ "type": "float",
+ "description": "The last bid price. Bid price and size is not always available.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "ask_price",
+ "type": "float",
+ "description": "The last ask price. Ask price and size is not always available.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "ask_size",
+ "type": "int",
+ "description": "The size of the last ask price. Ask price and size is not always available.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "last_bid_timestamp",
+ "type": "datetime",
+ "description": "The timestamp of the last bid price. Bid price and size is not always available.",
+ "default": null,
+ "optional": true
+ },
+ {
+ "name": "last_ask_timestamp",
+ "type": "datetime",
+ "description": "The timestamp of the last ask price. Ask price and size is not always available.",
+ "default": null,
+ "optional": true
+ }
+ ],
"polygon": [
{
"name": "vwap",
diff --git a/openbb_platform/openbb/package/equity.py b/openbb_platform/openbb/package/equity.py
index f36be502f66..b1700d93dd4 100644
--- a/openbb_platform/openbb/package/equity.py
+++ b/openbb_platform/openbb/package/equity.py
@@ -77,7 +77,7 @@ class ROUTER_equity(Container):
def market_snapshots(
self,
provider: Annotated[
- Optional[Literal["fmp", "polygon"]],
+ Optional[Literal["fmp", "intrinio", "polygon"]],
OpenBBCustomParameter(
description="The provider to use for the query, by default None.\n If None, the provider specified in defaults is selected or 'fmp' if there is\n no default."
),
@@ -88,19 +88,21 @@ class ROUTER_equity(Container):
Parameters
----------
- provider : Optional[Literal['fmp', 'polygon']]
+ provider : Optional[Literal['fmp', 'intrinio', 'polygon']]
The provider to use for the query, by default None.
If None, the provider specified in defaults is selected or 'fmp' if there is
no default.
market : Literal['amex', 'ams', 'ase', 'asx', 'ath', 'bme', 'bru', 'bud', 'bue', 'cai', 'cnq', 'cph', 'dfm', 'doh', 'etf', 'euronext', 'hel', 'hkse', 'ice', 'iob', 'ist', 'jkt', 'jnb', 'jpx', 'kls', 'koe', 'ksc', 'kuw', 'lse', 'mex', 'mutual_fund', 'nasdaq', 'neo', 'nse', 'nyse', 'nze', 'osl', 'otc', 'pnk', 'pra', 'ris', 'sao', 'sau', 'set', 'sgo', 'shh', 'shz', 'six', 'sto', 'tai', 'tlv', 'tsx', 'two', 'vie', 'wse', 'xetra']
The market to fetch data for. (provider: fmp)
+ date : Optional[Union[datetime.date, datetime.datetime, str]]
+ The date of the data. Can be a datetime or an ISO datetime string. Historical data appears to go back to mid-June 2022. Example: '2024-03-08T12:15:00+0400' (provider: intrinio)
Returns
-------
OBBject
results : List[MarketSnapshots]
Serializable results.
- provider : Optional[Literal['fmp', 'polygon']]
+ provider : Optional[Literal['fmp', 'intrinio', 'polygon']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
@@ -130,7 +132,8 @@ class ROUTER_equity(Container):
change_percent : Optional[float]
The change in price from the previous close, as a normalized percent.
last_price : Optional[float]
- The last price of the stock. (provider: fmp)
+ The last price of the stock. (provider: fmp);
+ The last trade price. (provider: intrinio)
last_price_timestamp : Optional[Union[date, datetime]]
The timestamp of the last price. (provider: fmp)
ma50 : Optional[float]
@@ -157,6 +160,27 @@ class ROUTER_equity(Container):
The exchange of the stock. (provider: fmp)
earnings_date : Optional[Union[date, datetime]]
The upcoming earnings announcement date. (provider: fmp)
+ last_size : Optional[int]
+ The last trade size. (provider: intrinio)
+ last_volume : Optional[int]
+ The last trade volume. (provider: intrinio)
+ last_trade_timestamp : Optional[datetime]
+ The timestamp of the last trade. (provider: intrinio);
+ The last trade timestamp. (provider: polygon)
+ bid_size : Optional[int]
+ The size of the last bid price. Bid price and size is not always available. (provider: intrinio);
+ The current bid size. (provider: polygon)
+ bid_price : Optional[float]
+ The last bid price. Bid price and size is not always available. (provider: intrinio)
+ ask_price : Optional[float]
+ The last ask price. Ask price and size is not always available. (provider: intrinio)
+ ask_size : Optional[int]
+ The size of the last ask price. Ask price and size is not always available. (provider: intrinio);
+ The current ask size. (provider: polygon)
+ last_bid_timestamp : Optional[datetime]
+ The timestamp of the last bid price. Bid price and size is not always available. (provider: intrinio)
+ last_ask_timestamp : Optional[datetime]
+ The timestamp of the last ask price. Ask price and size is not always available. (provider: intrinio)
vwap : Optional[float]
The volume weighted average price of the stock on the current trading day. (provider: polygon)
prev_open : Optional[float]
@@ -173,10 +197,6 @@ class ROUTER_equity(Container):
The last time the data was updated. (provider: polygon)
bid : Optional[float]
The current bid price. (provider: polygon)
- bid_size : Optional[int]
- The current bid size. (provider: polygon)
- ask_size : Optional[int]
- The current ask size. (provider: polygon)
ask : Optional[float]
The current ask price. (provider: polygon)
quote_timestamp : Optional[datetime]
@@ -189,8 +209,6 @@ class ROUTER_equity(Container):
The last trade condition codes. (provider: polygon)
last_trade_exchange : Optional[int]
The last trade exchange ID code. (provider: polygon)
- last_trade_timestamp : Optional[datetime]
- The last trade timestamp. (provider: polygon)
Examples
--------
@@ -205,7 +223,7 @@ class ROUTER_equity(Container):
"provider": self._get_provider(
provider,
"/equity/market_snapshots",
- ("fmp", "polygon"),
+ ("fmp", "intrinio", "polygon"),
)
},
standard_params={},
diff --git a/openbb_platform/openbb/package/equity_price.py b/openbb_platform/openbb/package/equity_price.py
index 52e106d9081..e0baa4ecd7a 100644
--- a/openbb_platform/openbb/package/equity_price.py
+++ b/openbb_platform/openbb/package/equity_price.py
@@ -354,6 +354,8 @@ class ROUTER_equity_price(Container):
PricePerformance
----------------
+ symbol : Optional[str]
+ Symbol representing the entity requested in the data.
one_day : Optional[float]
One-day return.
wtd : Optional[float]
@@ -374,16 +376,18 @@ class ROUTER_equity_price(Container):
Year to date return.
one_year : Optional[float]
One-year return.
+ two_year : Optional[float]
+ Two-year return.
three_year : Optional[float]
Three-year return.
+ four_year : Optional[float]
+ Four-year
five_year : Optional[float]
Five-year return.
ten_year : Optional[float]
Ten-year return.
max : Optional[float]
Return from the beginning of the time series.
- symbol : Optional[str]
- The ticker symbol. (provider: fmp)
Examples
--------
diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py
index 554cc5b8687..49af00c352b 100644
--- a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py
+++ b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py
@@ -34,6 +34,7 @@ from openbb_intrinio.models.insider_trading import IntrinioInsiderTradingFetcher
# )
from openbb_intrinio.models.key_metrics import IntrinioKeyMetricsFetcher
from openbb_intrinio.models.latest_attributes import IntrinioLatestAttributesFetcher
+from openbb_intrinio.models.market_snapshots import IntrinioMarketSnapshotsFetcher
from openbb_intrinio.models.options_chains import IntrinioOptionsChainsFetcher
from openbb_intrinio.models.options_unusual import IntrinioOptionsUnusualFetcher
from openbb_intrinio.models.reported_financials import IntrinioReportedFinancialsFetcher
@@ -76,6 +77,7 @@ intrinio_provider = Provider(
"KeyMetrics": IntrinioKeyMetricsFetcher,
"LatestAttributes": IntrinioLatestAttributesFetcher,
"MarketIndices": IntrinioIndexHistoricalFetcher,
+ "MarketSnapshots": IntrinioMarketSnapshotsFetcher,
"OptionsChains": IntrinioOptionsChainsFetcher,
"OptionsUnusual": IntrinioOptionsUnusualFetcher,
"ReportedFinancials": IntrinioReportedFinancialsFetcher,
diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/models/market_snapshots.py b/openbb_platform/providers/intrinio/openbb_intrinio/models/market_snapshots.py
new file mode 100644
index 00000000000..2cb54996683
--- /dev/null
+++ b/openbb_platform/providers/intrinio/openbb_intrinio/models/market_snapshots.py
@@ -0,0 +1,255 @@
+"""Intrinio Market Snapshots Model."""
+
+# pylint: disable=unused-argument
+
+import asyncio
+import gzip
+from datetime import (
+ date as dateType,
+ datetime,
+)
+from io import BytesIO
+from typing import Any, Dict, List, Optional, Union
+
+from openbb_core.provider.abstract.fetcher import Fetcher
+from openbb_core.provider.standard_models.market_snapshots import (
+ MarketSnapshotsData,
+ MarketSnapshotsQueryParams,
+)
+from openbb_core.provider.utils.helpers import amake_request
+from pandas import DataFrame, notna, read_csv, to_datetime
+from pydantic import Field
+from pytz import timezone
+
+
+class IntrinioMarketSnapshotsQueryParams(MarketSnapshotsQueryParams):
+ """Intrinio Market Snapshots Query.
+
+ Source: https://docs.intrinio.com/documentation/web_api/get_security_snapshots_v2
+ """
+
+ date: Optional[Union[dateType, datetime, str]] = Field(
+ default=None,
+ description="The date of the data. Can be a datetime or an ISO datetime string."
+ + " Historical data appears to go back to mid-June 2022."
+ + " Example: '2024-03-08T12:15:00+0400'",
+ )
+
+
+class IntrinioMarketSnapshotsData(MarketSnapshotsData):
+ """Intrinio Market Snapshots Data."""
+
+ __alias_dict__ = {
+ "last_price": "trade_price",
+ "last_size": "trade_size",
+ "last_volume": "total_trade_volume",
+ }
+
+ last_price: Optional[float] = Field(
+ default=None,
+ description="The last trade price.",
+ )
+ last_size: Optional[int] = Field(
+ default=None,
+ description="The last trade size.",
+ )
+ last_volume: Optional[int] = Field(
+ default=None,
+ description="The last trade volume.",
+ )
+ last_trade_timestamp: Optional[datetime] = Field(
+ default=None,
+ description="The timestamp of the last trade.",
+ )
+ bid_size: Optional[int] = Field(
+ default=None,
+ description="The size of the last bid price. Bid price and size is not always available.",
+ )
+ bid_price: Optional[float] = Field(
+ default=None,
+ description="The last bid price. Bid price and size is not always available.",
+ )
+ ask_price: Optional[float] = Field(
+ default=None,
+ description="The last ask price. Ask price and size is not always available.",
+ )
+ ask_size: Optional[int] = Field(
+ default=None,
+ description="The size of the last ask price. Ask price and size is not always available.",
+ )
+ last_bid_timestamp: Optional[datetime] = Field(
+ default=None,
+ description="The timestamp of the last bid price. Bid price and size is not always available.",
+ )
+ last_ask_timestamp: Optional[datetime] = Field(
+ default=None,
+ description="The timestamp of the last ask price. Ask price and size is not always available.",
+ )
+
+
+class IntrinioMarketSnapshotsFetcher(
+ Fetcher[
+ IntrinioMarketSnapshotsQueryParams,
+ List[IntrinioMarketSnapshotsData],
+ ]
+):
+ """Transform the query, extract and transform the data from the Intrinio endpoints."""
+
+ @staticmethod
+ def transform_query(params: Dict[str, Any]) -> IntrinioMarketSnapshotsQueryParams:
+ """Transform the query params."""
+ transformed_params = params
+
+ if "date" in transformed_params:
+ if isinstance(transformed_params["date"], datetime):
+ dt = transformed_params["date"]
+ dt = dt.astimezone(tz=timezone("America/New_York"))
+ if isinstance(transformed_params["date"], dateType):
+ dt = transformed_params["date"]
+ if isinstance(dt, dateType):
+ dt = datetime(
+ dt.year,
+ dt.month,
+ dt.day,
+ 20,
+ 0,
+ 0,
+ 0,
+ tzinfo=timezone("America/New_York"),
+ )
+ if isinstance(transformed_params["date"], str):
+ dt = datetime.fromisoformat(transformed_params["date"])
+ else:
+ try:
+ dt = datetime.fromisoformat(str(transformed_params["date"])) # type: ignore
+ except ValueError as exc:
+ raise ValueError(
+ "Invalid date format. Please use '2024-03-08T12:15-0400'."
+ ) from exc
+
+ transformed_params["date"] = (
+ dt.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
+ .replace("+", "-")
+ .replace("T00:", "T20:")
+ if isinstance(dt, datetime)
+ else dt
+ )
+ return IntrinioMarketSnapshotsQueryParams(**transformed_params)
+
+ @staticmethod
+ async def aextract_data(
+ query: IntrinioMarketSnapshotsQueryParams,
+ credentials: Optional[Dict[str, str]],
+ **kwargs: Any,
+ ) -> List[Dict]:
+ """Return the raw data from the Intrinio endpoint."""
+
+ api_key = credentials.get("intrinio_api_key") if credentials else ""
+
+ # This gets the URL to the actual file.
+ url = f"https://api-v2.intrinio.com/securities/snapshots?api_key={api_key}"
+ if query.date:
+ url += f"&at_datetime={query.date}"
+
+ response = await amake_request(url, **kwargs)
+
+ if isinstance(response, dict) and "error" in response:
+ raise RuntimeError(
+ f"Error: {response.get('error')}. Message: {response.get('message')}"
+ )
+ urls = []
+ # Get the URL to the CSV file.
+ if response.get("snapshots"): # type: ignore
+ for d in response["snapshots"]: # type: ignore
+ if d.get("files"):
+ for f in d["files"]:
+ if f.get("url"):
+ urls.append(f.get("url"))
+ if not urls:
+ raise RuntimeError("No snapshots found.")
+
+ results = []
+
+ async def response_callback(response, _):
+ """Response Callback."""
+ return await response.read()
+
+ async def get_csv(url):
+ """Return the CSV data."""
+ response = await amake_request(
+ url, response_callback=response_callback, **kwargs
+ )
+ df = DataFrame()
+ if isinstance(response, bytes):
+ file = gzip.decompress(response)
+ df = read_csv(BytesIO(file))
+ if df.empty:
+ raise RuntimeError("Empty CSV file")
+ df.columns = df.columns.str.lower().str.replace(" ", "_")
+
+ df = (
+ df.dropna(how="all", axis=1)
+ .dropna(subset=["trade_price", "last_trade_timestamp", "symbol"])
+ .sort_values("last_trade_timestamp", ascending=False)
+ )[
+ [
+ "symbol",
+ "trade_price",
+ "trade_size",
+ "total_trade_volume",
+ "bid_size",
+ "bid_price",
+ "ask_price",
+ "ask_size",
+ "last_trade_timestamp",
+ "last_bid_timestamp",
+ "last_ask_timestamp",
+ ]
+ ]
+
+ for col in [
+ "last_trade_timestamp",
+ "last_bid_timestamp",
+ "last_ask_timestamp",
+ ]:
+ df[col] = (
+ to_datetime(
+ df[col].apply(
+ lambda x: (
+ datetime.fromtimestamp(x, tz=timezone("UTC"))
+ if notna(x)
+ else x
+ )
+ )
+ )
+ .dt.tz_convert("America/New_York")
+ .dt.floor("S")
+ )
+
+ for c in ["trade_size", "total_trade_volume"]:
+ df[c] = df[c].astype("int64")
+
+ # Clear out NaN and non-numeric values with None.
+ df = (
+ df.replace("Max", None)
+ .replace("Min", None)
+ .replace(0, None)
+ .fillna("N/A")
+ .replace("N/A", None)
+ )
+
+ if len(df) > 0:
+ results.extend(df.reset_index(drop=True).to_dict(orient="records"))
+
+ await asyncio.gather(*[get_csv(url) for url in urls])
+
+ return results
+
+ @staticmethod
+ def transform_data(
+ query: IntrinioMarketSnapshotsQueryParams,
+ data: List[Dict],
+ **kwargs: Any,
+ ) -> List[IntrinioMarketSnapshotsData]:
+ """Return the transformed data."""
+ return [IntrinioMarketSnapshotsData.model_validate(d) for d in data]
diff --git a/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_market_snapshots_fetcher.yaml b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_market_snapshots_fetcher.yaml
new file mode 100644
index 00000000000..655c9db02c7
--- /dev/null
+++ b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_market_snapshots_fetcher.yaml
@@ -0,0 +1,4380 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Accept:
+ - application/json
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ method: GET
+ uri: https://api-v2.intrinio.com/securities/snapshots?api_key=MOCK_API_KEY&at_datetime=2022-06-30T20%3A00%3A00.000000
+ response:
+ body:
+ string: !!binary |
+ H4sIAIYs9mUAA1RR/UsjQQz9V2TA35w2zexMdWE5Ru/OqvgB27PeF0fsZtuB7oczsygt/u83Ih49
+ EkIgLy8vvJ0ILfVh3cUg8p87EV3DIhcIiBKMVHCAkMNbiiNRuw2/wwa/Sah1jH3Ix2PXRu9a10l+
+ Glx0HOQ/0lFQI2po27X0HEbLrhmXN/aunN3O5ccFiSABRqut6z89SNtspd2sOu/iuinsoszk7Nqe
+ yXJmUZtfAwCad9SZ54rb6GhT2KsLe3G5uPl+X5rs/PTb3encHuLX9EUGamJSOwTJFKKcpD6oVJKc
+ 7I9PgjnEfdbPFLn4WJyjUpmCH/uALy+98xyKY5MB7A9Kt2q5mjFV7EOx7v7nfZtSHDwXSzBMqqrU
+ sVbTCdHJ8lFPOaMpmhNCDVRDxUoZhajqWpMhPSGc4iNrTOR1MqInH0UORyK4bbILM62Ufv2d4i8A
+ AAD//wMAN6nLcdABAAA=
+ headers:
+ Connection:
+ - keep-alive
+ Content-Encoding:
+ - gzip
+ Content-Type:
+ - application/json
+ Date:
+ - Sat, 16 Mar 2024 23:34:30 GMT
+ Transfer-Encoding:
+ - chunked
+ Vary:
+ - Origin,Accept-Encoding
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - application/json
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ method: GET
+ uri: https://intrinio-equities-snapshots.s3.amazonaws.com/SNAPSHOT-22-06-30-20-00.gzip?X-Amz-Algorithm=MOCK_X-Amz-Algorithm&X-Amz-Credential=MOCK_X-Amz-Credential&X-Amz-Date=MOCK_X-Amz-Date&X-Amz-Expires=MOCK_X-Amz-Expires&X-Amz-Signature=MOCK_X-Amz-Signature&X-Amz-SignedHeaders=MOCK_X-Amz-SignedHeaders
+ response:
+ body:
+ string: !!binary |
+ H4sIAMoAvmIA/6T9yXrjyM4Fis7zKeoB+PmLvhlSVMe0OpN0l7M7vJMzPo9/sBCUxJCd+6+Ca9dm
+ ZplhUSQjEAvAwsL4eVydD800tOvNP5eh7zbz38f+D/31PLWHf8oP3s6H1+OmObTjNP9k6o+bcWqP
+ l/lX9v1uX33G4fw+/3c7Pi/+xp/NH4T/un/Mql/Po/C3+yj8123Ur0t7OjT+SaUm+yYmkxodfAg6
+ 5ZSessrOGkPndcAg1xz/f/9vo+Yh2Sj1pJRWyerm+P//f7498ev3cbNpnH/yqgn0Px6hVPb5KWaT
+ ncrzyXIUfH43DU3557//8nF4Hhr1ZF2jjWsC/X8epKN5ytFpEy3Oexys4AL9uZu++3Y626cYbNJ0
+ /03zazced+KbGC9vr+Jf/r2ZRvr5k9dNVDTCJWfi/VvSHPBZBaN5DCbHkzJfLxM1fZrxXy8T6Qaz
+ d7+m6f1Mz9g8edvgw0zM9DmLyygbTUz8Hp4CfQGjMSf/+/089+uxcfbJ0HXofrIL4X4ZmnNOqah9
+ 49wTZp7BqxdMm8OlbWx4SvQRrrHe3y9B3z54Q3c0n6djlEzr82l7fm8W//wa31fP/7yP1c+649A2
+ 5inYxjdZ2+vapbukh2hiTJrORochWvAlVrvDutHpydEbw+RQ11FJe/OUtA6W1uw8gI///RrTrm2b
+ /JQdf3zUuYzyOZqAlUeWiCYkD6CD5ArH/rSm9UsfbJrrnHPZxacYlTc5lnN8kLynzQvmG+YAfX9/
+ e0Sa1tFTJoOqTeABPN2S6DVM3WejnyIuERsTlyuHTLOPIdCD0U+JJsBTkKya08d6os2ibXR+Cu7h
+ ZTtjcX+JNgN1HcDHMgdX76vVpZqVh65f13P3+bhtImwMfyoZhetHp6ieUsgZayhiHvOo/34Dbb+X
+ bwLrz8ZpfkM0m3NSd4uR3JPR0WtaQk5HLCKnaJ5nwVU2++6f9178Jfeb9e8m+CcbyzN0Js/DIq2Q
+ J1ryMdLmTSM8bWSO5rZkoq3Hvnpvu1V/bgImN63tHHI18UzOZMc1neeDNZL98e3QffNMUlD6iR51
+ hCGl77Gd2EikRztEb8g+JUV2yIVyPsuW2G5oV+/il9Puepq4tCyxERgT7jAiR4JOtHDoCcUnsmPh
+ KUsmz2Hf/V9fjp5SO350ACqZtz6ybD7dvoin96W8CzRtFAw1D/vvX+Rlvelg6qMp5nr5JsK