DOCUMENTATION

Build deterministic trading strategies with the Podium Strategy SDK.

STRATEGY SDK

All strategies extend Strategy and implement universe() and signal() to return target portfolio weights.

REQUIRED & OPTIONAL METHODS

initialize(ctx) optional

Called once on the first tick. Use for setting parameters or loading state.

universe(ctx) -> list[str] required

Return the list of symbols to consider. Called before each signal() invocation.

signal(ctx) -> dict[str, float] required

Return target weights as a dict mapping symbol to weight (0.0-1.0). Weights are normalized to sum to 1.0 for long-only strategies.

risk_limits() -> dict optional

Override default risk limits per strategy. See Risk Limits docs for all available parameters.

STRATEGY CONTEXT

Every method receives a StrategyContext with:

python
# StrategyContext fields available in every method call:

ctx.date          # Current trading date (datetime)
ctx.portfolio     # Current portfolio state
ctx.data          # DataAccessor for market data
ctx.config        # StrategyConfig from strategy.json
ctx.security_master  # Security master lookup

DATA ACCESSOR

python
# DataAccessor methods:

ctx.data.returns(lookback=126) -> pd.DataFrame
  # Daily returns for all universe symbols

ctx.data.prices(lookback=126) -> pd.DataFrame
  # Daily close prices

ctx.data.volume(lookback=126) -> pd.DataFrame
  # Daily volume

RISK LIMITS OVERRIDE

python
# Optional: override default risk limits
def risk_limits(self) -> dict:
    return {
        "max_position_pct": 0.10,    # 10% max per position
        "max_sector_pct": 0.35,      # 35% max per sector
        "max_drawdown_pct": 0.20,    # 20% max drawdown
        "min_positions": 5,          # Minimum 5 positions
    }

COMPLETE WORKING EXAMPLE — MOMENTUM RANKING

python
from podium_sdk import Strategy, StrategyContext

class MomentumRanking(Strategy):
    """6-month momentum, top 20 by trailing return, equal weight."""
    TOP_N = 20
    LOOKBACK_DAYS = 126

    def initialize(self, ctx: StrategyContext) -> None:
        # Called once on first tick. Use for
        # loading parameters or state.
        pass

    def universe(self, ctx: StrategyContext) -> list[str]:
        # Return the list of symbols to consider.
        # Called before each signal() call.
        returns = ctx.data.returns(lookback=self.LOOKBACK_DAYS + 5)
        if returns.empty:
            return []
        return list(returns.columns)

    def signal(self, ctx: StrategyContext) -> dict[str, float]:
        # Return target weights {symbol: weight}.
        # Weights are normalized to sum to 1.0.
        returns = ctx.data.returns(lookback=self.LOOKBACK_DAYS)
        if returns.empty:
            return {}
        cum_return = (1 + returns).prod() - 1
        ranked = cum_return.sort_values(ascending=False)
        top_n = ranked.head(self.TOP_N)
        if len(top_n) == 0:
            return {}
        weight = 1.0 / len(top_n)
        return {sym: round(weight, 6) for sym in top_n.index}

USER GUIDES

In-depth manuals for backtesting, strategy development, and deployment