Strategy_concepts_0.md 4.1 KB

Strategy SDK Specification

1. Purpose

This document defines the core strategy contract for trader-mcp. It separates:

  • strategy logic
  • engine lifecycle control
  • capability access
  • configuration
  • runtime UI output

The goal is simple, single-file strategies that stay easy to reason about, safe to run, and consistent across the app.

2. Design Goals

2.1 Keep the surface small

Strategies should have a minimal API and minimal boilerplate.

2.2 Separate responsibilities

  • strategy, decides what to do
  • engine, decides when to load, unload, and tick
  • context, enforces permissions and binds instance identity (account_id, client_id) to exec calls
  • database, owns persistent config and identity

2.3 Prefer deterministic behavior

A given strategy instance should behave predictably for the same config and input stream.

2.4 Restrict capabilities explicitly

Strategies must not touch engine internals or persistence directly. All external actions go through the injected context.

3. Strategy Contract

Each strategy is a Python class extending Strategy.

from strategy_sdk import Strategy

class MyStrategy(Strategy):
    TICK_MINUTES = 1.0
    CONFIG_SCHEMA = {
        "risk": {"type": "float", "default": 0.01},
        "window": {"type": "int", "default": 20}
    }

    def init(self):
        return {
            "prices": [],
            "position": 0
        }

    def on_tick(self, tick):
        price = tick["price"]
        self.state["prices"].append(price)

    def render(self):
        return {
            "widgets": [
                {"type": "line_chart", "data": self.state["prices"]}
            ]
        }

4. Base Class Shape

class Strategy:
    CONFIG_SCHEMA = {}

    def __init__(self, context, config):
        self.context = context
        self.config = config
        self.state = self.init()

    def init(self):
        return {}

    def on_tick(self, tick):
        pass

    def render(self):
        return {"widgets": []}

5. Configuration

5.1 Purpose

CONFIG_SCHEMA drives validation and UI generation.

5.2 Rules

  • config is read-only from the strategy’s perspective
  • config is supplied by the engine
  • config changes are handled by reload, not mutation

5.3 Recommended schema style

CONFIG_SCHEMA = {
    "risk": {
        "type": "float",
        "default": 0.01,
        "min": 0.0,
        "max": 1.0
    },
    "window": {
        "type": "int",
        "default": 20
    }
}

6. State

6.1 Ownership

self.state belongs to the strategy instance.

6.2 Lifecycle

init() -> state created
on_tick() -> state updated
reload -> state reset

6.3 Guidance

  • keep state serializable where practical
  • do not let state depend on hidden external globals

7. Context

The context is a capability boundary, not a config loader.

Allowed responsibilities

  • market/data access
  • order placement
  • logging
  • engine-mediated actions
  • strategy-scoped metadata, including attaching the instance account_id and client_id to execution calls

Not the responsibility of context

  • config storage
  • persistence
  • lifecycle control
  • strategy identity ownership
  • deciding strategy behavior

Example:

class StrategyContext:
    def get_price(self):
        raise NotImplementedError

    def place_order(self, side, amount):
        raise NotImplementedError

    def get_orders(self):
        raise NotImplementedError

    def log(self, message):
        raise NotImplementedError

8. UI Output

Strategies should return structured UI data, not HTML.

def render(self):
    return {
        "widgets": [
            {"type": "line_chart", "data": [...]},
            {"type": "metric", "label": "PnL", "value": 123.45}
        ]
    }

Principles

  • no frontend code inside the strategy
  • no DOM or template output
  • dashboard owns rendering

9. Summary

The strategy SDK should make it obvious that:

  • strategy defines behavior
  • engine defines lifecycle
  • runtime defines tick cadence, in minutes
  • context defines permissions
  • config defines initial conditions
  • state belongs to the instance