Skip to content

feat: Add auction data handling to stock historical data client #576

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions alpaca/common/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
4 changes: 2 additions & 2 deletions alpaca/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
22 changes: 21 additions & 1 deletion alpaca/data/historical/stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -19,6 +19,7 @@
StockQuotesRequest,
StockSnapshotRequest,
StockTradesRequest,
StockAuctionsRequest,
)


Expand Down Expand Up @@ -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(),
)
Comment on lines +85 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have recently introduced page_size parameter to _get_marketdata() [1], could you please set page_size for auctions as well?

*1 #583

Suggested change
raw_auctions = self._get_marketdata(
path="/stocks/auctions",
params=request_params.to_request_fields(),
)
raw_auctions = self._get_marketdata(
path="/stocks/auctions",
params=request_params.to_request_fields(),
page_limit = 1_000,
page_size = 1_000,
)


if self._use_raw_data:
return raw_auctions

return AuctionSet(raw_auctions)

def get_stock_bars(
self, request_params: StockBarsRequest
) -> Union[BarSet, RawData]:
Expand Down
9 changes: 9 additions & 0 deletions alpaca/data/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
}
1 change: 1 addition & 0 deletions alpaca/data/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
95 changes: 95 additions & 0 deletions alpaca/data/models/auctions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from datetime import datetime
from typing import Dict, List
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to use Optional

Suggested change
from typing import Dict, List
from typing import Dict, List, Optional


from alpaca.common.models import ValidateBaseModel as BaseModel
from alpaca.common.types import RawData
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add other attribuites to docstring?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all done

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) -> None:
"""A collection of Auctions.

Args:
raw_data (RawData): The collection of raw auction data from API keyed by Symbol.
"""

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 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about putting open first before close as timestamp could be orderd by asc.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use orderby timestamp in the final dataframe, and then open will be before close.

Copy link
Contributor

@hiohiohio hiohiohio Apr 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. You are right. For the dataframe, it is easy. But also we have AuctionSet object and if we change here, the process not required in dataframe level as well? Do you have any concern to change order here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying that the order of the AuctionSet should be consistent with the order of the dataframe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I thought is order by open => close would be nicer than close => open order in a day.
currently:

{
    "data": {
        "SPY": [
            {
                "auction_type": "CLOSE",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 2, 20, 0, 0, 42680, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "OPEN",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 2, 13, 30, 0, 330621, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "CLOSE",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 3, 20, 0, 0, 130854, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "OPEN",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 3, 13, 30, 0, 692296, tzinfo=TzInfo(UTC)
                ),
            },
            ...
        ]
    }
}

What I thought good is:

{
    "data": {
        "SPY": [
            {
                "auction_type": "OPEN",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 2, 13, 30, 0, 330621, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "CLOSE",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 2, 20, 0, 0, 42680, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "OPEN",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 3, 13, 30, 0, 692296, tzinfo=TzInfo(UTC)
                ),
            },
            ...
            {
                "auction_type": "CLOSE",
                ...
                "timestamp": datetime.datetime(
                    2025, 4, 3, 20, 0, 0, 130854, tzinfo=TzInfo(UTC)
                ),
            },
            ...
        ]
    }
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it


parsed_auctions[symbol] = [
Auction(symbol, auction)
for auction in auction_data
if auction is not None
]

super().__init__(data=parsed_auctions)
23 changes: 23 additions & 0 deletions alpaca/data/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ def __init__(self, **data: Any) -> None:
super().__init__(**data)


# ############################## Auctions ################################# #


class StockAuctionsRequest(BaseTimeseriesDataRequest):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please write docstring and also add to api_reference?

"""
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 ################################# #


Expand Down
12 changes: 12 additions & 0 deletions docs/api_reference/data/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ Models
======


Auction
-------

.. autoclass:: alpaca.data.models.auctions.Auction


AuctionSet
----------

.. autoclass:: alpaca.data.models.auctions.AuctionSet


Bar
---

Expand Down
6 changes: 6 additions & 0 deletions docs/api_reference/data/stock/requests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ StockBarsRequest
.. autoclass:: alpaca.data.requests.StockBarsRequest


StockAuctionsRequest
--------------------

.. autoclass:: alpaca.data.requests.StockAuctionsRequest


StockQuotesRequest
------------------

Expand Down