Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tribulnation_engine-0.1.3.tar.gz (101.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tribulnation_engine-0.1.3-py3-none-any.whl (114.8 kB view details)

Uploaded Python 3

File details

Details for the file tribulnation_engine-0.1.3.tar.gz.

File metadata

  • Download URL: tribulnation_engine-0.1.3.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

Hashes for tribulnation_engine-0.1.3.tar.gz
Algorithm Hash digest
SHA256 0ed6b3261a00fcf594d95b773a8ea75c1e04b73bb36b6b1e5ed36aee8e520b4e
MD5 17274413d43725b8aa2bf23b7cd4e99a
BLAKE2b-256 f46252bf12730d66e2a1e32dcef5062c3505be7db236ddf57312b9419b8e0756

See more details on using hashes here.

File details

Details for the file tribulnation_engine-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for tribulnation_engine-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 2ca6d56221497b0aead03b093e03ec38ca8c7516b842a0ea616b1ea4f78a4297
MD5 31dfc86c18a9d6eceec8427ecb50a51d
BLAKE2b-256 ca92a2cd8c2a620c126b993e58a815dbefb7d92544f7180b536779b71e268da0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page