Portfolio-level exposure limits

Per-trade risk (chapter 73) controls a single position; portfolio-level limits control the aggregate — because uncorrelated-looking positions can turn out to move together exactly when it hurts most (e.g. a market-wide selloff hits every long equity position simultaneously, regardless of how independent their individual signals seemed).

Max concurrent positions

def can_open_new_position(kite, max_concurrent: int) -> bool:
    open_count = len([p for p in kite.positions()["net"] if p["quantity"] != 0])
    return open_count < max_concurrent

Simple, blunt, effective — caps how many simultaneous bets a strategy (or the whole bot) can have running, independent of how good each individual signal looks.

Max aggregate exposure as % of capital

def total_exposure_value(kite) -> float:
    return sum(abs(p["quantity"]) * p["last_price"] for p in kite.positions()["net"] if p["quantity"] != 0)

def check_exposure_limit(kite, account_equity: float, max_exposure_multiple: float = 1.5) -> bool:
    exposure = total_exposure_value(kite)
    return exposure < account_equity * max_exposure_multiple

max_exposure_multiple above 1.0 accounts for leveraged products (MIS, F&O) where notional exposure exceeds actual capital deployed — decide this deliberately based on how much leverage your strategy is designed to use, not left implicit.

Sector/underlying concentration limits

def sector_exposure(kite, sector_map: dict[str, str]) -> dict[str, float]:
    """sector_map: tradingsymbol -> sector name"""
    exposure = {}
    for p in kite.positions()["net"]:
        if p["quantity"] == 0:
            continue
        sector = sector_map.get(p["tradingsymbol"], "unknown")
        exposure[sector] = exposure.get(sector, 0) + abs(p["quantity"]) * p["last_price"]
    return exposure

def check_sector_limit(kite, sector_map, sector: str, account_equity: float, max_sector_pct: float = 25.0) -> bool:
    exposure = sector_exposure(kite, sector_map)
    return exposure.get(sector, 0) < account_equity * (max_sector_pct / 100)

Five "different" positions that are all, say, IT-sector large-caps are not five independent bets in a market stress scenario — they're closer to one concentrated bet on the sector. This is a genuinely common mistake in retail multi-stock strategies that look diversified on paper.

Correlation-aware sizing — the more advanced version

For a serious multi-position book, compute a rolling correlation matrix across your universe and reduce sizing on new positions that are highly correlated with existing ones, rather than only capping by count/sector. This is meaningfully more complex to implement correctly — start with count/exposure/sector limits (above) before reaching for this.

Next: 075 — Automating stop-loss and target