How to Auto-Install Python Packages in a Trading Bot
Your bot worked perfectly on your laptop. You deployed it to a server, ran it, and got: ModuleNotFoundError: No module named 'ccxt'. This guide covers six ways to fix it — from the obvious pip install to a system that installs missing packages automatically inside an isolated environment so this never happens again.
What we'll cover
- Why ModuleNotFoundError keeps happening
- Fix 1: pip install (and why it's not enough)
- Fix 2: Use a virtual environment per bot
- Fix 3: Pin everything in requirements.txt
- Fix 4: Auto-install at runtime (with caveats)
- Fix 5: Use uv for fast, isolated installs
- Fix 6: A self-healing bot runtime
- Bonus: Common import-name mismatches
01Why ModuleNotFoundError keeps happening
Python's import system trusts the active environment to have every package your code uses. If something is missing, Python doesn't try to fix it — it raises ModuleNotFoundError and your process dies.
The reason this hits trading bots harder than most other Python code:
- You iterate fast — adding
import pandasat 11 PM after a few drinks of inspiration - You run bots in many environments (laptop, VPS, Docker, cloud)
- Bots run for days unattended, so a missing package isn't caught until a key moment
- Different bots often need different package versions that conflict
02Fix 1: pip install (and why it's not enough)
The naive fix:
pip install ccxt
This works for the immediate error. But it installs the package globally for that Python interpreter. Three problems:
- Bot A needs
ccxt==4.0.0but Bot B needsccxt==4.2.5. One of them will break. - Updates can break everything. A
pip install --upgradecan change transitive dependencies and leave one of your bots broken. - You forget which packages each bot uses. Six months later, you can't reproduce the environment.
This is the OK first step, but not where you should stop.
03Fix 2: Use a virtual environment per bot
One venv per bot solves the version-conflict problem:
# Create a venv for this bot
python -m venv .venv-mybot
# Activate it (macOS/Linux)
source .venv-mybot/bin/activate
# Or on Windows:
# .venv-mybot\Scripts\activate
# Install what you need
pip install ccxt pandas numpy
Now run your bot using that venv's Python:
.venv-mybot/bin/python my_bot.py
This works. The downsides:
- You have to remember to activate the right venv every time
- Cron jobs and systemd services need absolute Python paths
- If you have 20 bots, you have 20 venvs to manage
04Fix 3: Pin everything in requirements.txt
For every bot, maintain a requirements.txt with explicit versions:
# requirements.txt
ccxt==4.2.5
pandas==2.1.0
numpy==1.26.0
requests==2.31.0
Then for any deploy:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
This is the textbook answer and works reliably. But it requires discipline. The reality of trading bot development is: you add an import to your code at 2 AM, you don't update requirements.txt, you push to production, it breaks. Every time.
05Fix 4: Auto-install at runtime (with caveats)
You can have your bot install its own dependencies on first run:
import importlib, subprocess, sys
def ensure(pkg, import_name=None):
try:
importlib.import_module(import_name or pkg)
except ImportError:
subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
importlib.import_module(import_name or pkg)
ensure("ccxt")
ensure("pandas")
import ccxt, pandas # now safe
Caveats: This pattern works but has rough edges. If a package fails to install (network error, wheel doesn't build), the bot crashes on startup. You're also installing into whichever venv is active — same scoping problems as fix #1. Worth using as a last resort or for the dev loop, not for production.
06Fix 5: Use uv for fast, isolated installs
uv is a fast Python package installer from Astral (the Ruff team) — written in Rust, 10–100× faster than pip. It also has built-in venv creation:
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create a venv + install in one shot
uv venv .venv-mybot
uv pip install --python .venv-mybot/bin/python ccxt pandas
# Or even simpler: uv run handles venv+install+execute
uv run --with ccxt --with pandas python my_bot.py
uv run is the cleanest workflow we've seen for one-off bot execution. It creates an ephemeral environment, installs the packages, and runs your script. No requirements.txt to maintain.
The catch: you still have to declare every package you need, every time. If you add a new import to your code, you have to remember to pass --with new_package.
07Fix 6: A self-healing bot runtime
The pattern we landed on after building hundreds of bots: have the runtime watch the bot process, parse ModuleNotFoundError from its output, install the missing package, and restart. Automatically.
Conceptually:
import re, subprocess
MAX_RETRIES = 3
MISSING_PATTERN = re.compile(r"No module named ['\"]([\w\.]+)['\"]")
def run_with_self_heal(bot_script, bot_venv):
for attempt in range(MAX_RETRIES):
result = subprocess.run(
[f"{bot_venv}/bin/python", bot_script],
capture_output=True, text=True
)
if result.returncode == 0:
return True
m = MISSING_PATTERN.search(result.stderr)
if not m:
print(result.stderr)
return False
missing = m.group(1).split(".")[0] # top-level package
print(f"[self-heal] installing {missing}")
subprocess.check_call([
"uv", "pip", "install",
"--python", f"{bot_venv}/bin/python",
missing
])
return False
This is exactly the pattern WatchDog Bot uses internally. Every bot gets its own uv-managed venv. When the bot raises ModuleNotFoundError, the runtime parses the missing module name, runs uv pip install into that bot's venv, and restarts the process. Up to 3 tries. Persistent — the runtime keeps a record so the next launch starts cleanly.
The user sees: their bot just works. No pip install, no requirements.txt, no remembering which venv to activate. They paste code with import ccxt, click Start, and the platform handles the rest.
One important guardrail: auto-install is great for well-known packages, but it can fail or take a long time for native-compiled dependencies. WatchDog Bot's runtime keeps a denylist (setuptools, wheel, pip itself) and a sanity check on package names so a malicious bot can't ask the platform to install something dangerous.
08Bonus: Common import-name mismatches
One reason auto-install systems trip up: the import name often differs from the PyPI package name. Some classics:
| import statement | pip install command |
|---|---|
| import cv2 | pip install opencv-python |
| import yaml | pip install PyYAML |
| import PIL | pip install Pillow |
| import sklearn | pip install scikit-learn |
| import bs4 | pip install beautifulsoup4 |
| import dotenv | pip install python-dotenv |
| import jwt | pip install PyJWT |
| import dateutil | pip install python-dateutil |
| import OpenSSL | pip install pyOpenSSL |
| import google.cloud | pip install google-cloud-storage |
A naive auto-installer will try pip install cv2 and fail. Any production-grade auto-install system maintains a mapping table for the common cases. (Yes, WatchDog Bot does.)
The best dependency management is the dependency management you don't have to think about.
Skip the dependency rabbit hole
WatchDog Bot auto-installs every package your bot needs, in an isolated venv, with retry-on-failure. Free trial, no credit card.
Start Free Trial →
WatchDog Bot