Hummingbot Connector 6.1.7

Latest

7 September 2026

This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.

CONNECTORCANCELSSHARDSMATCHING-ENGINEPERPETUALFEESRATE-LIMITSDIAGNOSTICSBUG-FIXES

Hummingbot Connector v6.1.7

Release Date: September 7, 2026 Tags: CONNECTOR, CANCELS, SHARDS, MATCHING-ENGINE, PERPETUAL, FEES, RATE-LIMITS, DIAGNOSTICS, BUG-FIXES

Overview

A cancel release, for venues moving markets onto Ecosystem 6.5.0's shard tier. On a sharded market the order rows this connector reads are a projection that lands a few milliseconds after the shard has the order, and a bot that cancels straight off its placement acknowledgement can arrive first. Measured on one loaded shard, 232 of 4,220 cancels were answered Open order not found for orders that were resting in the book. The route now asks the shard, which is the authority for what it holds, and the shard's answer is the answer.

It also corrects the fee your bot is told it paid. The venue reports one fee on the order, fixed when the order is placed; each fill's share of it was divided by the amount filled so far rather than by the order's size, so the first fill of an order carried the whole order's fee and later fills were overstated. A 0.00015152 BTC fill of a 0.001 BTC order was reported at 0.79 USDT — about 6.6% of a 12 USDT trade. Your wallets were always charged correctly; the number a strategy computes its profitability from was not.

The connector files themselves changed, so this is not a backend-only update: reinstall the kit into every Hummingbot checkout and restart the bots, or they keep reporting the old fee. Update Instructions has the commands.

Two more things a bot can see on any install, sharded or not: a perpetual order can now be cancelled by the client order id the bot invented, and an order keeps that id on its own record instead of only in a cache that expires. And when the rate limiter cannot reach Redis, the signed door now holds a reduced budget instead of waving everything through.

Requires Core v6.7.6 and Ecosystem v6.5.0 on every install: the connector's order-status and batch-cancel routes load the shard door that ships in Ecosystem 6.5.0 and answer 503 on every call without it, and the signed-request gate uses the per-caller in-flight cap that ships in Core 6.7.6. On an install that runs no shards the cancel path answers as it did.

Update Instructions

pnpm updator

Restart the backend when the update completes, then reinstall the connector kit into every Hummingbot checkout and restart the bots that run on it:

python install_connectors.py /path/to/hummingbot
cat /path/to/hummingbot/.bicrypto-kit-version     # expect: 2026.09.08

A bot already running keeps the old connector in memory whatever is on disk, so the restart is the step that delivers this. The bot logs its kit version on startup, and the instance card shows it if you have no shell on that machine.

Install the spot and perpetual connectors together. The perpetual one now reads the corrected fee calculation from the spot package, so a half-updated checkout reports the old numbers.


Upgrade Notes

  • Requires Core v6.7.6 and Ecosystem v6.5.0 on every install, not only on a sharded venue: without Ecosystem 6.5.0 the order-status and batch-cancel routes are still registered but every call is refused with 503this endpoint requires an extension that is not installed on this server — and without Core 6.7.6 the signed-request gate calls a core function that is not there. ECO_DOOR is needed only for the sharded-market behaviour: on an install that names no shard symbols and no shadow list the cancel path answers as it did, while clearing or killing ECO_DOOR on a venue that does name them is not a rollback — a cancel whose order has no projected row then answers 503 rather than 404, as the entries below describe.
  • A bot keeps the old fee figures until its checkout is reinstalled. The corrected split and the quieter price lookups live in the connector files, not in the backend. Until then the venue is right and the bot's own reporting is not, which is the same state as before this release.
  • Orders gain a clientOrderId column on the first boot after updating, so the id a bot invents survives the cache it used to live in. Nothing runs by hand.
  • The rate limiter now counts a window with a small server-side script instead of two commands. A Redis endpoint that refuses scripting — some proxies and managed tiers do — makes every signed budget check fall to the in-process bucket described below, at a quarter of each key's limit, with nothing else going wrong. Check that first if bots start seeing 429s with limits smaller than the ones you configured.

Added

An optional cache for the key lookup on every signed request

Every signed request reads its API key from the database, once per request. A market maker signing several requests a second pays for that read every time.

  • Added HB_APIKEY_CACHE_TTL_MS, 0 and therefore off: without it each signed request looks its key up exactly as it did before, with nothing cached and nothing subscribed. Set it, and each process keeps the key row it just verified for that many milliseconds.
  • Added an announcement whenever a key is disabled, enabled, edited, rotated or deleted, so every process drops its copy at once. The kill switch, a deletion, a scope or whitelist change and a rotated secret take effect when they are saved rather than when a cached copy expires. A key changed any other way — direct SQL, say — is held for as long as the interval you set.

Skipping the order read for a bot whose orders have not moved

