Academy/Strategy Code Breakdown/Cash-Secured Put — Code Walkthrough
Strategy Code BreakdownLesson 7

Cash-Secured Put — Code Walkthrough

Understand how CRR prices the sold put, what assignment probability means mathematically, and how annualized return on the collateral is calculated.

13 minute read
4 key takeaways

Cash-Secured Put — Code Walkthrough

The cash-secured put (CSP) is a popular income strategy. You sell an OTM put and hold enough cash to buy the stock if assigned. It's equivalent to a covered call in terms of risk profile. Let's walk through what makes its Python implementation interesting — especially the assignment probability calculation.

Step 1 — CashSecuredPutStrategy.evaluate()

python
def evaluate(self, spot_price, historical_vol=0.25):
    sigma   = self.implied_volatility or historical_vol
    T       = self.days_to_expiry / 365.0
    strike  = round(spot_price * (1 + self.strike_offset), 2)  # e.g. 5% OTM

    # Price the put we're selling using CRR
    premium       = crr_price(spot_price, strike, T, r, sigma, 'put')
    total_premium = premium * self.contracts * 100  # per-contract dollar amount

    capital    = strike * self.contracts * 100  # cash collateral required
    breakeven  = strike - premium               # effective purchase price if assigned

    # Annualized return on collateral
    ann_return = (total_premium / capital) * (365 / self.days_to_expiry) * 100

    assign_prob = assignment_probability_crr(spot_price, strike, T, r, sigma)

The Breakeven Concept

"If I get assigned, I'm forced to buy the stock at the strike price. But I collected the premium first, so my effective cost basis is strike − premium." If you planned to buy the stock anyway, this is a strategy to acquire it at a discount — or collect income if it doesn't fall.

Step 2 — assignment_probability_crr: Risk-Neutral Terminal Distribution

python
def assignment_probability_crr(S, K, T, r, sigma, steps=100):
    """P(assigned) = P(S_T < K) under the risk-neutral measure."""
    dt  = T / steps
    u   = math.exp(sigma * math.sqrt(dt))
    d   = 1.0 / u
    p   = (math.exp(r * dt) - d) / (u - d)
    q   = 1 - p

    # Build the probability of each terminal node using log-space arithmetic
    log_p, log_q = math.log(p), math.log(q)
    log_binom = [0.0] * (steps + 1)
    log_binom[0] = steps * log_q  # all-down node: q^n
    for j in range(1, steps + 1):
        # Recurrence: log C(n,j) × p^j × q^(n-j)
        log_binom[j] = log_binom[j-1] + math.log(steps - j + 1) - math.log(j) + log_p - log_q

    # Sum probabilities for all terminal nodes where S_T < K
    prob_below = 0.0
    for j in range(steps + 1):
        spot_t = S * (u**j) * (d**(steps - j))
        if spot_t < K:
            prob_below += math.exp(log_binom[j])

    return min(max(prob_below, 0.0), 1.0)

Why Log-Space?

Binomial coefficients C(100, 50) are astronomically large (~10^29). Computing them directly overflows even float64. By working in log-space (log of the probability instead of the probability), we avoid overflow entirely, then exponentiate only at the summation step.

The function uses the CRR's risk-neutral probability p to construct the full terminal distribution, then sums the probability mass for all nodes where the stock ends below the strike. This is the model-implied P(assignment) — the probability the put expires in the money under the risk-neutral measure.

Step 3 — Interpreting the Output

Output FieldFormulaWhat to Watch For
premium_collectedCRR put price × contracts × 100Higher IV = fatter premium, but also higher risk
breakevenstrike − premium (per share)Your actual cost basis if assigned
annualized_return(premium/capital) × (365/days) × 100Compare to risk-free rate — is the risk worth it?
assignment_probabilityP(S_T < K) × 100Too high = risky; sweet spot is usually 20–35%
Key Takeaways
  • You sell an OTM put and hold cash = strike × 100 as collateral
  • Max profit is the premium collected; max loss is strike − premium
  • Assignment probability uses the risk-neutral terminal distribution from the CRR tree
  • Annualized return = (premium / capital) × (365 / days) × 100

Open Cash-Secured Put in Lab

Clone and analyze the cash-secured put strategy