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 3 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_auction(self, request_params: StockAuctionsRequest):
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use plural?

Suggested change
def get_stock_auction(self, request_params: StockAuctionsRequest):
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
8 changes: 8 additions & 0 deletions alpaca/data/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,11 @@
"cc": "corrected_conditions",
"z": "tape",
}

AUCTION_MAPPING: Dict[str, str] = {
"c": "condition",
"p": "price",
"s": "size",
"t": "timestamp",
"x": "exchange",
}
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 *
82 changes: 82 additions & 0 deletions alpaca/data/models/auctions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from datetime import datetime
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


"""

symbol: str
timestamp: datetime
condition: str
price: float
size: float
exchange: 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:
auction_data.extend(c)
if o is not None:
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.

discussion: I felt it might be good to have indicator or separation between open and close. even though it might be possible to know based on timestamp. prefer to put something easy to distinguish.
idea: how about adding another attribuite i.e. open or close?


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

super().__init__(data=parsed_auctions)
8 changes: 8 additions & 0 deletions alpaca/data/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ 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?

feed: Optional[DataFeed] = None
asof: Optional[str] = None


# ############################## Bars ################################# #


Expand Down