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.
# 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-agentProject Structure
After running podium init my-agent, you get:
agent.py— Your agent implementation (extends PodiumAgent)strategy.json— Configuration: universe, risk limits, signal generator settingsrequirements.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.
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.
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 balanceget_positions()— All open positions with quantity, avg price, market value, weight, unrealized P&Lget_position(symbol)— Single position lookupget_weights()— Current position weights as a dictget_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 orderget_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.
{
"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
- Select a validated version to deploy
- Platform provisions a sandbox session
- Your agent code and artifacts are loaded into the sandbox
- On each tick, the platform serializes the PodiumContext (market data, portfolio, etc.) and sends it to the sandbox
- Your agent runs, submits orders via ctx.orders
- 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