Optimal Stopping
Longstaff-Schwartz algorithm for optimal exit timing
Optimal stopping answers: given your current position and stochastic market dynamics, should you exit now or wait? Horizon implements the Longstaff-Schwartz least-squares Monte Carlo algorithm, computing the optimal exit boundary by backward regression on simulated price paths.
API
Generate simulated paths
python
paths = hz.generate_gbm_paths(
S0=0.55, # current price (or probability)
mu=0.0, # drift
sigma=0.20, # volatility
T=30.0, # time horizon (days)
n_steps=100, # time steps per path
n_paths=10_000, # number of Monte Carlo paths
)
# paths shape: (n_paths, n_steps + 1)
Longstaff-Schwartz backward regression
python
def payoff_fn(price, t):
"""Payoff from exiting at price `price` at time `t`."""
return price - 0.55 # simple P&L from entry at 0.55
model = hz.longstaff_schwartz(
paths=paths,
payoff_fn=payoff_fn,
discount=0.99, # per-step discount factor
n_basis=3, # number of basis functions for regression
)
model.continuation_values # estimated continuation values at each step
model.exercise_boundary # price threshold per time step
model.expected_payoff # expected payoff under optimal policy
Real-time exit decision
python
should_exit = hz.should_exit(
current_state={"price": 0.62, "time_remaining": 15.0},
model=model,
)
should_exit.exit # True/False
should_exit.cont_val # estimated value of continuing
should_exit.exit_val # value of exiting now
How it works
The Longstaff-Schwartz algorithm works backward from expiry:
- At the final step, the exercise value is
payoff_fn(S_T, T). - At each earlier step, regress the discounted future value against basis functions of the current state (e.g., polynomials of price).
- The regression gives an estimate of the continuation value. Exercise whenever
payoff_fn(S_t, t) > continuation_value(S_t, t). - The exercise boundary is the price at each time step where the payoff equals the continuation value.
Example: exiting a prediction market position
python
# You bought YES at 0.55. When should you sell?
paths = hz.generate_gbm_paths(S0=0.55, mu=0.0, sigma=0.25, T=14.0,
n_steps=50, n_paths=5000)
def pnl(price, t):
return price - 0.55
model = hz.longstaff_schwartz(paths, pnl, discount=0.995)
# Current situation: price is 0.68 with 7 days left
decision = hz.should_exit({"price": 0.68, "time_remaining": 7.0}, model)
if decision.exit:
print(f"Exit now. Exit value: {decision.exit_val:.3f}, "
f"continuation: {decision.cont_val:.3f}")
else:
print(f"Hold. Continuation value {decision.cont_val:.3f} > "
f"exit value {decision.exit_val:.3f}")
When to use
- Profit taking: determine the price level at which taking profit now is better than waiting for more upside.
- Stop loss placement: compute the boundary below which holding has negative expected continuation value.
- Event markets: prediction markets with a known resolution date map directly to the finite-horizon stopping problem.
- Options-like positions: any position with time decay or a known expiry benefits from optimal stopping analysis.
The model is most useful when the position has a finite horizon and the payoff structure is path-dependent or nonlinear.