Skip to content

Commit

Permalink
feat: add get option contract
Browse files Browse the repository at this point in the history
  • Loading branch information
hiohiohio committed Jan 24, 2024
1 parent 791ce40 commit d846af4
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 0 deletions.
53 changes: 53 additions & 0 deletions alpaca/trading/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
GetCalendarRequest,
ClosePositionRequest,
GetAssetsRequest,
GetOptionContractsRequest,
OrderRequest,
GetOrdersRequest,
ReplaceOrderRequest,
Expand All @@ -23,6 +24,8 @@
)

from alpaca.trading.models import (
OptionContract,
OptionContractsResponse,
Order,
Position,
ClosePositionResponse,
Expand Down Expand Up @@ -661,3 +664,53 @@ def get_corporate_announcement_by_id(
return response

return CorporateActionAnnouncement(**response)

# ############################## OPTIONS CONTRACTS ################################# #

def get_option_contracts(
self, request: GetOptionContractsRequest
) -> Union[OptionContractsResponse, RawData]:
"""
The option contracts API serves as the master list of option contracts available for trade and data consumption from Alpaca.
Args:
request (GetOptionContractsRequest): The parameters that option contracts can be queried by.
Returns:
OptionContracts (Union[OptionContractsResponse, RawData]): The object includes list of option contracts.
"""
if request is None:
raise ValueError("request (GetOptionContractsRequest) is required")
if request.underlying_symbol == "":
raise ValueError("underlying_symbol is required")

params = request.to_request_fields()

response = self.get(f"/options/contracts", params)

if self._use_raw_data:
return response

return TypeAdapter(OptionContractsResponse).validate_python(response)

def get_option_contract(
self, symbol_or_id: Union[UUID, str]
) -> Union[OptionContract, RawData]:
"""
The option contracts API serves as the master list of option contracts available for trade and data consumption from Alpaca.
Args:
symbol_or_id (Union[UUID, str]): The symbol or id of the option contract to retrieve.
Returns:
OptionContracts (Union[OptionContracts, RawData]): The list of option contracts.
"""
if symbol_or_id == "":
raise ValueError("symbol_or_id is required")

response = self.get(f"/options/contracts/{symbol_or_id}")

if self._use_raw_data:
return response

return TypeAdapter(OptionContract).validate_python(response)
27 changes: 27 additions & 0 deletions alpaca/trading/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,30 @@ class TradeConfirmationEmail(str, Enum):

ALL = "all"
NONE = "none"


class ContractType(str, Enum):
"""
Represents the contract type of options
"""

CALL = "call"
PUT = "put"


class ExerciseStyle(str, Enum):
"""
Represents the exercise style of options
"""

AMERICAN = "american"
EUROPEAN = "european"


class ActivityCategory(str, Enum):
"""
Represents the category of an Activity
"""

TRADE_ACTIVITY = "trade_activity"
NON_TRADE_ACTIVITY = "non_trade_activity"
60 changes: 60 additions & 0 deletions alpaca/trading/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
AssetClass,
AssetStatus,
AssetExchange,
ContractType,
DTBPCheck,
ExerciseStyle,
OrderStatus,
OrderType,
OrderClass,
Expand Down Expand Up @@ -604,3 +606,61 @@ class TradeUpdate(BaseModel):
position_qty: Optional[float] = None
price: Optional[float] = None
qty: Optional[float] = None


class OptionContract(BaseModel):
"""
Represents an option contract.
Attributes:
id (str) The unique identifier of the option contract.
symbol (str): The symbol representing the option contract.
name (str): The name of the option contract.
status (AssetStatus): The status of the option contract.
tradable (bool): Indicates whether the option contract is tradable.
expiration_date (date): The expiration date of the option contract.
root_symbol (str): The root symbol of the option contract.
underlying_symbol (str): The underlying symbol of the option contract.
underlying_asset_id (UUID): The unique identifier of the underlying asset.
type (ContractType): The type of the option contract.
style (ExerciseStyle): The style of the option contract.
strike_price (float): The strike price of the option contract.
size (str): The size of the option contract. Usually contracts have size=100.
open_interest (Optional[str]): The open interest of the option contract.
open_interest_date (Optional[date]): The date of the open interest data.
close_price (Optional[str]): The close price of the option contract.
close_price_date (Optional[date]): The date of the close price data.
"""

id: str
symbol: str
name: str
status: AssetStatus
tradable: bool
expiration_date: date
root_symbol: str
underlying_symbol: str
underlying_asset_id: UUID
type: ContractType
style: ExerciseStyle
strike_price: float
size: str
open_interest: Optional[str] = None
open_interest_date: Optional[date] = None
close_price: Optional[str] = None
close_price_date: Optional[date] = None


class OptionContractsResponse(BaseModel):
"""
Represents a response from the option contracts endpoint.
Attributes:
option_contracts (Optional[List[OptionContract]]): The list of option contracts.
limit (int): The maximum number of option contracts in the response.
page (int): The page number of the response.
"""

option_contracts: Optional[List[OptionContract]] = None
limit: int
page: int
37 changes: 37 additions & 0 deletions alpaca/trading/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from alpaca.common.requests import NonEmptyRequest
from alpaca.common.enums import Sort
from alpaca.trading.enums import (
ContractType,
ExerciseStyle,
OrderType,
AssetStatus,
AssetClass,
Expand Down Expand Up @@ -457,3 +459,38 @@ def root_validator(cls, values: dict) -> dict:
raise ValueError("The date range is limited to 90 days.")

return values


class GetOptionContractsRequest(NonEmptyRequest):
"""
Used to fetch option contracts for a given underlying symbol.
Attributes:
underlying_symbol (str): The underlying symbol for the option contracts to be returned.
status (Optional[AssetStatus]): The status of the asset.
expiration_date (Optional[Union[date, str]]): The expiration date of the option contract. (YYYY-MM-DD)
expiration_date_gte (Optional[Union[date, str]]): The expiration date of the option contract greater than or equal to. (YYYY-MM-DD)
expiration_date_lte (Optional[Union[date, str]]): The expiration date of the option contract less than or equal to. (YYYY-MM-DD)
root_symbol (Optional[str]): The option root symbol.
type (Optional[ContractType]): The option contract type.
style (Optional[ExerciseStyle]): The option contract style.
strike_price_gte (Optional[str]): The option contract strike price greater than or equal to.
strike_price_lte (Optional[str]): The option contract strike price less than or equal to.
limit (Optional[int]): The maximum number of entries to return in the response.
page (Optional[int]): The page number for the results to return.
"""

underlying_symbol: str

status: Optional[AssetStatus] = AssetStatus.ACTIVE
expiration_date: Optional[Union[date, str]] = None
expiration_date_gte: Optional[Union[date, str]] = None
expiration_date_lte: Optional[Union[date, str]] = None
root_symbol: Optional[str] = None
type: Optional[ContractType] = None
style: Optional[ExerciseStyle] = None
strike_price_gte: Optional[str] = None
strike_price_lte: Optional[str] = None

limit: Optional[int] = None
page: Optional[int] = None
85 changes: 85 additions & 0 deletions tests/trading/trading_client/test_option_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
Contains tests for Trading API's option routes.
"""

from alpaca.common.enums import BaseURL
from alpaca.trading.requests import GetOptionContractsRequest
from alpaca.trading.client import TradingClient
from alpaca.trading.models import OptionContract, OptionContractsResponse


def test_get_option_contracts(reqmock, trading_client: TradingClient):
reqmock.get(
f"{BaseURL.TRADING_PAPER.value}/v2/options/contracts?underlying_symbol=AAPL",
text="""
{
"option_contracts": [
{
"id": "00000000-0000-0000-0000-000000000000",
"symbol": "AAPL231103C00170000",
"name": "AAPL Nov 03 2023 170 Call",
"status": "active",
"tradable": true,
"expiration_date": "2023-11-03",
"root_symbol": "AAPL",
"underlying_symbol": "AAPL",
"underlying_asset_id": "00000000-0000-0000-0000-000000000000",
"type": "call",
"style": "american",
"strike_price": "170",
"size": "100",
"open_interest": "0",
"open_interest_date": "2023-11-03",
"close_price": null,
"close_price_date": null
}
],
"page": 1,
"limit": 5
}
""",
)

res = trading_client.get_option_contracts(
GetOptionContractsRequest(underlying_symbol="AAPL")
)

assert reqmock.called_once
assert isinstance(res, OptionContractsResponse)
assert len(res.option_contracts) == 1
assert isinstance(res.option_contracts[0], OptionContract)


def test_get_option_contract(reqmock, trading_client: TradingClient):
symbol = "AAPL231103C00170000"

reqmock.get(
f"{BaseURL.TRADING_PAPER.value}/v2/options/contracts/{symbol}",
text="""
{
"id": "00000000-0000-0000-0000-000000000000",
"symbol": "AAPL231103C00170000",
"name": "AAPL Nov 03 2023 170 Call",
"status": "active",
"tradable": true,
"expiration_date": "2023-11-03",
"root_symbol": "AAPL",
"underlying_symbol": "AAPL",
"underlying_asset_id": "00000000-0000-0000-0000-000000000000",
"type": "call",
"style": "american",
"strike_price": "170",
"size": "100",
"open_interest": "0",
"open_interest_date": "2023-11-03",
"close_price": null,
"close_price_date": null
}
""",
)

contract = trading_client.get_option_contract(symbol)

assert reqmock.called_once
assert isinstance(contract, OptionContract)
assert contract.symbol == symbol

0 comments on commit d846af4

Please sign in to comment.