diff --git a/alpaca/common/rest.py b/alpaca/common/rest.py index 8de1585a..a8da6c42 100644 --- a/alpaca/common/rest.py +++ b/alpaca/common/rest.py @@ -365,10 +365,10 @@ def _validate_credentials( return api_key, secret_key, oauth_token - def get_marketdata( + def _get_marketdata( self, path: str, - params: Dict[str, Any] = None, + params: Dict[str, Any], page_limit: int = 10_000, no_sub_key: bool = False, ) -> Dict[str, List[Any]]: @@ -426,10 +426,13 @@ def _get_marketdata_entries(response: HTTPResult, no_sub_key: bool) -> RawData: "trade", "trades", } - selected_key = data_keys.intersection(response) - if selected_key is None or len(selected_key) < 1: + selected_keys = data_keys.intersection(response) + # Neither of these should ever happen! + if selected_keys is None or len(selected_keys) < 1: raise ValueError("The data in response does not match any known keys.") - selected_key = selected_key.pop() + if len(selected_keys) > 1: + raise ValueError("The data in response matches multiple known keys.") + selected_key = selected_keys.pop() if selected_key == "news": return {"news": response[selected_key]} return response[selected_key] diff --git a/alpaca/data/historical/corporate_actions.py b/alpaca/data/historical/corporate_actions.py index 1299726f..b77faebd 100644 --- a/alpaca/data/historical/corporate_actions.py +++ b/alpaca/data/historical/corporate_actions.py @@ -60,7 +60,7 @@ def get_corporate_actions( if request_params.types: params["types"] = ",".join(request_params.types) - response = self.get_marketdata( + response = self._get_marketdata( path="/corporate-actions", params=params, page_limit=1000, diff --git a/alpaca/data/historical/crypto.py b/alpaca/data/historical/crypto.py index 956e6796..891f0a54 100644 --- a/alpaca/data/historical/crypto.py +++ b/alpaca/data/historical/crypto.py @@ -91,7 +91,7 @@ def get_crypto_bars( """ # paginated get request for crypto market data api - raw_bars = self.get_marketdata( + raw_bars = self._get_marketdata( path=f"/crypto/{feed.value}/bars", params=request_params.to_request_fields(), ) @@ -115,7 +115,7 @@ def get_crypto_quotes( """ # paginated get request for market data api - raw_quotes = self.get_marketdata( + raw_quotes = self._get_marketdata( path=f"/crypto/{feed.value}/quotes", params=request_params.to_request_fields(), ) @@ -140,7 +140,7 @@ def get_crypto_trades( """ # paginated get request for market data api - raw_trades = self.get_marketdata( + raw_trades = self._get_marketdata( path=f"/crypto/{feed.value}/trades", params=request_params.to_request_fields(), ) @@ -163,7 +163,7 @@ def get_crypto_latest_trade( Union[Dict[str, Trade], RawData]: The latest trade in raw or wrapped format """ - raw_trades = self.get_marketdata( + raw_trades = self._get_marketdata( path=f"/crypto/{feed.value}/latest/trades", params=request_params.to_request_fields(), ) @@ -186,7 +186,7 @@ def get_crypto_latest_quote( Union[Dict[str, Quote], RawData]: The latest quote in raw or wrapped format """ - raw_quotes = self.get_marketdata( + raw_quotes = self._get_marketdata( path=f"/crypto/{feed.value}/latest/quotes", params=request_params.to_request_fields(), ) @@ -209,7 +209,7 @@ def get_crypto_latest_bar( Union[Dict[str, Bar], RawData]: The latest bar in raw or wrapped format """ - raw_bars = self.get_marketdata( + raw_bars = self._get_marketdata( path=f"/crypto/{feed.value}/latest/bars", params=request_params.to_request_fields(), ) @@ -235,7 +235,7 @@ def get_crypto_latest_orderbook( Union[Dict[str, Orderbook], RawData]: The orderbook data either in raw or wrapped form. """ - raw_orderbooks = self.get_marketdata( + raw_orderbooks = self._get_marketdata( path=f"/crypto/{feed.value}/latest/orderbooks", params=request_params.to_request_fields(), ) @@ -259,7 +259,7 @@ def get_crypto_snapshot( Union[SnapshotSet, RawData]: The snapshot data either in raw or wrapped form """ - raw_snapshots = self.get_marketdata( + raw_snapshots = self._get_marketdata( path=f"/crypto/{feed.value}/snapshots", params=request_params.to_request_fields(), ) diff --git a/alpaca/data/historical/news.py b/alpaca/data/historical/news.py index b7b04c8b..ce8aff1d 100644 --- a/alpaca/data/historical/news.py +++ b/alpaca/data/historical/news.py @@ -51,7 +51,7 @@ def get_news(self, request_params: NewsRequest) -> Union[RawData, NewsSet]: Args: request_params (NewsRequest): The request params to filter the news data""" - raw_news = self.get_marketdata( + raw_news = self._get_marketdata( path=f"/news", params=request_params.to_request_fields(), ) diff --git a/alpaca/data/historical/option.py b/alpaca/data/historical/option.py index 1a05d5b0..b0a8a089 100644 --- a/alpaca/data/historical/option.py +++ b/alpaca/data/historical/option.py @@ -85,7 +85,7 @@ def get_option_bars( """ # paginated get request for market data api - raw_bars = self.get_marketdata( + raw_bars = self._get_marketdata( path=f"/options/bars", params=request_params.to_request_fields(), ) @@ -123,7 +123,7 @@ def get_option_latest_quote( Returns: Union[Dict[str, Quote], RawData]: The latest quote in raw or wrapped format """ - raw_latest_quotes = self.get_marketdata( + raw_latest_quotes = self._get_marketdata( path=f"/options/quotes/latest", params=request_params.to_request_fields(), ) @@ -144,7 +144,7 @@ def get_option_latest_trade( Returns: Union[Dict[str, Quote], RawData]: The latest quote in raw or wrapped format """ - raw_latest_trades = self.get_marketdata( + raw_latest_trades = self._get_marketdata( path=f"/options/trades/latest", params=request_params.to_request_fields(), ) @@ -165,7 +165,7 @@ def get_option_trades( Returns: Union[TradeSet, RawData]: The trade data either in raw or wrapped form """ - raw_trades = self.get_marketdata( + raw_trades = self._get_marketdata( path=f"/options/trades", params=request_params.to_request_fields(), ) @@ -187,7 +187,7 @@ def get_option_snapshot( Returns: Union[Dict[str, OptionsSnapshot], RawData]: The snapshot data either in raw or wrapped form """ - raw_snapshots = self.get_marketdata( + raw_snapshots = self._get_marketdata( path=f"/options/snapshots", params=request_params.to_request_fields(), ) @@ -213,7 +213,7 @@ def get_option_chain( params = request_params.to_request_fields() del params["underlying_symbol"] - raw_snapshots = self.get_marketdata( + raw_snapshots = self._get_marketdata( path=f"/options/snapshots/{request_params.underlying_symbol}", params=params, ) diff --git a/alpaca/data/historical/stock.py b/alpaca/data/historical/stock.py index 2589eb35..ab72755f 100644 --- a/alpaca/data/historical/stock.py +++ b/alpaca/data/historical/stock.py @@ -84,7 +84,7 @@ def get_stock_bars( Returns: Union[BarSet, RawData]: The bar data either in raw or wrapped form """ - raw_bars = self.get_marketdata( + raw_bars = self._get_marketdata( path="/stocks/bars", params=request_params.to_request_fields(), ) @@ -105,7 +105,7 @@ def get_stock_quotes( Returns: Union[QuoteSet, RawData]: The quote data either in raw or wrapped form """ - raw_quotes = self.get_marketdata( + raw_quotes = self._get_marketdata( path="/stocks/quotes", params=request_params.to_request_fields(), ) @@ -126,7 +126,7 @@ def get_stock_trades( Returns: Union[TradeSet, RawData]: The trade data either in raw or wrapped form """ - raw_trades = self.get_marketdata( + raw_trades = self._get_marketdata( path="/stocks/trades", params=request_params.to_request_fields(), ) @@ -147,7 +147,7 @@ def get_stock_latest_trade( Returns: Union[Dict[str, Trade], RawData]: The latest trade in raw or wrapped format """ - raw_latest_trades = self.get_marketdata( + raw_latest_trades = self._get_marketdata( path="/stocks/trades/latest", params=request_params.to_request_fields(), ) @@ -168,7 +168,7 @@ def get_stock_latest_quote( Returns: Union[Dict[str, Quote], RawData]: The latest quote in raw or wrapped format """ - raw_latest_quotes = self.get_marketdata( + raw_latest_quotes = self._get_marketdata( path="/stocks/quotes/latest", params=request_params.to_request_fields(), ) @@ -189,7 +189,7 @@ def get_stock_latest_bar( Returns: Union[Dict[str, Bar], RawData]: The latest minute bar in raw or wrapped format """ - raw_latest_bars = self.get_marketdata( + raw_latest_bars = self._get_marketdata( path="/stocks/bars/latest", params=request_params.to_request_fields(), ) @@ -211,7 +211,7 @@ def get_stock_snapshot( Returns: Union[SnapshotSet, RawData]: The snapshot data either in raw or wrapped form """ - raw_snapshots = self.get_marketdata( + raw_snapshots = self._get_marketdata( path="/stocks/snapshots", params=request_params.to_request_fields(), no_sub_key=True, diff --git a/tests/data/test_historical_stock_data.py b/tests/data/test_historical_stock_data.py index 6fd52569..7bac0d8d 100644 --- a/tests/data/test_historical_stock_data.py +++ b/tests/data/test_historical_stock_data.py @@ -2,10 +2,7 @@ from datetime import datetime, timezone from typing import Dict -import pytest - from alpaca.common.enums import Sort -from alpaca.common.exceptions import APIError from alpaca.data import Bar, Quote, Snapshot, Trade from alpaca.data.enums import DataFeed, Exchange from alpaca.data.historical import StockHistoricalDataClient @@ -707,32 +704,6 @@ def test_get_multisymbol_latest_trade(reqmock, stock_client: StockHistoricalData assert reqmock.called_once -def test_get_latest_trade_multi_not_found( - reqmock, stock_client: StockHistoricalDataClient -): - symbol = "AAPL" - - reqmock.get( - f"https://data.alpaca.markets/v2/stocks/{symbol}/trades/latest?&feed=IEX", - text=""" - { - "next_page_token": null - "trade": null, - "symbol": "AAPL" - } - """, - ) - request = StockLatestTradeRequest(symbol_or_symbols=symbol, feed=DataFeed.IEX) - - trade = stock_client.get_stock_latest_trade(request_params=request) - - assert isinstance(trade, Dict) - - assert trade == {} - - assert reqmock.called_once - - def test_get_latest_trade_multi_not_found( reqmock, stock_client: StockHistoricalDataClient ):