Repository navigation
(fix) perpetual position mode follows the exchange; switch endpoint reports only what the exchange did - #213
fengtality wants to merge 4 commits into
Conversation
|
2db2cee to
698e01e
Compare
524626f to
903e52d
Compare
|
Adversarial review — the harshest of the three; the PR's original narrative was factually wrong and the endpoint had three residual lies. All fixed in the latest commit; the PR body has been rewritten accordingly.
Compat (unchanged, documented): the 400-on-empty is external-breaking until |
rapcmia
left a comment
There was a problem hiding this comment.
- git switch --detach origin/fix/207-throttler-pair-limits
- git switch --detach origin/fix/208-per-pair-trading-rules
- git switch --detach origin/fix/210-position-mode-truth
- Setup with bitget_perpetual
- Empty-pair position-mode request returned HTTP 400.
- Valid BTC-USDT pair registration and HEDGE switch succeeded.
- Position query reported HEDGE, matching the connector and exchange.
- Unsupported BTC-USDS returned HTTP 400 using ONEWAY without changing the valid pair’s state.
- An active Bitget order caused the expected HTTP 502 when switching to ONEWAY.
- The test order was cancelled and confirmed inactive.
- After restart, Bitget’s exchange mode remained HEDGE. Once BTC-USDT was registered, the local connector adopted HEDGE and matched the exchange.
903e52d to
d276034
Compare
…s reported only once the exchange makes it Connectors are created with no trading pairs, so the HEDGE forced at init could not reach the exchange, and bybit/bitget flipped only their local mode to HEDGE. On one-way accounts their orders then went out with the wrong position side. Init now reads the account's mode instead, and bitget, which needs a pair to read it, reads it again when its first market is added. The position-mode endpoint takes an optional trading_pair to register first, refuses when no pair is registered, and awaits the exchange call, returning 502 when the exchange keeps the old mode instead of reporting success for a switch that never happened. Fixes #210. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@rapcmia could you QA this with bitget_perpetual? Ideally on an account you can flip between one-way and hedge. Small sizes are fine; one pair, e.g. Restart the API between cases so the connector is created fresh. Check the local mode with 1. One-way account, init. Set the account to one-way in the bitget UI → restart → GET position-mode. 2. Hedge account, executor adds the market. Set the account to hedge → restart → GET shows 3. Switch with no pair registered. Restart → 4. Switch through a pair. 5. Known gap: direct orders only. Hedge account → restart → If you have a bybit account: repeat case 1. Expect |
…an executor's does POST /trading/orders never registered its pair on the connector, so on bitget, which can only read the account's position mode with a pair registered, a connector that only took direct orders stayed at the ONEWAY default and sent hedge-mode accounts orders without tradeSide. It also left bitget's position refresh with no product type to query. place_trade now registers the pair on perpetual connectors through the same helper as add_market and the position-mode endpoint, which reads the mode on the first pair. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@rapcmia update to the QA checklist: the direct-order gap is fixed in 5. Direct orders only. Hedge account → restart → |
Tested on ccddb71 with bitget_perpetual, using the API routes.Passed:
Failed:
Tested on ccddb71 with bitget_perpetual, using the API routes.Passed:
Failed:
@fengtality I tested with bitget_perpetual on ea55b40, using only the API routes and restarting the API between cases:
Case 2 still fails. After a restart on a hedge account, a new position executor leaves the mode on ONEWAY, all its open orders are refused, and it ends FAILED. It looks like add_market sets up the order book before register_trading_pair runs (services/trading_service.py#L163-L175), so the pair is already registered and the mode is never read. The "Position mode initialized" log line doesn't show at the default log level, so I checked with GET position-mode instead. |
… as a direct order's does add_market set up the order book before registering the pair, and the order book tracker shares the connector's pair list, so the pair was already there and the first-pair read of the account's mode never ran. On a bitget hedge account the local mode stayed ONEWAY and every executor order was refused. add_market now notes whether the pair is the first before the order book registers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pyinjective configures the root logger when imported, so main's basicConfig was a no-op and every INFO line was dropped, including the connector's position-mode adoption. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rapcmia
left a comment
There was a problem hiding this comment.
- Position-mode guardrails, rejected a mode change with no registered pair or an unsupported pair, while preserving the valid connector mode.
- Valid-pair mode changes, set and read Bitget Perpetual HEDGE mode successfully with a supported trading pair.
- Open-position protection, rejected a switch to ONEWAY while a controlled SOL-USDT position was open and kept HEDGE active until cleanup.
- One-way initialization and direct orders, confirmed the expected ONEWAY fallback after restart and verified that first-pair registration supports direct SOL-USDT trading.
- Position-mode adoption after restart, started with the local ONEWAY fallback, registered SOL-USDT, adopted Bitget's HEDGE mode, opened a 0.1 SOL position at 5x, and closed it without leaving a position or active order.
- API INFO logging, confirmed the HEDGE initialization and executor-creation messages appear in the HAPI container logs.
Fixes #210. Rebuilt on
main(was stacked on the closed #212; no longer depends on #211).Init: read the account's mode instead of forcing HEDGE
_create_and_initialize_trading_connectornow calls hummingbot's own_initialize_position_mode()(read the exchange, adopt it) instead ofset_position_mode(HEDGE)with no pairs registered. On binance/okx/gate_io the result is the same as before. On bybit and bitget local no longer flips to HEDGE regardless of the account.bitget can only read the mode once a pair is registered, so a perpetual connector reads it again when it gets its first pair. Pairs are registered through one helper,
register_trading_pair, from all three places that register them:add_market(executors),place_trade(POST /trading/orders), and the position-mode endpoint. So the mode is read before the first order either way.place_tradedidn't register pairs before. On bitget that also meant_update_positionshad no product type to query for a connector used only for direct orders.Switch endpoint
PositionModeRequesttakes an optionaltrading_pair, registered first (unlisted pair → 400, not registered). It's registered beforesupported_position_modes()is checked, because bybit's answer depends on the registered pairs.trading_pair, instead of a false success._execute_set_position_modeinstead of the fire-and-forgetset_position_mode, then checks the local mode: 502 when the exchange kept the old mode (open positions, -4068…).Behavior change
POST position-mode {"position_mode": "HEDGE", "trading_pair": ...}.hummingbot-api-clientneeds the optionaltrading_pairfield.Tests
test/test_position_mode_sync.pydrives the realBitgetPerpetualDerivativewith only_api_get/_api_postreplaced by a fake account: first pair adopts the account's HEDGE; no-pair switch → 400 with no exchange call; unlisted pair → 400, not registered; switch through a pair reaches the exchange; exchange rejection → 502; a direct order on a fresh connector for a hedge account goes out withtradeSide. The first two and the direct-order test fail onmainfor the reasons above. Full suite: 933 passed, 1 skipped.QA
Please test with bitget_perpetual — see the checklist comment below.
🤖 Generated with Claude Code