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

python
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.

python
def initialize(self, ctx: StrategyContext) -> None:
    # Called once before the backtest begins. Optional.
    self.lookback = 126
    self.top_n = 20

universe(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.

python
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).

python
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.

python
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