A yes/no question needs a logit
When the outcome is yes or no (does SPY rise tomorrow?), a straight-line regression can predict probabilities below 0 or above 1. The logit model squeezes a linear score through a curve: P(up)=1/(1+e^(-z)) with z=β₀+β₁x₁+…. In statsmodels it is one line, smf.logit('up ~ ret + vol20 + spread', data).fit(disp=0), and res.predict(data) returns the probability of each row. The coefficients are changes in the log-odds, which are hard to feel. Two translations help. e^β is the odds ratio: the factor by which the odds of 'up' are multiplied when the variable rises by one unit (0.95 means a 5% cut). The average marginal effect, res.get_margeff().summary_frame()['dy/dx'], says how many points of probability one more unit adds, averaged over all rows.
A direction model must beat a trivial baseline, and in markets the baseline is strong: SPY rose on 55.0% of the 5,345 days, so a rule that always says 'up' is right 55.0% of the time. The logit with yesterday's return, the 20-day volatility and the 10y–2y spread gives an odds ratio of 0.95 for the return (a one-point higher return lowers the odds of a rise by 5%; the marginal effect is -1.26 points) and a McFadden R² of 0.0007, essentially nothing. Its hit rate is 55.2% against 55.0% for always saying 'up', because the model predicts a probability above 0.5 on 99% of days. A p-value below 5% says the coefficient is probably not zero; it does not say the model is useful. Always put the hit rate next to the naive rate.
- Coefficients are log-odds: translate them into odds ratios (
exp) or marginal effects on the probability. - Compare with the naive rule: always predicting the majority direction is the baseline a model must beat.
- Significant is not useful: a McFadden R-squared of 0.0007 is a coefficient you can measure and a forecast you cannot use.
Lab · what's graded
- The daily table15 pts
- The logit fit10 pts
- Odds ratios10 pts
- Average marginal effects15 pts
- The model's hit rate10 pts
- The naive baseline10 pts
- The whole study30 pts