Skip to content

Commit 2048ae2

Browse files
committed
refactor(live): isolate final fill classification
1 parent db883ca commit 2048ae2

3 files changed

Lines changed: 18 additions & 54 deletions

File tree

backend_api_python/app/services/pending_order_worker.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
)
7676
from app.services.pending_order_position_sync import PendingOrderPositionSyncMixin
7777
from app.services.pending_orders.sent_order_recovery import (
78-
normalize_live_order_status,
78+
is_final_fill, normalize_live_order_status,
7979
tracked_fill_baseline,
8080
)
8181
from app.services.live_trading.binance import BinanceFuturesClient
@@ -110,22 +110,6 @@
110110
ALPACA_FILL_DELTA_EPSILON = 1e-8
111111

112112

113-
def _is_final_fill(
114-
*,
115-
requested: float,
116-
filled: float,
117-
avg_price: float,
118-
status: Any = "",
119-
) -> bool:
120-
requested_qty = max(0.0, float(requested or 0.0))
121-
filled_qty = max(0.0, float(filled or 0.0))
122-
if requested_qty <= 0 or filled_qty <= 0 or float(avg_price or 0.0) <= 0:
123-
return False
124-
if normalize_live_order_status(status) == "filled":
125-
return True
126-
return filled_qty >= requested_qty * 0.999999
127-
128-
129113
def _broker_order_type(payload: Dict[str, Any], ref_price: float) -> Tuple[str, float]:
130114
order_type = str(payload.get("order_type") or "market").strip().lower()
131115
if order_type == "maker_then_market":
@@ -2190,12 +2174,7 @@ def _execute_live_order(self, *, order_id: int, order_row: Dict[str, Any], paylo
21902174
filled=filled,
21912175
avg_price=avg_price,
21922176
executed_at=executed_at if filled > 0 else None,
2193-
final_filled=_is_final_fill(
2194-
requested=amount,
2195-
filled=filled,
2196-
avg_price=avg_price,
2197-
status=execution_result.status,
2198-
),
2177+
final_filled=is_final_fill(amount, filled, avg_price, execution_result.status),
21992178
)
22002179
_console_print(f"[worker] order sent: strategy_id={strategy_id} pending_id={order_id} exchange={res.exchange_id} order_id={res.exchange_order_id} filled={filled} avg={avg_price}")
22012180
except Exception as e:
@@ -2392,12 +2371,7 @@ def _execute_ibkr_order(
23922371
filled=filled,
23932372
avg_price=avg_price,
23942373
executed_at=executed_at if filled > 0 else None,
2395-
final_filled=_is_final_fill(
2396-
requested=amount,
2397-
filled=filled,
2398-
avg_price=avg_price,
2399-
status=result.status,
2400-
),
2374+
final_filled=is_final_fill(amount, filled, avg_price, result.status),
24012375
)
24022376
_console_print(f"[worker] IBKR order sent: strategy_id={strategy_id} pending_id={order_id} order_id={exchange_order_id} filled={filled} avg={avg_price}")
24032377

@@ -2575,12 +2549,7 @@ def _execute_alpaca_order(
25752549
filled=filled,
25762550
avg_price=avg_price,
25772551
executed_at=executed_at if filled > 0 else None,
2578-
final_filled=_is_final_fill(
2579-
requested=amount,
2580-
filled=filled,
2581-
avg_price=avg_price,
2582-
status=result.status,
2583-
),
2552+
final_filled=is_final_fill(amount, filled, avg_price, result.status),
25842553
)
25852554
_console_print(
25862555
f"[worker] Alpaca order sent: strategy_id={strategy_id} pending_id={order_id} "

backend_api_python/app/services/pending_orders/sent_order_recovery.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ def normalize_live_order_status(status: str) -> str:
1919
return "unknown"
2020

2121

22+
def is_final_fill(requested: float, filled: float, avg_price: float, status: Any = "") -> bool:
23+
requested_qty = max(0.0, float(requested or 0.0))
24+
filled_qty = max(0.0, float(filled or 0.0))
25+
if requested_qty <= 0 or filled_qty <= 0 or float(avg_price or 0.0) <= 0:
26+
return False
27+
if normalize_live_order_status(status) == "filled":
28+
return True
29+
return filled_qty >= requested_qty * 0.999999
30+
31+
2232
def tracked_fill_baseline(
2333
row: Dict[str, Any],
2434
*,

backend_api_python/tests/test_pending_order_worker_live_sync.py

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from app.services import pending_order_worker as worker_module
6-
from app.services.pending_orders.sent_order_recovery import normalize_live_order_status
6+
from app.services.pending_orders.sent_order_recovery import is_final_fill, normalize_live_order_status
77

88

99
def _row(*, filled: float, avg_price: float):
@@ -142,30 +142,15 @@ def test_live_sent_sync_keeps_terminal_fill_open_when_average_price_is_missing(m
142142

143143

144144
def test_exchange_filled_status_accepts_quantity_precision_remainder():
145-
assert worker_module._is_final_fill(
146-
requested=0.1617456789,
147-
filled=0.161745,
148-
avg_price=58_705.0,
149-
status="FILLED",
150-
) is True
145+
assert is_final_fill(0.1617456789, 0.161745, 58_705.0, "FILLED") is True
151146

152147

153148
def test_non_terminal_partial_fill_remains_open():
154-
assert worker_module._is_final_fill(
155-
requested=1.0,
156-
filled=0.75,
157-
avg_price=58_705.0,
158-
status="PARTIALLY_FILLED",
159-
) is False
149+
assert is_final_fill(1.0, 0.75, 58_705.0, "PARTIALLY_FILLED") is False
160150

161151

162152
def test_terminal_fill_without_average_price_remains_open():
163-
assert worker_module._is_final_fill(
164-
requested=1.0,
165-
filled=1.0,
166-
avg_price=0.0,
167-
status="FILLED",
168-
) is False
153+
assert is_final_fill(1.0, 1.0, 0.0, "FILLED") is False
169154

170155

171156
def test_ibkr_submission_never_fabricates_a_fill_from_requested_amount(monkeypatch):

0 commit comments

Comments
 (0)