SDK Agent Manual

Build custom Python trading agents with full control over strategy logic, data processing, and order management. The SDK gives you the PodiumAgent base class, a rich Context API, and a CLI for the full development lifecycle.

Getting Started

The SDK workflow follows a straightforward path: install, scaffold, implement, validate, upload, backtest, deploy. The CLI handles each step.

bash
# 1. Install the SDK
pip install podium-sdk

# 2. Authenticate with your API key
podium login

# 3. Scaffold a new agent project
podium init my-agent

# 4. Edit agent.py and strategy.json
# ... implement your strategy ...

# 5. Validate locally
podium validate my-agent

# 6. Upload to the platform
podium push my-agent

# 7. Run a backtest
podium backtest my-agent --start 2024-01-01 --end 2024-06-30

# 8. Deploy to paper trading
podium deploy my-agent

# 9. Check status
podium status my-agent

# 10. View logs
podium logs my-agent

Project Structure

After running podium init my-agent, you get:

  • agent.py — Your agent implementation (extends PodiumAgent)
  • strategy.json — Configuration: universe, risk limits, signal generator settings
  • requirements.txt — Python dependencies (must be from the allowlist)
  • artifacts/ — Optional directory for model files (.pkl, .pt, .npy, .onnx)

Agent Lifecycle

Every SDK agent extends the PodiumAgent base class and implements lifecycle hooks. The platform calls these hooks at the appropriate times.

python
from podium import PodiumAgent

class MyAgent(PodiumAgent):
    def setup(self, ctx):
        """Called once on first tick after deploy."""
        self.lookback = 20
        self.threshold = 0.02
        # Load a pre-trained model artifact
        # self.model = ctx.models.load("model.pkl")

    def on_market_data(self, ctx):
        """Called on each tick. This is where your strategy lives."""
        universe = ctx.data.get_universe()
        prices = ctx.data.get_prices(universe, days=self.lookback)

        for symbol in universe:
            bars = prices.get(symbol, [])
            if len(bars) < self.lookback:
                continue

            closes = [b["close"] for b in bars]
            sma = sum(closes) / len(closes)
            current = closes[0]  # Newest first

            position = ctx.portfolio.get_position(symbol)

            if current > sma * (1 + self.threshold) and not position:
                ctx.orders.submit(symbol, "buy", 100)
                ctx.log.info(f"BUY {symbol}: price {current:.2f} > SMA {sma:.2f}")

            elif current < sma * (1 - self.threshold) and position:
                ctx.orders.submit(symbol, "sell", position.quantity)
                ctx.log.info(f"SELL {symbol}: price {current:.2f} < SMA {sma:.2f}")

    def on_order_fill(self, ctx, fill):
        """Called when an order fills."""
        ctx.log.info(f"Filled: {fill.side} {fill.quantity} {fill.symbol} @ {fill.price}")

    def on_error(self, ctx, error):
        """Called on platform-detected errors before auto-pause."""
        ctx.log.error(f"Agent error: {error.message}")

setup(ctx)

Called once on the first tick after deployment. Use it to initialize parameters, load model artifacts, and set up any state your agent needs.

on_market_data(ctx) — Required

Called on every tick. This is where your strategy logic lives. Access market data, portfolio state, and submit orders through the context object.

on_order_fill(ctx, fill)

Called when an order fills. The fill object contains symbol, side, quantity, price, and timestamp. Use it for logging, state updates, or follow-up orders.

on_error(ctx, error)

Called when the platform detects an error before auto-pausing the agent. Use it for cleanup, alerting, or graceful degradation.

Context API

The context object (ctx) is passed to every lifecycle hook. It provides access to market data, portfolio state, order submission, persistent state, model artifacts, platform tools, and logging.

python
def on_market_data(self, ctx):
    # --- Data API ---
    universe = ctx.data.get_universe()          # List of symbols
    prices = ctx.data.get_prices(               # OHLCV bars
        symbols=["AAPL", "MSFT"],
        days=20                                 # Last 20 trading days
    )
    fundamentals = ctx.data.get_fundamentals("AAPL")  # PE, PB, etc.

    # --- Portfolio API ---
    cash = ctx.portfolio.get_cash()             # Available cash
    positions = ctx.portfolio.get_positions()   # All open positions
    position = ctx.portfolio.get_position("AAPL")  # Single position
    weights = ctx.portfolio.get_weights()       # Position weights
    total = ctx.portfolio.get_total_value()     # Portfolio value

    # --- Orders API ---
    ctx.orders.submit("AAPL", "buy", 100)                    # Market order
    ctx.orders.submit("AAPL", "buy", 100,
                      order_type="limit", limit_price=150.0)  # Limit order
    ctx.orders.submit("AAPL", "sell", 50,
                      order_type="stop", stop_price=140.0)    # Stop order
    ctx.orders.cancel("order-id-123")                         # Cancel order
    open_orders = ctx.orders.get_open_orders()                # List open

    # --- State API (persistent across ticks) ---
    ctx.state.set("last_signal", "bullish")
    signal = ctx.state.get("last_signal")

    # --- Models API (artifact loading) ---
    model = ctx.models.load("model.pkl")        # Pickle
    weights = ctx.models.load("weights.pt")     # PyTorch
    array = ctx.models.load("data.npy")         # NumPy

    # --- Tools API (platform tools) ---
    rsi = ctx.tools.call("rsi", symbol="AAPL")
    macd = ctx.tools.call("macd", symbol="AAPL")

    # --- Log API ---
    ctx.log.info("Processing tick")
    ctx.log.warning("Low liquidity detected")
    ctx.log.error("Failed to compute signal")

