Bot Instances
Running your own Hummingbot market makers on the platform server — detection, provisioning, the diagnostic doctor, the desired-state supervisor, memory ceilings, crash diagnosis and live logs, with no terminal.
Admin → Hummingbot → Bot Instances runs Hummingbot on the platform server
itself and controls it from the browser. Register a checkout once and from then
on start, stop, restart, diagnose, reinstall the connector and read live logs
without opening a terminal.
This is for your own market making — providing liquidity on your own books. Your users are unaffected; they continue to run Hummingbot on their own machines against their own API keys, and both models work at the same time.
One Hummingbot process costs roughly 400–700 MB of RAM for a single connector on one pair, and up to about 1.2 GB for XEMM, which runs two. That server is already running your database, Redis, the backend, the frontend — and ScyllaDB if Ecosystem is installed. A handful of your own bots is comfortable; one per user is not, and when the host runs out of memory the kernel may pick your database rather than a bot.
Before you start
Hummingbot has to exist on the server. The panel supervises a checkout; it can fetch the source for you, but it cannot complete the build inside an HTTP request. Two values identify an install:
| Value | Example |
|---|---|
Install path — the checkout root, containing hummingbot/ and bin/ |
/home/user/hummingbot |
| Python interpreter — the conda environment's python | /home/user/miniconda3/envs/hummingbot/bin/python |
The backend process does not inherit your shell's PATH. A bare python
resolves to whatever the service user happens to have — frequently the wrong
environment, or Python 2.7, or nothing at all.
Detection and provisioning
Opening Add instance runs a detection pass first. It searches a bounded set of locations — a fixed list of roots, one level of expansion, never a recursive disk walk, because it runs synchronously inside an admin request on a production server. It offers what it finds with an origin and a confidence, so a wrong pick is obvious, and it pre-fills the exchange URL from the address you are browsing and sizes the memory limit against the host's free memory.
A candidate that would land on the connector kit shipped with the platform is
rejected rather than offered. <platform-root>/hummingbot is the obvious guess
and is exactly where the kit lives, so that flag is what stops the panel handing
you a path the doctor is guaranteed to reject.
If nothing is installed, Provision prepares a location:
| Action | Does |
|---|---|
| Check | Validates the target path only — nothing is written |
| Create | Creates the directory |
| Install | Creates it and clones the Hummingbot source into it |
It refuses filesystem roots, the platform's own directory and public web roots, and requires roughly 2 GB free. It then prints the exact remaining command rather than pretending to run a ten-minute Cython build inside a web request:
cd /path/to/target && ./install && conda activate hummingbot && ./compileconda activate has to happen between the two: ./install creates the
environment and ./compile must run inside it.
On a Windows host there is no runnable command, because ./install is a bash
script and Hummingbot's source build is not supported natively on Windows. The
panel says so, and offers to provision into a WSL distribution instead. It
also lists running VMware guests, because WSL 2 needs Hyper-V and Hyper-V
costs VMware Workstation its acceleration, so operators running Linux in
Workstation usually have WSL unavailable. Both listings are about where to
build: a bot is always run by the configured interpreter on the host itself.
Registering an instance
Nothing starts on save. desiredStatus defaults to STOPPED so you can diagnose
the configuration before a bot ever touches the book.
| Field | Meaning |
|---|---|
| Name | A label, e.g. "BTC-USDT market maker" |
| Strategy preset | A preset from the Strategy Studio. Its YAML is regenerated into the checkout on every start |
| Market | Chosen from the real market list, not typed. Overrides the preset's own pair |
| Install path | Absolute path to the checkout |
| Python interpreter | Absolute path to the environment's python |
| Trading credentials | The API key this bot signs with — pick one or mint one from the form |
| Exchange base URL | The URL the connector dials, normally this deployment's own public URL |
| Config password | Hummingbot's own password, which decrypts its stored connector credentials |
| Memory limit | The bot is killed above this. Default 1536 MB. Enforced on Linux |
| Auto-restart | Restart after a crash, with backoff |
The market has to exist
Registering or starting an instance whose market the exchange does not list is
refused, with the pairs that do exist. Previously this produced the worst kind of
failure — a completely successful start: the connector was created, the process
stayed alive, the panel showed RUNNING, and the bot logged
bicrypto is not ready. Please wait... forever without ever quoting, because its
book never arrived.
The check runs again at start, because a market can be delisted between choosing it and running. On an install without the Ecosystem addon the market list cannot be read, so the check yields nothing and starting is allowed — refusing on the basis of a list that cannot be seen would be worse than the hang it prevents.
Trading credentials
Hummingbot will not trade a connector it has no keys for, and it keeps those keys inside its own install rather than reading yours — so the supervisor writes them there at start time from whatever is selected here. Without a key the bot loads its strategy and then exits.
A key minted from this form is scoped to what a market maker needs and no more — read balances and markets, place and cancel orders of the relevant type, and for perpetuals manage its own positions. Never key-management scopes, so a leaked secret cannot mint more keys. The secret is written straight into the Hummingbot install and never returned to the browser.
The config password
Hummingbot's one-time config-password step only exists on its interactive path:
login_prompt() walks a user through creating conf/.password_verification, and
there is no equivalent under --headless, so a fresh checkout dies with a raw
FileNotFoundError. The panel performs that step before launch.
That file is also the only way to detect a wrong password, because every
encrypted connector key under conf/connectors/ is sealed with the same secret.
Rewriting it on a mismatch would turn "you typed the wrong password" into "every
API key you saved is now permanently undecryptable", silently. A mismatch is
reported and you decide.
The stored password is encrypted at rest with a key derived from
APP_ACCESS_TOKEN_SECRET, domain-separated from anything else that secret
protects, and passed to the child process through its environment — never
through argv, which is world-readable in ps on most Linux hosts. Rotating that
secret invalidates stored passwords; the panel detects it and asks you to
re-enter, rather than failing the bot with an obscure error.
Diagnose before you start
Diagnose tests the real server, right now, and reports each check with what was found and how to fix it:
| Check | Catches |
|---|---|
| Hummingbot install path | The directory exists and is genuinely a checkout |
| Launcher script | Which entry point will be used |
| Python interpreter | It runs, and which version it is |
| Hummingbot importable | That this interpreter and this checkout are a matching pair |
| Bicrypto connector | Installed, and not nested |
| Config directory | Exists and is writable — the panel writes controller YAML into it |
| Launcher capabilities | Which options this build supports, probed rather than assumed |
| Headless mode | Whether this build accepts it |
| Memory headroom | Free memory against this instance's cap |
A fail blocks startup; a warn does not. "Hummingbot importable" is the one that earns its place: a valid-looking path paired with a valid-looking python from a different environment passes every other check and fails only at launch.
If the connector check reports a nested package, use Reinstall connector — it runs the installer shipped with your platform, including the clean mode that wipes the target directories first.
This is the environment check for a server-run install. The connector installer's
own --doctor mode is a separate check, for whether connect bicrypto will
appear inside a given checkout.
Start, stop, restart
The buttons record intent. A supervisor loop converges the real process towards it within a couple of seconds — which is why a card may briefly read Starting or Stopping, and why pressing a button twice is harmless.
| Status | Means |
|---|---|
| Running | The process is alive and supervised |
| Starting | Diagnosis passed and the process is being launched |
| Stopping | SIGTERM sent; the bot is winding down |
| Stopped | Not running, deliberately |
| Crashed | It exited on its own, or failed to start. The reason is on the card |
Stopping is graceful: SIGTERM and 20 seconds to cancel resting orders before it is forced. Killing a market maker instantly would leave live orders on the book with nothing managing them.
Restart regenerates the controller YAML from the linked preset, so it is also how you roll out a strategy change. Configuration is read at launch, so editing an instance while it runs does not affect the live process — the panel prompts you to restart.
Auto-restart backs off: a bot that dies is restarted after 5 seconds, doubling to a ceiling of 5 minutes; ten minutes of healthy uptime resets it. A bot that can never stay up stops consuming the host.
Why it is desired-state, not direct execution
Admin routes never spawn anything. They write the desired status on the row and return; one reconciler loop converges reality towards it. Three consequences you can rely on:
- One bot per instance, never two. Within a backend process — across every one of its worker threads — exactly one reconciler loop runs. Otherwise each worker would launch its own copy of every bot against the same account: two market makers quoting the same book, neither aware of the other's inventory. Two backend processes on one host is not a supported topology, but it does happen — an orphan that outlived a restart — and there the in-process guards cannot reach, because the database row is all the two share. So the right to launch is taken with a single atomic statement on that row. The process that loses it starts nothing and writes a line to the instance log naming the duplicate-backend condition, which is your cue to go and find the orphan.
- Start and stop are idempotent. A double-clicked button, a retried request or a request that times out mid-spawn all converge to one outcome.
- It survives a deploy. A bot you asked to run comes back after a backend restart instead of staying silently dead, and a process that outlived the restart is re-adopted — verified as the bot it recorded before adopting it — rather than started a second time alongside itself. Live log capture for a re-adopted process only resumes after a restart.
Safety model
A panel that runs programs on your server deserves scrutiny. Precisely what it can do:
- There is no command box. The browser sends an intent from a fixed set — start, stop, restart, install, diagnose — which the server maps to a hard-coded argument array.
- Nothing reaches a shell. Arguments are passed directly to the process, so quoting and shell metacharacters in a path cannot become a command.
- The installer path is fixed. "Reinstall connector" runs the installer shipped with your platform and cannot be pointed at another script.
- Permission-gated. Viewing needs
view.hb.instance; start, stop and restart needmanage.hb.instance; editing and reinstalling neededit.hb.instance; registering, provisioning and minting a key needcreate.hb.instance; removal needsdelete.hb.instance. - Audited. Every start, stop, restart, edit and install is written to the instance log with the administrator who requested it.
Logs and crash diagnosis
Logs streams the process output, per run, newest last, colouring errors and
warnings. Lines tagged [supervisor] come from the panel itself — start and stop
requests, install runs, crash reasons and memory kills. Logs are written to disk,
so the final output of a crashed bot survives a backend restart, which is exactly
when you most want to read it.
Repeated lines are throttled after the third occurrence, with a periodic marker so time is still visible. Hummingbot's MQTT bridge retries every five seconds for the life of the process and is unavoidable in headless mode, so it is filtered as noise; nothing in the panel depends on it.
When a supervised bot exits, the card names a probable cause and the next
action instead of "exited with code 1". Known Hummingbot failures are matched
by name — no saved keys for the connector, a missing interpreter, a config it
would not accept — each with the fix. Pure consequence lines such as Exiting.
are never reported as the cause, which is what made "read the logs" mean "read
past four lines of noise".
Memory ceilings
Each instance carries a hard limit, default 1536 MB. A bot over it is killed and the reason is recorded on the card. A runaway bot must die on its own rather than let the kernel pick a victim, which on this host could just as easily be MySQL or the backend itself.
The watchdog reads live memory usage from the operating system, which is available on Linux. On other platforms the cap is recorded but not applied, and the panel says so rather than implying protection it does not have.
Deleting an instance
Deleting a running instance is refused unless you confirm, because a process with no record is one nothing can ever stop. Stop it first.