The two order-derived user streams re-read a bot's whole order partition every second whether or not anything of that bot's has moved, and the frame they build is then almost always identical to the last one and never sent. The read is the whole cost.

  • Added HB_WS_ACTIVITY_GATE, off by default. Switched on, those two streams skip a bot's read on a tick when none of that bot's orders have moved since the last one, and read anyway once HB_WS_RECONCILE_MS (30 s) has passed. The frames themselves are unchanged — only the decision to read moves — and an unknown bot is always read, so a bot never learns of a fill late because the gate guessed.

Diagnose says more, and says it about this server

  • Added a V2 controller support row, which fails when the installed launcher does not advertise --v2. Every strategy this panel generates is a V2 controller and a start is refused without that flag, so a checkout too old to run any of them used to report all-green and then never start, with an error no line of the report accounted for.
  • Added — a launcher that reports no options at all is now a blocking failure rather than a warning, with its own remedy, instead of the generic complaint that --v2 is required.
  • Added — the connector installer prints the interpreter it ran under on a successful run, which is the value the admin panel's Python interpreter field wants, and warns when that interpreter is a conda base environment rather than the one Hummingbot was built in.

A cross-exchange configuration with a paper hedge says so

A live maker with a paper taker is a supported rehearsal and is still allowed — refusing it would strand a ladder already resting. But it is an unhedged market maker for as long as it runs: every maker fill moves real inventory here while the hedge is filled by Hummingbot's simulator, and the strategy's own profit counts hedges that never happened. It ran for an operator with nothing anywhere saying so.

  • Added — the warning now appears where an operator is already looking: in the instance log at start, in the instance's last error, and as a header in the strategy file itself, which travels with the preview, the download and the config a supervised bot is started from.

Changed

Cancelling on a sharded market asks the shard

The single cancel route resolved an order by reading its row, which on a sharded market may not exist yet, and answered 404 for a live order — a refusal the connector cannot act on: it will not treat not found as cancelled, so it keeps the order tracked and asks again, and the order rests on the book holding the customer's funds until one of those cancels lands. It now forwards the cancel to the shard on the order's placement hint and answers from the shard.

  • Changed — on a symbol the shard tier owns, a cancel whose order has no projected row yet is forwarded, by its id, to the shard that the market recorded at placement names. A shard that holds it cancels it. For an order no shard holds, the platform checks the order's own ledger row before answering: one that has filled or been cancelled answers Order is not open (400), which the connector already reads as already-gone; one that never existed answers Open order not found (404); and an open order its shard has not loaded yet answers a retryable 503, so the bot keeps tracking it and asks again. A projected row that exists and is not open is still Open order not found, as before.
  • Changed — when the shard tier owns the symbol but the door is switched off at runtime (the kill switch, a degraded settings bus), the order cannot be reached from this process and the route answers 503 rather than 404, so the connector retries the cancel inside its own cancel budget rather than giving up after the one request a 404 buys it and reporting a failed cancel. The tier owns the symbol when ECO_SHARD_SYMBOLS names it, or when that variable is unset beside a shadow list — a shadow list leaves every symbol it does not name the tier's, while a shadowed symbol is still the single-process engine's and keeps the 404. A venue that shards every market without naming any cannot tell a switched-off door from an install with no tier, and keeps the 404 too.
  • Changed — a cancel-all with no symbol fans out to every shard, and one for a symbol goes to the shard that owns it; each cancels the bot's orders it holds. When a shard cannot be reached the reply is marked truncated, so the caller knows the sweep was incomplete and can repeat it, and the cancels the other shards completed stand.
  • Changed — an order-status poll for an order whose projected row has not landed yet asks the shard that holds it before answering not found; a finished order is still answered from its row.
  • Changed — a cancel now reads the one order row it needs, by the key the platform records when the order is placed and keeps for seven days, instead of reading back every order the account holds on that market. Cancels stop competing with the same account's placements, which a market maker cancelling several times a second feels most. An order older than that, or one whose recorded key cannot be read, takes the read it always took and is answered exactly as before.

The bot door keeps a budget when Redis is down

When the rate limiter could not reach Redis, the signed door answered unlimited: every per-key budget switched off at once, at the moment a venue can least afford it.

  • Changed — a signed request whose budget check cannot reach Redis is now metered from a window kept inside the process, at a quarter of that key's configured limit, and X-RateLimit-Limit and X-RateLimit-Remaining report the smaller figure, so a bot is told the budget it is actually being held to. It keeps trading through the outage and is refused past the reduced ceiling instead of being waved through. The quarter is deliberate: a per-process counter cannot see the other processes serving the same key, so several processes may each grant a quarter. HB_LIMITER_FAIL_CLOSED=false restores the old reading. The unsigned market-data endpoints keep failing open either way, because availability there beats strictness.
  • Changed — the counter itself is one Redis command instead of two, on both the per-key and the per-IP door, and a window's expiry is set when the window is born rather than re-armed on every request. The figures on the wire are the same ones as before; the requirement it adds is in Upgrade Notes.

A client order id in the exchange's own shape is refused

