@ -270,9 +270,10 @@ class TestCancelStaleOrders:
def test_cancels_open_orders ( self , session , mock_broker , state_manager ) :
def test_cancels_open_orders ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
prefix = f " pt- { session . session_id [ : 8 ] } - "
mock_broker . list_orders . return_value = [
mock_broker . list_orders . return_value = [
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 ),
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = f " { prefix } aaa " ),
Order ( id = " ord2 " , symbol = " TSLA " , qty = 5 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 ),
Order ( id = " ord2 " , symbol = " TSLA " , qty = 5 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = f " { prefix } bbb " ),
]
]
cancelled = engine . _cancel_stale_orders ( )
cancelled = engine . _cancel_stale_orders ( )
assert len ( cancelled ) == 2
assert len ( cancelled ) == 2
@ -280,13 +281,28 @@ class TestCancelStaleOrders:
def test_handles_cancel_failure ( self , session , mock_broker , state_manager ) :
def test_handles_cancel_failure ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
prefix = f " pt- { session . session_id [ : 8 ] } - "
mock_broker . list_orders . return_value = [
mock_broker . list_orders . return_value = [
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 ),
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = f " { prefix } aaa " ),
]
]
mock_broker . cancel_order . side_effect = Exception ( " API error " )
mock_broker . cancel_order . side_effect = Exception ( " API error " )
cancelled = engine . _cancel_stale_orders ( )
cancelled = engine . _cancel_stale_orders ( )
assert cancelled == [ ] # failed to cancel
assert cancelled == [ ] # failed to cancel
def test_skips_other_session_orders ( self , session , mock_broker , state_manager ) :
""" Orders from other sessions (different prefix) must not be cancelled. """
engine = _make_engine ( session , mock_broker , state_manager )
prefix = f " pt- { session . session_id [ : 8 ] } - "
mock_broker . list_orders . return_value = [
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = f " { prefix } aaa " ) ,
Order ( id = " ord2 " , symbol = " TSLA " , qty = 5 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = " pt-othersess-bbb " ) ,
Order ( id = " ord3 " , symbol = " GOOG " , qty = 2 , side = " buy " , status = " open " , filled_avg_price = None , filled_qty = 0 , client_order_id = None ) ,
]
cancelled = engine . _cancel_stale_orders ( )
assert len ( cancelled ) == 1
assert " AAPL " in cancelled [ 0 ]
assert mock_broker . cancel_order . call_count == 1
def test_handles_list_orders_failure ( self , session , mock_broker , state_manager ) :
def test_handles_list_orders_failure ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
mock_broker . list_orders . side_effect = Exception ( " API down " )
mock_broker . list_orders . side_effect = Exception ( " API down " )
@ -304,9 +320,9 @@ class TestVerifyOrderFill:
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
status = " filled " , filled_avg_price = 101.5 , filled_qty = 10 ,
status = " filled " , filled_avg_price = 101.5 , filled_qty = 10 ,
)
)
result = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
order, reason = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
assert result is not None
assert order is not None
assert result . filled_avg_price == 101.5
assert order . filled_avg_price == 101.5
def test_rejected_order ( self , session , mock_broker , state_manager ) :
def test_rejected_order ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
@ -314,8 +330,9 @@ class TestVerifyOrderFill:
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
status = " rejected " , filled_avg_price = None , filled_qty = 0 ,
status = " rejected " , filled_avg_price = None , filled_qty = 0 ,
)
)
result = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
order , reason = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
assert result is None
assert order is None
assert " rejected " in reason
def test_timeout ( self , session , mock_broker , state_manager ) :
def test_timeout ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
@ -323,8 +340,9 @@ class TestVerifyOrderFill:
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
status = " new " , filled_avg_price = None , filled_qty = 0 ,
status = " new " , filled_avg_price = None , filled_qty = 0 ,
)
)
result = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
order , reason = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 0.1 )
assert result is None
assert order is None
assert " timeout " in reason
def test_api_error_retries ( self , session , mock_broker , state_manager ) :
def test_api_error_retries ( self , session , mock_broker , state_manager ) :
engine = _make_engine ( session , mock_broker , state_manager )
engine = _make_engine ( session , mock_broker , state_manager )
@ -333,9 +351,9 @@ class TestVerifyOrderFill:
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
Order ( id = " ord1 " , symbol = " AAPL " , qty = 10 , side = " buy " ,
status = " filled " , filled_avg_price = 102.0 , filled_qty = 10 ) ,
status = " filled " , filled_avg_price = 102.0 , filled_qty = 10 ) ,
]
]
result = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 2.0 )
order, reason = engine . _verify_order_fill ( " ord1 " , " AAPL " , timeout_sec = 2.0 )
assert result is not None
assert order is not None
assert result . filled_avg_price == 102.0
assert order . filled_avg_price == 102.0
# ── _check_kill_switch ──────────────────────────────────────────────────────
# ── _check_kill_switch ──────────────────────────────────────────────────────