Skip to content

Commit

Permalink
fix: docgen
Browse files Browse the repository at this point in the history
refactor: cleanup

fix: to_request_fields empty detection

refactor: typing

refactor: prettiness
  • Loading branch information
aarjaneiro committed Jan 17, 2025
1 parent aa7a965 commit ee6f1bc
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 70 deletions.
4 changes: 3 additions & 1 deletion alpaca/common/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,7 @@ def map_values(val: Any) -> Any:
# {trusted_contact: {}, contact: {}, identity: None, etc}
# so we do a simple list comprehension to filter out None and {}
return {
key: map_values(val) for key, val in d.items() if val is not None and len(str(val)) > 0
key: map_values(val)
for key, val in d.items()
if val is not None and val != {} and len(str(val)) > 0
}
4 changes: 1 addition & 3 deletions alpaca/trading/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ class OrderClass(str, Enum):
The order classes supported by Alpaca vary based on the order's security type.
The following provides a comprehensive breakdown of the supported order classes for each category:
- Equity trading: simple (or ""), oco, oto, bracket.
- Options trading:
- simple (or "").
- mleg (required for multi-leg complex option strategies)
- Options trading: Simple (or ""), mleg (required for multi-leg complex option strategies).
- Crypto trading: simple (or "").
"""

Expand Down
4 changes: 3 additions & 1 deletion alpaca/trading/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ def root_validator(cls, data: dict) -> dict:
if "_is_sub_mleg" not in data or not data["_is_sub_mleg"]:
if "legs" not in data or data["legs"] == "":
raise ValueError("legs is required for mleg orders")
if data["legs"] is not None: # it is possible when querying individual legs that this is None
if (
data["legs"] is not None
): # it is possible when querying individual legs that this is None
if len(data["legs"]) < 1:
raise ValueError("legs must have at least one order")
for leg in data["legs"]:
Expand Down
43 changes: 24 additions & 19 deletions alpaca/trading/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ class StopLossRequest(NonEmptyRequest):
stop_price: float
limit_price: Optional[float] = None

class OrderLegRequest(NonEmptyRequest):

class OptionLegRequest(NonEmptyRequest):
"""
Used for providing details for a leg of a multi-leg order.
Expand Down Expand Up @@ -285,8 +286,8 @@ class OrderRequest(NonEmptyRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. If specified,
must contain at least 2 but no more than 4 legs.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order If specified (must contain at least 2 but no more than 4 legs for options).
Otherwise, for equities, a list of individual orders.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
position_intent (Optional[PositionIntent]): An enum to indicate the desired position strategy: BTO, BTC, STO, STC.
Expand All @@ -301,7 +302,7 @@ class OrderRequest(NonEmptyRequest):
order_class: Optional[OrderClass] = None
extended_hours: Optional[bool] = None
client_order_id: Optional[str] = None
legs: Optional[List[OrderLegRequest]] = None
legs: Optional[Union[List[OptionLegRequest], List["OrderRequest"]]] = None
take_profit: Optional[TakeProfitRequest] = None
stop_loss: Optional[StopLossRequest] = None
position_intent: Optional[PositionIntent] = None
Expand All @@ -323,18 +324,24 @@ def root_validator(cls, values: dict) -> dict:
if "legs" not in values or values["legs"] is None:
raise ValueError("legs is required for the mleg order class.")
l_len = len(values["legs"])
if l_len> 4:
if l_len > 4:
raise ValueError("At most 4 legs are allowed for the mleg order class.")
if l_len < 2:
raise ValueError("At least 2 legs are required for the mleg order class.")
raise ValueError(
"At least 2 legs are required for the mleg order class."
)
n_unique = len(set([l.symbol for l in values["legs"]]))
if n_unique != l_len:
raise ValueError("All legs must have unique symbols.")
else:
if "symbol" not in values or values["symbol"] is None:
raise ValueError("symbol is required for all order classes other than mleg.")
raise ValueError(
"symbol is required for all order classes other than mleg."
)
if "side" not in values or values["side"] is None:
raise ValueError("side is required for all order classes other than mleg.")
raise ValueError(
"side is required for all order classes other than mleg."
)

return values

Expand All @@ -355,7 +362,7 @@ class MarketOrderRequest(OrderRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed for options.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
position_intent (Optional[PositionIntent]): An enum to indicate the desired position strategy: BTO, BTC, STO, STC.
Expand All @@ -382,7 +389,7 @@ class StopOrderRequest(OrderRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed for options.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
stop_price (float): The price at which the stop order is converted to a market order or a stop limit
Expand Down Expand Up @@ -413,13 +420,12 @@ class LimitOrderRequest(OrderRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed for options.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
limit_price (Optional[float]): The worst fill price for a limit or stop limit order. For the mleg order class, this
is specified such that:
- A positive value indicates a debit, representing a cost or payment to be made.
- A negative value signifies a credit, reflecting an amount to be received.
is specified such that a positive value indicates a debit (representing a cost or payment to be made) while a
negative value signifies a credit (reflecting an amount to be received).
position_intent (Optional[PositionIntent]): An enum to indicate the desired position strategy: BTO, BTC, STO, STC.
"""

Expand Down Expand Up @@ -456,15 +462,14 @@ class StopLimitOrderRequest(OrderRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed for options.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
stop_price (float): The price at which the stop order is converted to a market order or a stop limit
order is converted to a limit order.
limit_price (float): The worst fill price for a limit or stop limit order. For the mleg order class, this
is specified such that:
- A positive value indicates a debit, representing a cost or payment to be made.
- A negative value signifies a credit, reflecting an amount to be received.
is specified such that a positive value indicates a debit (representing a cost or payment to be made) while a
negative value signifies a credit (reflecting an amount to be received).
position_intent (Optional[PositionIntent]): An enum to indicate the desired position strategy: BTO, BTC, STO, STC.
"""

Expand Down Expand Up @@ -492,7 +497,7 @@ class TrailingStopOrderRequest(OrderRequest):
extended_hours (Optional[float]): Whether the order can be executed during regular market hours.
client_order_id (Optional[str]): A string to identify which client submitted the order.
order_class (Optional[OrderClass]): The class of the order. Simple orders have no other legs.
legs (Optional[List[OrderLegRequest]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed.
legs (Optional[Union[List[OptionLegRequest], List[OrderRequest]]]): For multi-leg option orders, the legs of the order. At most 4 legs are allowed for options.
take_profit (Optional[TakeProfitRequest]): For orders with multiple legs, an order to exit a profitable trade.
stop_loss (Optional[StopLossRequest]): For orders with multiple legs, an order to exit a losing trade.
trail_price (Optional[float]): The absolute price difference by which the trailing stop will trail.
Expand Down
44 changes: 32 additions & 12 deletions examples/options-trading-mleg.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
"metadata": {},
"cell_type": "code",
"source": [
"from alpaca.trading import LimitOrderRequest\n",
"\n",
"# Please change the following to your own PAPER api key and secret\n",
"# or set them as environment variables (ALPACA_API_KEY, ALPACA_SECRET_KEY).\n",
"# You can get them from https://alpaca.markets/\n",
Expand All @@ -41,10 +39,7 @@
"# Below are the variables for development this documents\n",
"# Please do not change these variables\n",
"\n",
"trade_api_url = None\n",
"trade_api_wss = None\n",
"data_api_url = None\n",
"option_stream_data_wss = None"
"trade_api_url = None"
],
"id": "4ec3fa9be63ec8be",
"outputs": [],
Expand Down Expand Up @@ -95,8 +90,9 @@
"from alpaca.trading.requests import (\n",
" GetOptionContractsRequest,\n",
" MarketOrderRequest,\n",
" OrderLegRequest,\n",
" ReplaceOrderRequest\n",
" OptionLegRequest,\n",
" ReplaceOrderRequest,\n",
" LimitOrderRequest,\n",
")\n",
"from alpaca.trading.enums import (\n",
" AssetStatus,\n",
Expand Down Expand Up @@ -238,7 +234,7 @@
" cts = trade_client.get_option_contracts(req)\n",
"\n",
" c = get_least_error_contract(cts.option_contracts, optimal_price)\n",
" order_legs.append(OrderLegRequest(\n",
" order_legs.append(OptionLegRequest(\n",
" symbol=c.symbol,\n",
" side=OrderSide.BUY,\n",
" ratio_qty=1\n",
Expand All @@ -247,7 +243,7 @@
"# We should see that the symbols are similar, like \"TSLA______C________\" and \"TSLA______P________\",\n",
"# with all values marked as \"_\" being the same in both symbols.\n",
"# Such is because we expect only the contract type (call or put, C or P) to be different.\n",
"order_legs\n"
"order_legs"
],
"id": "c5d3eef0fcabc15e",
"outputs": [],
Expand All @@ -271,6 +267,30 @@
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"# Note that we can query via order ids or client order ids for the whole order or individual legs\n",
"\n",
"# Query by the order's client id\n",
"q1 = trade_client.get_order_by_client_id(res.client_order_id)\n",
"\n",
"# Query by the whole order's id\n",
"q2 = trade_client.get_order_by_id(res.id)\n",
"\n",
"# Query just the first leg's client id\n",
"q3 = trade_client.get_order_by_client_id(res.legs[0].client_order_id)\n",
"\n",
"# Query by first leg's id\n",
"q4 = trade_client.get_order_by_id(res.legs[0].id)\n",
"\n",
"print(f\"Q1: {q1}\\n===\\nQ2: {q2}\\n===\\nQ3: {q3}\\n===\\nQ4: {q4}\")"
],
"id": "626f69b5d3a81150",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "markdown",
Expand All @@ -296,6 +316,7 @@
"C = optimal_price + (stddev / 2)\n",
"A = B - stddev\n",
"D = C + stddev\n",
"\n",
"print(f\"A: {A}, B: {B}, C: {C}, D: {D}\")"
],
"id": "88d3d516e5e20270",
Expand Down Expand Up @@ -389,7 +410,7 @@
"\n",
"order_legs_m = []\n",
"for buff in buffers:\n",
" order_legs_m.append(OrderLegRequest(\n",
" order_legs_m.append(OptionLegRequest(\n",
" symbol=buff.contract.symbol,\n",
" side=OrderSide.BUY if buff.is_buy else OrderSide.SELL,\n",
" ratio_qty=1\n",
Expand Down Expand Up @@ -489,7 +510,6 @@
" req = ReplaceOrderRequest(\n",
" qty=55,\n",
" )\n",
"\n",
" res = trade_client.replace_order_by_id(res.id, req)\n",
" print(f\"Replaced order: {res}\")\n",
"else:\n",
Expand Down
Loading

0 comments on commit ee6f1bc

Please sign in to comment.