Skip to content

Commit eed586c

Browse files
author
yunjinqi
committed
fix: accept raw bybit execution fills
1 parent f0e21ee commit eed586c

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

backtrader/brokers/btapibroker.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@
188188
"fillPrice",
189189
"fill_px",
190190
"fillPx",
191+
"exec_price",
192+
"execPrice",
193+
"execution_price",
194+
"executionPrice",
191195
"trade_price",
192196
"tradePrice",
193197
"avg_price",
@@ -2416,7 +2420,9 @@ def _trade_dedupe_key(self, update, order=None):
24162420
"TradeID",
24172421
"exec_id",
24182422
"execId",
2423+
"execID",
24192424
"execution_id",
2425+
"executionId",
24202426
"fill_id",
24212427
"fillId",
24222428
)
@@ -2446,6 +2452,7 @@ def _trade_update_details(self, update, order=None, **extra):
24462452
for key in (
24472453
"kind",
24482454
"trade_id",
2455+
"execID",
24492456
"external_order_id",
24502457
"externalOrderId",
24512458
"venue_order_id",
@@ -2474,9 +2481,12 @@ def _trade_update_details(self, update, order=None, **extra):
24742481
"posSide",
24752482
"offset",
24762483
"size",
2484+
"execQty",
24772485
"fillSz",
24782486
"accFillSz",
24792487
"price",
2488+
"execPrice",
2489+
"execFee",
24802490
"fillPx",
24812491
"avgPx",
24822492
"px",
@@ -3135,6 +3145,11 @@ def _remote_commission(cls, update):
31353145
"comm",
31363146
"fee",
31373147
"fees",
3148+
"exec_fee",
3149+
"execFee",
3150+
"execFeeV2",
3151+
"fill_fee",
3152+
"fillFee",
31383153
"trade_fee",
31393154
"trade_commission",
31403155
"commission_amount",

tests/unit/brokers/test_btapibroker.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
35693670
def 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

Comments
 (0)