diff --git a/packages/keel-broker-robinhood/keel_broker_robinhood/translate.py b/packages/keel-broker-robinhood/keel_broker_robinhood/translate.py index dcb0392b..e918b09f 100644 --- a/packages/keel-broker-robinhood/keel_broker_robinhood/translate.py +++ b/packages/keel-broker-robinhood/keel_broker_robinhood/translate.py @@ -49,12 +49,27 @@ #: by capitalizing the venue's spelling. Keeping the mapping explicit, rather than deriving one #: from the other programmatically, means a new Robinhood state added by a future API version #: fails to translate (via `to_port_status`'s `PENDING` fallback) instead of silently guessing. +#: +#: Robinhood's docs publish two `state` enums that do not agree with each other: the order-response +#: object lists `partially_filled` and omits `pending`; the `GET /orders/` query filter lists +#: `pending` and omits `partially_filled`. This table covers the union of both, since either shape +#: could plausibly arrive here, rather than picking one enum and dropping values from the other. +#: `partially_filled` maps to `OPEN`, not `PENDING`: a partially-filled GTC limit is still resting +#: and working at the venue, and `PENDING` would read as not-yet-working, which misdescribes an +#: order the venue has already begun executing. `OPEN` is in the port's accepted status vocabulary +#: (see the conformance suite's status assertion). +#: +#: `partially_filled`'s exact spelling is doc-sourced, not verified against a live order -- no +#: order object has ever been observed at this venue (see #198) -- and the two docs pages +#: disagree on which enum even applies here. This entry is the order-response enum's spelling; +#: treat it as the best available guess, not a confirmed fact, until #198 closes. STATE_TO_PORT_STATUS: dict[str, str] = { "open": "OPEN", "canceled": "CANCELLED", "filled": "FILLED", "failed": "FAILED", "pending": "PENDING", + "partially_filled": "OPEN", } diff --git a/tests/broker_robinhood/test_translate.py b/tests/broker_robinhood/test_translate.py index b1437ec6..98cf576d 100644 --- a/tests/broker_robinhood/test_translate.py +++ b/tests/broker_robinhood/test_translate.py @@ -268,6 +268,15 @@ def test_to_port_status_maps_every_known_state(state: str, expected: str) -> Non assert STATE_TO_PORT_STATUS[state] == expected +def test_to_port_status_maps_partially_filled_to_open_not_pending() -> None: + """`partially_filled` is the order-response enum's spelling for a resting order that has + started filling -- still working at the venue, not merely accepted-but-untouched. `OPEN` is + the honest port status; falling through to `PENDING` (the pre-fix behaviour) would read as + not-yet-working, which is wrong for an order the venue has partially executed. See #226.""" + assert to_port_status("partially_filled") == "OPEN" + assert STATE_TO_PORT_STATUS["partially_filled"] == "OPEN" + + def test_to_port_status_defaults_an_unknown_state_to_pending_not_failed() -> None: """An unrecognised state means the adapter does not know the outcome -- not that the order failed. `PENDING` keeps the order under observation; `FAILED` would declare a terminal