Trading engine — gateway, task manager, and process SDK
Project description
Trading Engine
Run algorithmic trading strategies as managed tasks — with a live dashboard, per-task logs, restart policies, and a market SDK that abstracts across venues.
Quickstart
1 — Install
pip install tribulnation-engine
2 — Initialize
Initialize the engine in a new directory:
engine init
# creates engine.toml, .env, and strats/ directory
Edit engine.toml and .env to configure accounts and strategies.
3 — Write a strategy
# strats/my_strat.py
from tribulnation.engine import Process, RestartPolicy
class MyStrat(Process):
name = 'my-strat'
restart = RestartPolicy(on='error', delay=5.0)
async def run(self, market: str):
mkt = await self.sdk.market(market)
book = await mkt.depth()
self.log.info('mark price: %s', book.mark_price)
run() parameters become the task's argument schema — they appear as a form in
the dashboard and are coerced to the declared types when a task is started.
4 — Start the engine
engine start # foreground, logs to stdout
engine start -d # background — writes .engine.pid and engine.log
For longer-running deployments on a systemd host, you can also install it as a user service:
engine service install --cwd . --memory 2G -v
engine service status
engine service logs -f
The generated service runs engine start, restarts automatically, and uses
systemd MemoryMax when --memory is provided. Manage it with:
engine service restart
engine service stop
engine service uninstall
5 — Run a strategy
From the dashboard at http://localhost:3121 or via the CLI:
engine task start my-strat bitcoin -a market=mexc:spot:BTCUSDT
# engine task start <process_name> <run_id> -a <arg_name>=<arg_value> ...
6 — Stop a strategy
From the dashboard or:
engine task stop my-strat bitcoin
# engine task stop <process_name> <run_id>
Strategies
The Process base
from tribulnation.engine import Process, RestartPolicy
Implement async def run(self, ...). Anything run() needs is injected via
self:
| Attribute | What it is |
|---|---|
self.sdk |
Market SDK — call await self.sdk.market('venue::symbol') |
self.log |
Logger scoped to this task |
self.run_id |
The run ID this task was started with |
self.set_state(s) |
Publish a named state ('connected', 'quoting', …) |
self.require(cls, id) |
Declare a dependency on another running task |
self.ipc |
Call methods on Service processes |
Restart policy
class Hedger(Process):
restart = RestartPolicy(on='error', delay=5.0)
on= |
Behaviour |
|---|---|
'never' |
Stop on exit or error |
'error' |
Restart after an unhandled exception, with delay seconds between attempts |
'always' |
Restart after any exit |
max_attempts=N caps the number of consecutive restarts.
Dependencies
Use require() to gate a task on another reaching a named state:
class DydxMaker(Process):
async def run(self, maker: str, hedge: str) -> None:
async with self.require(Hedger, self.run_id, state='connected')(
listen=maker, hedge=hedge
):
# runs only while Hedger/{self.run_id} is alive and in state 'connected'
...
require() also auto-starts the dependency if it isn't running, and cancels
the dependent if the dependency stops or errors.
Logging
Standard logging calls are automatically captured and streamed to the
dashboard. No setup needed:
log = logging.getLogger(__name__)
class Hedger(Process):
async def run(self, ...):
log.info('listener live: %s → %s', listen, hedge)
# or use the process logger:
self.log.info('works the same way')
INFO and above are always captured. DEBUG records are captured only from
loggers whose name starts with a prefix listed in [daemon] debug_loggers:
[daemon]
debug_loggers = ["strats"]
Config reference (engine.toml)
[engine]
processes = [
"strats.hedger:Hedger",
"strats.dydx_maker:DydxMaker",
]
[daemon]
host = "localhost"
port = 3121
db = "engine.db" # SQLite path; default "engine.db"
max_logs = 500 # in-memory log lines per task; default unlimited
[accounts.dydx-main]
venue = "dydx"
mnemonic = "$DYDX_MNEMONIC"
[accounts.hyperliquid-main]
venue = "hyperliquid"
address = "$HYPERLIQUID_ADDRESS"
private_key = "$HYPERLIQUID_PRIVATE_KEY"
[[tasks]]
process = "hedger"
id = "btc"
args = { listen = "dydx:perp:BTC-USD", hedge = "hl::BTC" }
Account credentials are resolved from environment variables when the value
starts with $. engine start automatically loads .env from the same
directory as engine.toml.
[[tasks]] entries are started automatically when the engine starts. Each
entry needs process (the registered process name), id (the run ID), and
optionally args (a table of keyword arguments matching the process
signature).
CLI
engine start # launch gateway + manager (foreground)
engine start -d # background — writes .engine.pid + engine.log
engine service install --cwd . --memory 2G -v # install as a user systemd service
engine service logs -f # follow service logs
engine stop # stop a background engine
engine task start hedger btc -a listen=dydx:perp:BTC-USD -a hedge=hyperliquid::BTC
engine task stop hedger btc
engine register strats.new_strat:NewStrat # hot-load a process class
HTTP API
| Method | Path | Description |
|---|---|---|
GET |
/api/tasks |
Running tasks |
GET |
/api/tasks/history |
Completed tasks (SQLite) |
GET |
/api/task/{process}/{id} |
Single task |
GET |
/api/task/{process}/{id}/logs |
Task logs |
GET |
/api/task/{process}/{id}/attempts |
Restart attempts |
POST |
/api/task/{process}/{id} |
Start a task — body: {"args": {...}} |
DELETE |
/api/task/{process}/{id} |
Stop a task |
DELETE |
/api/task/{process}/{id}?purge=true |
Stop and remove from history |
DELETE |
/api/task/{process}/{id}/logs |
Clear logs and attempt history |
GET |
/api/processes |
Registered process classes |
POST |
/api/processes |
Register a process at runtime |
GET |
/api/health |
Health check |
GET |
/api/ws |
WebSocket event feed |
Architecture
engine start
├── engine gateway owns real venue SDK connections, serves the market RPC protocol
└── engine manager task control plane
├── in-process runtime — strategies run as asyncio tasks
├── REST + WebSocket API (FastAPI / uvicorn)
└── SQLite store — task history, logs, restart attempts
Strategies never hold venue connections directly. self.sdk inside a task is a
ProxySDK that routes market calls to the gateway over a local Unix socket. The
gateway owns the real credentials and connections; the manager owns task
lifecycle and the dashboard.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tribulnation_engine-0.1.4.tar.gz.
File metadata
- Download URL: tribulnation_engine-0.1.4.tar.gz
- Upload date:
- Size: 101.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70cef7fcc54cb3556130ac2176fcdded6761f8127521db0533f596aefa595776
|
|
| MD5 |
d2a297c41cbe9948ffcaeeb2a00754e8
|
|
| BLAKE2b-256 |
a2d3bae40344be9177fb3c0aa031782f8f0b6b57079d94b5493ebcebae723707
|
File details
Details for the file tribulnation_engine-0.1.4-py3-none-any.whl.
File metadata
- Download URL: tribulnation_engine-0.1.4-py3-none-any.whl
- Upload date:
- Size: 114.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03d2ae28bcf03fe6a711202163d8b47ac4c3b45805d2869db423b81170eb6f68
|
|
| MD5 |
6cb1c3aa3cb77c0e4e0fdc007bf95648
|
|
| BLAKE2b-256 |
b257231d7644ccb9fb516da5b0b6c1443bfce32d4923d16d24090208a331f3c8
|