Strategy Class
The base class for all deterministic Podium strategies. Subclass it and implement universe() and signal() at minimum. Strategies return target weights — the engine derives orders, simulates fills, and tracks the portfolio.
Class Definition
from podium_sdk import Strategy, StrategyContext
from podium_sdk.types import RiskLimits
class Strategy(ABC):
def initialize(self, ctx: StrategyContext) -> None: ...
def universe(self, ctx: StrategyContext) -> list[str]: ... # required
def signal(self, ctx: StrategyContext) -> dict[str, float]: ... # required
def risk_limits(self, ctx: StrategyContext) -> RiskLimits: ...Methods
initialize(ctx: StrategyContext) -> None
Optional. Called once before the backtest begins. Use it to set parameters or cache state on self.
def initialize(self, ctx: StrategyContext) -> None:
# Called once before the backtest begins. Optional.
self.lookback = 126
self.top_n = 20universe(ctx: StrategyContext) -> list[str]
Required. Return the symbols to consider on the current date. Called before each signal() invocation, so the universe can be dynamic.
def universe(self, ctx: StrategyContext) -> list[str]:
# Return the list of symbols to consider on this date.
# Called before each signal() invocation (dynamic, daily).
returns = ctx.data.returns(lookback=self.lookback + 5)
if returns.empty:
return []
return list(returns.columns)signal(ctx: StrategyContext) -> dict[str, float]
Required. Return target weights as a {symbol: weight} dict. Positive weights are long, negative weights are short. The engine normalizes weights, applies guardrails, and converts the resulting weight changes into orders filled at the next open (delay-1).
def signal(self, ctx: StrategyContext) -> dict[str, float]:
# Return target weights {symbol: weight}.
# Long-only weights should sum to ~1.0; the engine
# normalizes and derives orders (delay-1 execution).
returns = ctx.data.returns(lookback=self.lookback)
momentum = (1 + returns).prod() - 1
top = momentum.nlargest(self.top_n)
weight = 1.0 / len(top)
return {sym: round(weight, 6) for sym in top.index}risk_limits(ctx: StrategyContext) -> RiskLimits
Optional. Return a RiskLimits dataclass to customize guardrail thresholds. If not overridden, sensible defaults are used. See Risk Limits for every check.
def risk_limits(self, ctx: StrategyContext) -> RiskLimits:
# Override to customize guardrail thresholds.
# Returns RiskLimits() defaults if not overridden.
return RiskLimits(
max_position_pct=0.10, # 10% max per position
max_sector_pct=0.35, # 35% max per sector
max_drawdown_pct=0.20, # 20% drawdown kill switch
min_positions=5,
)Note for early SDK users
Earlier drafts referenced an Agent class with class attributes (universe: list[str]) and an order-based analyze() method. That API is superseded. The current SDK is method-based and weight-based: implement universe() and signal() on a Strategy subclass and return target weights. There is no analyze() or context.orders.buy() in the deterministic engine.
Related
- Context API — date, portfolio, data, config, security master, ops, skills
- Data API — OHLCV, returns, fundamentals, panel accessors
- Alpha Operators — formulaic operator library via
ctx.ops