Configuration¶
The library needs to know three things: where UBI is, where this project's MongoDB is, and UBI's api key and secret. The first two come from environment variables, usually written in a .env file at the repository root. The third comes from a document in MongoDB. The same MongoDB database also holds the stored asset baskets, which need no configuration of their own. UBI's order engine must also be running, which is set up in UBI, not here.
Where each setting is read¶
The diagram below shows every setting and the code or container that reads it. Solid arrows are read by the library; dashed arrows are read by Docker Compose or by UBI.
flowchart LR
ENV[".env at the<br/>repository root"]
ENV --> CFG["Configuration<br/>ubi_base_url<br/>mongodb_host, _port, _db,<br/>_username, _password"]
ENV -.-> DC["docker compose<br/>ports and passwords"]
DC -.-> MG[("MongoDB<br/>port 2003")]
CFG --> CL["UnifiedBrokerInterface<br/>constructor"]
CL -- "reads settings where<br/>broker_name is<br/>unified_broker_interface" --> MG
MG -- "api_key, api_secret" --> CL
CL -- "POST /api/session/connect" --> UBI["UBI<br/>127.0.0.1:8080"]
CFG --> BS["BasketStore<br/>constructor"]
BS -- "reads and writes the<br/>asset_baskets collection" --> MG
UENV["UBI's own .env<br/>order engine settings"] -.-> UBI
How the variables are read¶
Configuration, in tradingmachine.utilities.configuration, is the only place in the library that reads the environment, and it reads nothing until a value is first asked for. At that moment it loads .env, searching the working directory and then its parents, and reads the variables from the process environment. Importing the library therefore never touches the file system.
Three rules follow from that, and they explain most surprises.
- A variable already exported in the shell wins over the same variable in
.env, because loading the file never overrides a value that is set. When a change to.envseems to have no effect, check for an exported value. - The file is loaded once per
Configurationobject. A long-running process that needs a changed.envcallsreload()on it. - A missing variable is
None, not an error. The client raisesValueErrorwhen it needs a value that is missing.
The UBI client shows how to point a Configuration at a different file, or at no file at all.
The environment variables¶
.env is gitignored and must never be committed. The table below lists every variable in it, whether the library reads it, whether the Docker containers read it, and the default Compose falls back to.
| Variable | Read by the library | Read by the containers | Compose default | What it is |
|---|---|---|---|---|
TRADINGMACHINE_UBI_BASE_URL |
UBI's address, http://127.0.0.1:8080 |
|||
TRADINGMACHINE_MONGODB_HOST |
The host MongoDB is reachable on | |||
TRADINGMACHINE_MONGODB_PORT |
2003 |
The published MongoDB port | ||
TRADINGMACHINE_MONGODB_DB |
The database holding the settings and asset_baskets collections |
|||
TRADINGMACHINE_MONGODB_USERNAME |
tradingmachine |
The MongoDB root user | ||
TRADINGMACHINE_MONGODB_PASSWORD |
The MongoDB root password | |||
TRADINGMACHINE_REDIS_HOST |
Redis's host, for future code | |||
TRADINGMACHINE_REDIS_PORT |
2002 |
The published Redis port | ||
TRADINGMACHINE_REDIS_DB |
The Redis database number, for future code | |||
TRADINGMACHINE_REDIS_USERNAME |
default, the user Redis's password belongs to |
|||
TRADINGMACHINE_REDIS_PASSWORD |
Set with --requirepass on every start |
|||
TRADINGMACHINE_TIMESCALEDB_HOST |
TimescaleDB's host, for future code | |||
TRADINGMACHINE_TIMESCALEDB_PORT |
2004 |
The published TimescaleDB port | ||
TRADINGMACHINE_TIMESCALEDB_DB |
tradingmachine |
The database created at first start | ||
TRADINGMACHINE_TIMESCALEDB_USERNAME |
tradingmachine |
The superuser | ||
TRADINGMACHINE_TIMESCALEDB_PASSWORD |
The superuser's password |
The library reads exactly six variables, all through Configuration. The Redis and TimescaleDB variables exist for the containers and for code that has not been written yet. The file also holds a leftover PYTHONPATH line from before the project became an installable library; it does nothing, and it is the cause of the harmless Compose warning shown on Installation.
A .env with placeholder values is shown below. The hosts are illustrative: on the development machine the databases are reached through the machine's local network address, while UBI is always reached on 127.0.0.1, because it binds only there.
TRADINGMACHINE_UBI_BASE_URL=http://127.0.0.1:8080
TRADINGMACHINE_MONGODB_HOST=127.0.0.1
TRADINGMACHINE_MONGODB_PORT=2003
TRADINGMACHINE_MONGODB_DB=tradingmachine
TRADINGMACHINE_MONGODB_USERNAME=tradingmachine
TRADINGMACHINE_MONGODB_PASSWORD=<a password>
TRADINGMACHINE_REDIS_HOST=127.0.0.1
TRADINGMACHINE_REDIS_PORT=2002
TRADINGMACHINE_REDIS_DB=0
TRADINGMACHINE_REDIS_USERNAME=default
TRADINGMACHINE_REDIS_PASSWORD=<a password>
TRADINGMACHINE_TIMESCALEDB_HOST=127.0.0.1
TRADINGMACHINE_TIMESCALEDB_PORT=2004
TRADINGMACHINE_TIMESCALEDB_DB=tradingmachine
TRADINGMACHINE_TIMESCALEDB_USERNAME=tradingmachine
TRADINGMACHINE_TIMESCALEDB_PASSWORD=<a password>
The library builds its MongoDB address from those values as mongodb://<username>:<password>@<host>:<port>/?authSource=admin. The authSource=admin part is needed because the container creates its root user in the admin database, and the username and password are escaped, so a generated password containing @ or / is safe.
The MongoDB settings document¶
UBI's api key and secret are not environment variables. The client reads them from this project's MongoDB, in the database named by TRADINGMACHINE_MONGODB_DB, from the settings collection document whose broker_name is unified_broker_interface. The values must match the same document in UBI's own MongoDB, which is what UBI checks a login against; The settings documents on the UBI site describes UBI's side.
The document looks like the one below. The values here are placeholders.
{
"broker_name": "unified_broker_interface",
"api_key": "<the key UBI has in its own settings>",
"api_secret": "<the secret UBI has in its own settings>"
}
No code in the library creates this document; it is seeded by hand once. One way to do that from the project's own environment is the snippet below, which upserts the document so that running it twice does no harm. It uses the library's own Configuration to find MongoDB.
import pymongo
from tradingmachine.utilities import configuration
project_configuration = configuration.Configuration()
with pymongo.MongoClient(
project_configuration.mongodb_connection_string
) as mongo_client:
database = mongo_client[project_configuration.mongodb_database_name]
database["settings"].update_one(
{
"broker_name": "unified_broker_interface",
},
{
"$set": {
"api_key": "<the key UBI has in its own settings>",
"api_secret": "<the secret UBI has in its own settings>",
},
},
upsert=True,
)
If UBI's key or secret ever changes, this document must be changed to match. Until it is, every request fails with AuthenticationError after its one retry.
The table below lists what goes wrong when part of this configuration is missing, and when you find out.
| What is missing | What you see | When |
|---|---|---|
TRADINGMACHINE_UBI_BASE_URL |
ValueError: UBI base url is not configured: TRADINGMACHINE_UBI_BASE_URL |
The first instrument is built |
The settings document |
ValueError: No settings document with broker_name='unified_broker_interface' in MongoDB database ... |
The first instrument is built |
api_key or api_secret in it |
ValueError: Settings document 'unified_broker_interface' is missing api_key or api_secret |
The first instrument is built |
| The right key or secret | AuthenticationError |
The first request |
| UBI itself | UnreachableError |
The first request |
Stored baskets use the same database¶
Asset baskets, such as an index's constituents or a portfolio, are kept in the asset_baskets collection of the same database, because UBI stores no index constituents or fund holdings. BasketStore finds MongoDB through the same Configuration, so there is nothing more to set. The collection and its indexes are created by the first save, and there is no setup step. Asset baskets explains how baskets are saved, imported from a CSV file and loaded.
The order engine is configured in UBI¶
UBI places every order through its order engine, a separate UBI process, and its settings live in UBI's own .env, not in this project. There is nothing to configure here. Until 2026-09-27 UBI also had a direct placement mode, chosen with UNIFIED_BROKER_INTERFACE_API_ORDER_PLACEMENT; that setting no longer exists and UBI ignores it if it is still set.
The table below shows which parts of the library need the engine running.
| Part of the library | Needs the order engine |
|---|---|
| Candles, quotes, discovery, positions, holdings and order book reads | |
Every order: place_order, every price wrapper, the position and holdings methods, and every class in tradingmachine.orders |
|
modify_order and cancel_order on an order placed outside the engine |
, UBI sends them from its API |
modify_order and cancel_order on an order the engine placed, cancel_parent and Account.flatten's halt |
Order engine explains what the engine does with an order, including why it holds a plain limit order.