A cancel accepts either the exchange's order id or the bot's own through one path segment, which is unambiguous only while the two shapes cannot be confused. An id minted in the exchange's own form could otherwise name a different order on the same account, and the cancel would land on the wrong one.

  • Changed — a placement or amend that carries a client order id longer than 64 characters, or written in the exchange's own id form, is refused with 422 and the reason, on the spot and perpetual doors alike. Both accepted either before, because the id was never stored on the order; Hummingbot's own ids are unaffected.

Finding the Python interpreter, and saying which one

An operator whose conda lived in /opt was told no conda environment was found, adapted the field's example — which names a home directory — and saved an interpreter that did not exist. Every part of that sequence is corrected.

  • Changed — auto-detect finds a conda installation wherever one conventionally lives: any conda, miniconda, anaconda, miniforge or mambaforge directory one level inside your home directory, /opt, /usr/local, /root, C:\ProgramData, your AppData folder or the Hummingbot checkout's parent, plus whatever conda told the backend about itself. It used to check a fixed list that did not include /opt/anaconda3.
  • Changed — it also offers the environments conda has recorded for itself, so one created with --prefix or under a custom environments directory is found; neither can be reached by scanning an installation's own environments folder, which is where this step used to look.
  • Changed — when the interpreter check fails, Diagnose names up to three interpreters that actually exist on this server, in full, instead of one fixed home-directory example. When it finds none it says where it looked, names the OS account the backend runs as, and tells you to run conda env list as the account that installed Hummingbot.
  • Changed — creating or editing an instance refuses an interpreter that cannot be spawned, with the reason, rather than saving a certain failure. On an edit the check runs only when the interpreter itself changes, so lowering a memory cap or turning autoRestart off is never blocked by a broken interpreter — and autoRestart is the switch that stops the crash loop one causes.
  • Changed — a failed start carries each check's suggested fix into the instance log and the recorded last error, not only into the Diagnose dialog, which is where an operator looks first.
  • Changed — the Config directory check names the OS account the backend runs as, which is often not the account that installed Hummingbot, and the files the panel writes there.

Fixed

A partial fill reported the whole order's fee

The venue reports one fee on the order, calculated across the whole order when it is placed and never rewritten as fills land; the matching engine settles each fill at its own share and records that share on the trade, so the money moved was always right. The number derived from it was not: the connectors and the user-trades stream divided the order's fee by the amount filled so far rather than by the order's size, so the first fill of an order carried the entire fee and every later fill was overstated. A cross-exchange strategy decides whether to hold or re-quote a level from a profitability figure computed net of exactly that number.

  • Fixed — a fill's share is now the order's fee in proportion to the fill against the order's size, on the spot connector, the perpetual connector and the user-trades stream. The shares of a partly filled order sum to the order's fee instead of exceeding it.

An order could outlive the only record of its client order id

The client order id a bot invents was kept only in a placement alias — a cache with a seven-day life, evicted under memory pressure and gone when the cache restarts without persistence. Once it was lost, status and cancel answers carried the exchange's own id in the client-id field, and a bot that matches its in-flight orders by its own id could no longer recognise, or cancel, an order that went on resting and holding the customer's funds.

  • Fixed — spot and perpetual placements record the client order id on the order itself as well as in the alias, and an amend records the replacement's the same way, so the id survives an eviction or a restart.

A perpetual order could not be cancelled by its client order id

The perpetual cancel route matched the exchange's own order id only. A bot that cancels before the placement response arrives, or after that response was lost, holds nothing but the client order id it invented, and every such cancel was answered Open perp order not found for an order resting on the book. The spot route has accepted either id for some time.

  • Fixed — the perpetual cancel route accepts either id, resolving a client order id through the placement alias or the order's own record. A placement that is known to have failed answers never created (400) and one still in flight a retryable 503, as the spot route does.

A cancel-all for one market could claim a clean sweep it had not made

Reading an account's open orders stops after a page budget and says so. The all-markets sweep passed that on; the single-market one dropped it, so an account with a long history was told the market was clear while orders it never read were still resting.

  • Fixed — a single-market cancel-all is marked truncated when the read stopped early, so a bot knows to repeat it.

Internal price lookups logged an error every minute

Hummingbot builds throwaway connector instances with blank configuration for its own rate lookups. Such an instance cannot reach the venue and is not a fault, but it raised — and the framework's own wrapper logs a raised exception with a full traceback, once per pair per rate cycle, for ever. That is the noise that hides a real fault, and it produced a support ticket from an operator whose bot was trading perfectly.

  • Fixed — an unconfigured lookup instance, and a market with no trades yet, answer quietly on both connectors. Nothing about a real bot's prices changes: the caller dropped the value either way.

Smaller repairs

  • Fixed — the WSL and VMware guest probes look for the interpreter under /opt/miniconda3, /opt/anaconda3 and /opt/miniforge3 as well as /opt/conda and the home-directory installs, so a guest with a system-wide conda is no longer reported as having no interpreter.
  • FixedExecutable not found now says the path either does not exist or cannot be read by the account the backend runs as, and names that account. The backend cannot tell those apart — it looks as itself — and the bare message sent operators hunting for a missing file that was there all along.