|
5 | 5 | import copy |
6 | 6 | import datetime |
7 | 7 | from mcp.server.fastmcp import FastMCP |
| 8 | +from schwab.utils import ( |
| 9 | + AccountHashMismatchException, |
| 10 | + UnsuccessfulOrderException, |
| 11 | + Utils as SchwabUtils, |
| 12 | +) |
8 | 13 | from schwab.orders.common import first_triggers_second as trigger_builder |
9 | 14 | from schwab.orders.common import one_cancels_other as oco_builder |
10 | 15 | from schwab.orders.options import OptionSymbol |
|
30 | 35 | option_sell_to_open_limit, |
31 | 36 | option_sell_to_open_market, |
32 | 37 | ) |
33 | | -from schwab_mcp.tools.utils import JSONType, call |
| 38 | +from schwab_mcp.tools.utils import JSONType, ResponseHandler, call |
34 | 39 |
|
35 | 40 |
|
36 | 41 | # Internal helper function to apply session and duration settings |
@@ -168,6 +173,33 @@ def _build_option_order_spec( |
168 | 173 | ) |
169 | 174 |
|
170 | 175 |
|
| 176 | +def _order_response_handler(ctx: SchwabContext, account_hash: str) -> ResponseHandler: |
| 177 | + utils = SchwabUtils(ctx.client, account_hash) |
| 178 | + |
| 179 | + def handler(response: Any) -> tuple[bool, JSONType]: |
| 180 | + headers = getattr(response, "headers", {}) |
| 181 | + location = headers.get("Location") if headers else None |
| 182 | + |
| 183 | + try: |
| 184 | + order_id = utils.extract_order_id(response) |
| 185 | + except (AccountHashMismatchException, UnsuccessfulOrderException): |
| 186 | + order_id = None |
| 187 | + |
| 188 | + if order_id is None and location is None: |
| 189 | + return False, None |
| 190 | + |
| 191 | + payload: dict[str, Any] = {} |
| 192 | + if order_id is not None: |
| 193 | + payload["orderId"] = order_id |
| 194 | + payload["accountHash"] = account_hash |
| 195 | + if location is not None: |
| 196 | + payload["location"] = location |
| 197 | + |
| 198 | + return True, payload |
| 199 | + |
| 200 | + return handler |
| 201 | + |
| 202 | + |
171 | 203 | async def get_order( |
172 | 204 | ctx: SchwabContext, |
173 | 205 | account_hash: Annotated[str, "Account hash for the Schwab account"], |
@@ -286,7 +318,10 @@ async def place_equity_order( |
286 | 318 |
|
287 | 319 | # Place the order |
288 | 320 | return await call( |
289 | | - client.place_order, account_hash=account_hash, order_spec=order_spec_dict |
| 321 | + client.place_order, |
| 322 | + account_hash=account_hash, |
| 323 | + order_spec=order_spec_dict, |
| 324 | + response_handler=_order_response_handler(ctx, account_hash), |
290 | 325 | ) |
291 | 326 |
|
292 | 327 |
|
@@ -332,7 +367,10 @@ async def place_option_order( |
332 | 367 |
|
333 | 368 | # Place the order |
334 | 369 | return await call( |
335 | | - client.place_order, account_hash=account_hash, order_spec=order_spec_dict |
| 370 | + client.place_order, |
| 371 | + account_hash=account_hash, |
| 372 | + order_spec=order_spec_dict, |
| 373 | + response_handler=_order_response_handler(ctx, account_hash), |
336 | 374 | ) |
337 | 375 |
|
338 | 376 |
|
@@ -433,7 +471,10 @@ async def place_one_cancels_other_order( |
433 | 471 | client = ctx.orders |
434 | 472 |
|
435 | 473 | return await call( |
436 | | - client.place_order, account_hash=account_hash, order_spec=oco_order_spec |
| 474 | + client.place_order, |
| 475 | + account_hash=account_hash, |
| 476 | + order_spec=oco_order_spec, |
| 477 | + response_handler=_order_response_handler(ctx, account_hash), |
437 | 478 | ) |
438 | 479 |
|
439 | 480 |
|
@@ -491,6 +532,7 @@ async def place_first_triggers_second_order( |
491 | 532 | client.place_order, |
492 | 533 | account_hash=account_hash, |
493 | 534 | order_spec=trigger_order_dict, |
| 535 | + response_handler=_order_response_handler(ctx, account_hash), |
494 | 536 | ) |
495 | 537 |
|
496 | 538 |
|
@@ -604,6 +646,7 @@ async def place_bracket_order( |
604 | 646 | client.place_order, |
605 | 647 | account_hash=account_hash, |
606 | 648 | order_spec=bracket_order_dict, |
| 649 | + response_handler=_order_response_handler(ctx, account_hash), |
607 | 650 | ) |
608 | 651 |
|
609 | 652 |
|
@@ -669,7 +712,10 @@ async def place_option_combo_order( |
669 | 712 | ) |
670 | 713 |
|
671 | 714 | return await call( |
672 | | - ctx.orders.place_order, account_hash=account_hash, order_spec=builder.build() |
| 715 | + ctx.orders.place_order, |
| 716 | + account_hash=account_hash, |
| 717 | + order_spec=builder.build(), |
| 718 | + response_handler=_order_response_handler(ctx, account_hash), |
673 | 719 | ) |
674 | 720 |
|
675 | 721 |
|
|
0 commit comments