@@ -3566,6 +3566,107 @@ def test_remote_trade_update_accepts_raw_okx_trade_aliases_and_fee():
35663566 broker .stop ()
35673567
35683568
3569+ def test_remote_trade_update_accepts_raw_bybit_v5_execution_aliases_and_fee ():
3570+ """Raw Bybit V5 execution events must use exchange fill fields and exact fees."""
3571+ symbol = "BTCUSDT"
3572+ client = FakeBtApiClient (
3573+ history = {symbol : [make_bar (0 , 100.0 , 101.0 , 99.0 , 100.5 )]},
3574+ )
3575+ store = make_store (api = client , provider = "bybit" )
3576+ data = store .getdata (dataname = symbol )
3577+ broker = store .getbroker (account_refresh_interval = 60.0 , positions_refresh_interval = 60.0 )
3578+
3579+ data ._start ()
3580+ assert data .load () is True
3581+ broker .start ()
3582+ broker .setcommission (
3583+ commission = 10.0 ,
3584+ commtype = bt .CommInfoBase .COMM_FIXED ,
3585+ )
3586+ try :
3587+ order = broker .buy (
3588+ owner = None ,
3589+ data = data ,
3590+ size = 2 ,
3591+ price = 101.0 ,
3592+ exectype = bt .Order .Limit ,
3593+ )
3594+
3595+ client .push_broker_update (
3596+ {
3597+ "kind" : "trade" ,
3598+ "exchange" : "Bybit" ,
3599+ "orderId" : "btapi-1" ,
3600+ "orderLinkId" : "btapi-1" ,
3601+ "execID" : "bybit-exec-1" ,
3602+ "symbol" : symbol ,
3603+ "side" : "Buy" ,
3604+ "execQty" : "1" ,
3605+ "execPrice" : "101.5" ,
3606+ "execFee" : "0.15" ,
3607+ "feeCurrency" : "USDT" ,
3608+ "isMaker" : False ,
3609+ }
3610+ )
3611+ broker .next ()
3612+
3613+ assert order .status == bt .Order .Partial
3614+ assert order .executed .size == pytest .approx (1.0 )
3615+ assert order .executed .price == pytest .approx (101.5 )
3616+ assert order .executed .comm == pytest .approx (0.15 )
3617+ assert broker .positions [symbol ].size == pytest .approx (1.0 )
3618+ assert broker .positions [symbol ].price == pytest .approx (101.5 )
3619+
3620+ client .push_broker_update (
3621+ {
3622+ "kind" : "trade" ,
3623+ "exchange" : "Bybit" ,
3624+ "orderId" : "btapi-1" ,
3625+ "orderLinkId" : "btapi-1" ,
3626+ "execID" : "bybit-exec-1" ,
3627+ "symbol" : symbol ,
3628+ "side" : "Buy" ,
3629+ "execQty" : "1" ,
3630+ "execPrice" : "102.0" ,
3631+ "execFee" : "9.99" ,
3632+ "feeCurrency" : "USDT" ,
3633+ "isMaker" : False ,
3634+ }
3635+ )
3636+ broker .next ()
3637+
3638+ assert order .status == bt .Order .Partial
3639+ assert order .executed .size == pytest .approx (1.0 )
3640+ assert order .executed .comm == pytest .approx (0.15 )
3641+
3642+ client .push_broker_update (
3643+ {
3644+ "kind" : "trade" ,
3645+ "exchange" : "Bybit" ,
3646+ "orderId" : "btapi-1" ,
3647+ "orderLinkId" : "btapi-1" ,
3648+ "execID" : "bybit-exec-2" ,
3649+ "symbol" : symbol ,
3650+ "side" : "Buy" ,
3651+ "execQty" : "1" ,
3652+ "execPrice" : "102.0" ,
3653+ "execFee" : "0.20" ,
3654+ "feeCurrency" : "USDT" ,
3655+ "isMaker" : False ,
3656+ }
3657+ )
3658+ broker .next ()
3659+
3660+ assert order .status == bt .Order .Completed
3661+ assert order .executed .size == pytest .approx (2.0 )
3662+ assert order .executed .price == pytest .approx (101.75 )
3663+ assert order .executed .comm == pytest .approx (0.35 )
3664+ assert broker .positions [symbol ].size == pytest .approx (2.0 )
3665+ assert broker .positions [symbol ].price == pytest .approx (101.75 )
3666+ finally :
3667+ broker .stop ()
3668+
3669+
35693670def test_remote_trade_update_without_price_is_ignored_not_zero_filled ():
35703671 """Malformed fills must not execute locally at price zero."""
35713672 client = FakeBtApiClient (
0 commit comments