diff --git a/alpaca/common/rest.py b/alpaca/common/rest.py index a8da6c42..29e33c5f 100644 --- a/alpaca/common/rest.py +++ b/alpaca/common/rest.py @@ -425,6 +425,7 @@ def _get_marketdata_entries(response: HTTPResult, no_sub_key: bool) -> RawData: "snapshots", "trade", "trades", + "auctions", } selected_keys = data_keys.intersection(response) # Neither of these should ever happen! diff --git a/alpaca/common/utils.py b/alpaca/common/utils.py index 1c3dd0ea..86db98c1 100644 --- a/alpaca/common/utils.py +++ b/alpaca/common/utils.py @@ -33,7 +33,7 @@ def validate_uuid_id_param( def validate_symbol_or_asset_id( - symbol_or_asset_id: Union[UUID, str] + symbol_or_asset_id: Union[UUID, str], ) -> Union[UUID, str]: """ A helper function to eliminate duplicate checks of symbols or asset ids. @@ -55,7 +55,7 @@ def validate_symbol_or_asset_id( def validate_symbol_or_contract_id( - symbol_or_contract_id: Union[UUID, str] + symbol_or_contract_id: Union[UUID, str], ) -> Union[UUID, str]: """ A helper function to eliminate duplicate checks of symbols or contract id. diff --git a/alpaca/data/historical/stock.py b/alpaca/data/historical/stock.py index ab72755f..585f2573 100644 --- a/alpaca/data/historical/stock.py +++ b/alpaca/data/historical/stock.py @@ -10,7 +10,7 @@ from alpaca.data.historical.utils import ( parse_obj_as_symbol_dict, ) -from alpaca.data.models import BarSet, QuoteSet, TradeSet +from alpaca.data.models import BarSet, QuoteSet, TradeSet, AuctionSet from alpaca.data.requests import ( StockBarsRequest, StockLatestBarRequest, @@ -19,6 +19,7 @@ StockQuotesRequest, StockSnapshotRequest, StockTradesRequest, + StockAuctionsRequest, ) @@ -72,6 +73,25 @@ def __init__( raw_data=raw_data, ) + def get_stock_auctions(self, request_params: StockAuctionsRequest): + """Returns auction data for an equity or list of equities over a given time period. + + Args: + request_params (StockAuctionsRequest): The request object for retrieving stock auction data. + + Returns: + Union[AuctionSet, RawData]: The auction data either in raw or wrapped form + """ + raw_auctions = self._get_marketdata( + path="/stocks/auctions", + params=request_params.to_request_fields(), + ) + + if self._use_raw_data: + return raw_auctions + + return AuctionSet(raw_auctions, request_params.sort) + def get_stock_bars( self, request_params: StockBarsRequest ) -> Union[BarSet, RawData]: diff --git a/alpaca/data/mappings.py b/alpaca/data/mappings.py index 6ba92b0b..699ce8e3 100644 --- a/alpaca/data/mappings.py +++ b/alpaca/data/mappings.py @@ -82,3 +82,12 @@ "cc": "corrected_conditions", "z": "tape", } + +AUCTION_MAPPING: Dict[str, str] = { + "c": "condition", + "p": "price", + "s": "size", + "t": "timestamp", + "x": "exchange", + "at": "auction_type", +} diff --git a/alpaca/data/models/__init__.py b/alpaca/data/models/__init__.py index 0db35cc9..227e3700 100644 --- a/alpaca/data/models/__init__.py +++ b/alpaca/data/models/__init__.py @@ -5,3 +5,4 @@ from alpaca.data.models.trades import * from alpaca.data.models.snapshots import * from alpaca.data.models.orderbooks import * +from alpaca.data.models.auctions import * diff --git a/alpaca/data/models/auctions.py b/alpaca/data/models/auctions.py new file mode 100644 index 00000000..0cbc0289 --- /dev/null +++ b/alpaca/data/models/auctions.py @@ -0,0 +1,108 @@ +from datetime import datetime +from typing import Dict, List + +from alpaca.common.models import ValidateBaseModel as BaseModel +from alpaca.common.types import RawData +from alpaca.common.enums import Sort +from alpaca.data.mappings import AUCTION_MAPPING +from alpaca.data.models.base import BaseDataSet, TimeSeriesMixin + + +class Auction(BaseModel): + """Represents one auction of aggregated trade data over a specified interval. + + Attributes: + symbol (str): The ticker identifier for the security whose data forms the bar. + timestamp (datetime): The timestamp of the auction. + condition (str): The condition of the auction. + price (float): The price of the auction. + size (float): The size of the auction. + exchange (str): The exchange of the auction. + auction_type (str): The type of auction. OPEN or CLOSE. + + """ + + symbol: str + timestamp: datetime + condition: str + price: float + size: float + exchange: str + auction_type: str + + def __init__(self, symbol: str, raw_data: RawData) -> None: + """Instantiates an auction + + Args: + raw_data (RawData): Raw unparsed auction data from API, contains ohlc and other fields. + """ + mapped_auction = {} + + if raw_data is not None: + mapped_auction = { + AUCTION_MAPPING[key]: val + for key, val in raw_data.items() + if key in AUCTION_MAPPING + } + + super().__init__(symbol=symbol, **mapped_auction) + + +class AuctionSet(BaseDataSet, TimeSeriesMixin): + """A collection of Auctions. + + Attributes: + data (Dict[str, List[Auction]]): The collection of Auctions keyed by symbol. + """ + + data: Dict[str, List[Auction]] = {} + + def __init__(self, raw_data: RawData, sort: Sort) -> None: + """A collection of Auctions. + + Args: + raw_data (RawData): The collection of raw auction data from API keyed by Symbol. + sort (Sort): The sort order of the auctions. + """ + parsed_auctions = {} + + raw_auctions = raw_data + + if raw_auctions is not None: + for symbol, auctions in raw_auctions.items(): + + auction_data = [] + for auction in auctions: + c = auction.get("c") + o = auction.get("o") + + if sort == Sort.DESC: + if c is not None: + for close_auction in c: + if close_auction: + close_auction["at"] = "CLOSE" + auction_data.extend(c) + if o is not None: + for open_auction in o: + if open_auction: + open_auction["at"] = "OPEN" + auction_data.extend(o) + else: # NOTE: None and ASC are the same + if o is not None: + for open_auction in o: + if open_auction: + open_auction["at"] = "OPEN" + auction_data.extend(o) + if c is not None: + for close_auction in c: + if close_auction: + close_auction["at"] = "CLOSE" + auction_data.extend(c) + + parsed_auctions[symbol] = [ + Auction(symbol, auction) + for auction in auction_data + if auction is not None + ] + + super().__init__(data=parsed_auctions) diff --git a/alpaca/data/requests.py b/alpaca/data/requests.py index 2454cd9d..827c77d7 100644 --- a/alpaca/data/requests.py +++ b/alpaca/data/requests.py @@ -60,6 +60,29 @@ def __init__(self, **data: Any) -> None: super().__init__(**data) +# ############################## Auctions ################################# # + + +class StockAuctionsRequest(BaseTimeseriesDataRequest): + """ + The request model for retrieving auction data for stocks. + + See BaseTimeseriesDataRequest for more information on available parameters. + + Attributes: + symbol_or_symbols (Union[str, List[str]]): The ticker identifier or list of ticker identifiers. + start (Optional[datetime]): The beginning of the time interval for desired data. Timezone naive inputs assumed to be in UTC. + end (Optional[datetime]): The end of the time interval for desired data. Defaults to now. Timezone naive inputs assumed to be in UTC. + limit (Optional[int]): Upper limit of number of data points to return. Defaults to None. + feed (Optional[DataFeed]): The stock data feed to retrieve from. + sort (Optional[Sort]): The chronological order of response based on the timestamp. Defaults to ASC. + asof (Optional[str]): The asof date of the queried stock symbol(s) in YYYY-MM-DD format. + """ + + feed: Optional[DataFeed] = None + asof: Optional[str] = None + + # ############################## Bars ################################# # diff --git a/docs/api_reference/data/models.rst b/docs/api_reference/data/models.rst index a75bdd22..91deab66 100644 --- a/docs/api_reference/data/models.rst +++ b/docs/api_reference/data/models.rst @@ -3,6 +3,18 @@ Models ====== +Auction +------- + +.. autoclass:: alpaca.data.models.auctions.Auction + + +AuctionSet +---------- + +.. autoclass:: alpaca.data.models.auctions.AuctionSet + + Bar --- diff --git a/docs/api_reference/data/stock/requests.rst b/docs/api_reference/data/stock/requests.rst index f3f08d08..659730f5 100644 --- a/docs/api_reference/data/stock/requests.rst +++ b/docs/api_reference/data/stock/requests.rst @@ -15,6 +15,12 @@ StockBarsRequest .. autoclass:: alpaca.data.requests.StockBarsRequest +StockAuctionsRequest +-------------------- + +.. autoclass:: alpaca.data.requests.StockAuctionsRequest + + StockQuotesRequest ------------------