ctx.data — Market Data

  • get_prices(symbols, days) — OHLCV bars, newest first. Each bar has date, open, high, low, close, volume.
  • get_universe() — Resolved list of tradeable symbols from your strategy.json config.
  • get_fundamentals(symbol) — PE ratio, PB ratio, market cap, sector, dividend yield, beta.

ctx.portfolio — Portfolio State

  • get_cash() — Available cash balance
  • get_positions() — All open positions with quantity, avg price, market value, weight, unrealized P&L
  • get_position(symbol) — Single position lookup
  • get_weights() — Current position weights as a dict
  • get_total_value() — Total portfolio value (cash + positions)

ctx.orders — Order Submission

  • submit(symbol, side, quantity, ...) — Queue an order. Supports market, limit, stop, and stop-limit order types.
  • cancel(order_id) — Cancel a pending order
  • get_open_orders() — List all open orders
  • Time-in-force options: day, gtc, opg, cls, ioc, fok

ctx.state — Persistent State

Key-value store that persists across ticks. Use it for tracking signals, counters, regime states, or any data your agent needs to remember between ticks.

ctx.models — Artifact Loading

Load pre-trained model files from the artifacts/ directory. Supports pickle (.pkl), PyTorch (.pt), NumPy (.npy), and ONNX (.onnx) formats. Files are stored in Azure Blob Storage and loaded into the sandbox at runtime.

Strategy Configuration (strategy.json)

Every SDK agent requires a strategy.json file that defines the agent's universe, risk limits, and runtime configuration. This file is validated on upload.

json
{
  "name": "SMA Crossover Agent",
  "version": "1.0.0",
  "description": "Trades based on simple moving average crossovers",
  "universe": {
    "assetClass": "us_equities",
    "index": "sp500",
    "sectors": ["Technology", "Healthcare"],
    "marketCapRange": ["large", "mega"]
  },
  "riskLimits": {
    "maxDrawdown": 0.15,
    "maxPositionPct": 0.10,
    "sectorConcentration": 0.40
  },
  "rebalanceFrequency": "daily",
  "positionSizing": "equal_weight",
  "benchmark": "SPY",
  "startingCapital": 100000,
  "signalGenerator": {
    "type": "agent",
    "entrypoint": "agent:MyAgent",
    "dependencies": ["numpy", "pandas"]
  }
}

signalGenerator.type

  • "agent" — PodiumAgent subclass with full lifecycle hooks (recommended)
  • "custom" — Custom signal generator function (generate_signals)
  • "llm" — Standard LLM-based decision making (same as no-code)

signalGenerator.entrypoint

Format: "module:ClassName" for agent type, or "module:function_name" for custom type. Example: "agent:MyAgent" means the MyAgent class in agent.py.

Runtime Configuration (Optional)

  • compute: "cpu" (default) or "gpu"
  • GPU types: T4 (inference) or A100 (training/large models)
  • Custom Docker images supported for advanced use cases

Validation & Upload

Before your agent can be deployed, it goes through validation. This happens both locally (via the CLI) and on the platform (after upload).

What gets validated

  • Code syntax — Python code must parse without errors
  • Strategy config — strategy.json must match the schema (valid universe, risk limits, signal generator config)
  • Package allowlist — All dependencies must be from the approved package list (numpy, pandas, scikit-learn, torch, etc.)
  • Entrypoint — The specified class or function must exist in the code
  • Artifact size — Model files must be within size limits

Version Management

Each upload creates a new version. You can have multiple versions and roll back to any previous version. Only versions that pass validation can be deployed or backtested.

Deployment

Deploy your agent to paper trading from the CLI or the web dashboard. The platform runs your agent in a sandboxed Python environment (Azure Container Apps Dynamic Sessions) with access to the Context API.

Deployment Flow

  1. Select a validated version to deploy
  2. Platform provisions a sandbox session
  3. Your agent code and artifacts are loaded into the sandbox
  4. On each tick, the platform serializes the PodiumContext (market data, portfolio, etc.) and sends it to the sandbox
  5. Your agent runs, submits orders via ctx.orders
  6. Orders are extracted from the sandbox and submitted to the broker, subject to risk limit enforcement

Agent States

  • draft — Uploaded but not deployed
  • validating — Validation in progress
  • staging — Ready to deploy
  • running — Actively trading
  • paused — Temporarily stopped
  • stopped — Permanently stopped
  • error — Stopped due to error

Supported Packages

All dependencies must be from the approved allowlist. This ensures sandbox security and reproducibility.

Data Science

  • numpy
  • pandas
  • scipy
  • statsmodels

Machine Learning

  • scikit-learn
  • torch
  • tensorflow
  • xgboost
  • lightgbm
  • onnxruntime

Technical Analysis

  • ta-lib
  • ta
  • pandas-ta