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.1.tar.gz (100.5 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.1-py3-none-any.whl (113.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: tribulnation_engine-0.1.1.tar.gz
  • Upload date:
  • Size: 100.5 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.1.tar.gz
Algorithm Hash digest
SHA256 2528ab8af87debc12a2f642f4a8fb9d6886ec6c5f6490ff7c05878f2112609e2
MD5 3c5b45c212fee43eed9ec09ad8f75f65
BLAKE2b-256 d36be4417f0a89eb2194ef0554a6512f6c8e96911792a889252c378b15563b58

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for tribulnation_engine-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 de686abdb4dcdea9e40f9604a747de08fa2bd4ebd73c3048854b49dc1501938d
MD5 68a8bc696abb948b51f1660e2c7f65c0
BLAKE2b-256 831f13b4be02393d2e9e6da4bbcc198108d6b9670750e1d42f57978da91fd74e

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