Learn Without Walls

Module 19: Behavioral Finance & Market Anomalies

When humans are the data-generating process: cognitive biases, prospect theory, and exploitable market patterns

Part IV of 5 Module 19 of 22

Introduction: When Humans Are the Data-Generating Process

Classical finance assumes rational, utility-maximizing agents who instantly incorporate all available information into prices. Behavioral finance starts from a different premise: humans are the data-generating process in financial markets, and humans are systematically biased. These biases are not random noise — they are structured, predictable deviations from rationality that leave measurable fingerprints in asset prices. For a statistician, behavioral finance is the study of systematic errors in the human estimation process.

Stats Bridge

In statistics, we distinguish between random errors (unbiased noise that cancels in expectation) and systematic errors (bias that persists regardless of sample size). Cognitive biases are systematic errors in human judgment. They produce biased estimators of value, probability, and risk. Because these biases are shared across market participants, they aggregate into price distortions that a rational observer can detect — and potentially exploit.

1. Loss Aversion and Prospect Theory

1.1 The Core Finding

Kahneman and Tversky (1979) discovered that people do not evaluate outcomes in terms of final wealth levels (as expected utility theory assumes), but in terms of gains and losses relative to a reference point. Furthermore, losses are weighted approximately 2.5 times more heavily than equivalent gains.

v(x) = xα    for x ≥ 0      v(x) = −λ(−x)β    for x < 0

Typical estimates: α = β ≈ 0.88,   λ ≈ 2.25
Stats Bridge

The prospect theory value function is an asymmetric loss function. In statistics, the most common loss function is squared error (symmetric). Prospect theory says humans implicitly use a loss function where underprediction (loss) is penalized λ ≈ 2.5 times more than overprediction (gain). This is equivalent to using a weighted asymmetric loss function, which a statistician would recognize as a check function (used in quantile regression) with asymmetric weights.

1.2 Financial Implications of Loss Aversion

BehaviorDescriptionMarket Consequence
Disposition effectSell winners too early, hold losers too longMomentum: winners underreact on the upside
Equity premium puzzleStocks must offer very high returns to compensate for loss aversionHistorically high equity risk premium (~6%)
Risk aversion in gainsPrefer certain $50 over 50/50 chance of $100Demand for safe assets is irrationally high
Risk seeking in lossesPrefer gamble over certain lossDoubling down on losing positions
Finance Term

Disposition Effect — The tendency of investors to sell assets that have gained value while holding assets that have lost value. First documented by Shefrin and Statman (1985). This behavior is irrational because it generates taxable capital gains while forgoing tax-loss harvesting opportunities.

2. Overconfidence: Miscalibrated Confidence Intervals

2.1 The Calibration Problem

When people construct 90% confidence intervals for unknown quantities, the true value falls outside their intervals roughly 50% of the time. This is not a minor miscalibration — it is a massive, systematic failure of probabilistic reasoning.

Stats Bridge

A perfectly calibrated forecaster produces prediction intervals with correct coverage probability. If your 90% intervals contain the truth only 50% of the time, your intervals are drastically too narrow. In statistical terms, you are systematically underestimating variance. This maps to financial behavior: investors underestimate the uncertainty in their return forecasts, leading to overtrading and underdiversification.

2.2 Forms of Overconfidence

TypeStatistical DescriptionFinancial Manifestation
OverestimationBiased point estimate (Ê[skill] > E[skill])Believing you can beat the market consistently
OverprecisionUnderestimated variance (σ̂ << σ)Concentrated portfolios; too-tight stop losses
OverplacementBiased rank estimate (better-than-average effect)Active trading when passive would be better

2.3 Trading Volume and Overconfidence

Barber and Odean (2000) showed that individual investors who trade the most earn the lowest net returns. Overconfident traders trade too frequently, incurring transaction costs that erode returns. The annual return shortfall attributable to excessive trading is approximately 3.7 percentage points for the most active traders versus the least active.

Key Insight

Overconfidence is arguably the most costly bias in finance. It does not cancel across investors because it predominantly manifests as excessive trading, which is a pure cost. Whether you are overconfident that the stock will go up or overconfident that it will go down, you trade too much either way, and brokers capture the cost.

3. Anchoring: Biased Priors

3.1 The Mechanism

Anchoring is the tendency for initial values to disproportionately influence subsequent estimates, even when the initial values are arbitrary or irrelevant. In experiments, people who first see a random number give estimates biased toward that number.

Stats Bridge

Anchoring is analogous to a biased prior in Bayesian statistics. A Bayesian updater with a strong (informative) prior that is systematically wrong will produce biased posterior estimates, especially when the data (likelihood) is weak. In finance, the “prior” is the last price you saw, the analyst’s target, or the price you paid. The “data” is new information. When information is ambiguous (low SNR), the biased prior dominates.

3.2 Financial Examples of Anchoring

Key Insight

Anchoring creates underreaction to new information. When a company reports earnings 20% above expectations, the stock price adjusts upward, but often not by enough — because investors are anchored to the old valuation. This underreaction is one explanation for the post-earnings announcement drift anomaly (prices continue to drift in the direction of the earnings surprise for weeks after the announcement).

4. Herding: Correlated Errors Create Bubbles

4.1 The Statistics of Herding

When investors make independent errors, those errors cancel in aggregate (by the law of large numbers), and prices remain efficient. But when investors herd — imitating each other rather than acting on private information — their errors become correlated, and the law of large numbers breaks down.

Stats Bridge

The Efficient Market Hypothesis implicitly assumes independence of investor errors. Herding violates this assumption by introducing positive correlation among errors. Recall that Var(∑ Xi) = ∑ Var(Xi) + 2 ∑i<j Cov(Xi, Xj). When correlations are positive, the variance of the aggregate error does not shrink with N. The crowd wisdom fails because the crowd is not independent.

4.2 Herding Mechanisms

MechanismDescriptionExample
Informational cascadeIgnore private info; follow others’ actionsBuying a stock because “everyone is buying it”
Reputational herdingFund managers follow consensus to protect careers“Nobody gets fired for buying IBM”
Momentum feedbackRising prices attract more buyers, driving prices higherTech bubble 1999–2000, crypto 2017, 2021
Social media amplificationViral narratives create synchronized buying/sellingGameStop/AMC 2021 meme stock frenzy

4.3 Bubbles as Statistical Phenomena

A price bubble occurs when the market price deviates significantly from fundamental value for an extended period. From a statistical perspective, bubbles are characterized by:

5. The Momentum Anomaly

5.1 Definition and Evidence

The momentum anomaly, documented by Jegadeesh and Titman (1993), states that stocks that have performed well over the past 3–12 months tend to continue performing well, and stocks that have performed poorly tend to continue underperforming. This is one of the most robust and widely replicated findings in empirical finance.

Finance Term

Momentum — The tendency for assets with strong recent performance to continue outperforming and those with weak recent performance to continue underperforming. A momentum strategy buys recent winners and sells recent losers. Typical formation period: 3–12 months. Typical holding period: 3–12 months.

Stats Bridge

Momentum is positive serial correlation in returns at the 3–12 month horizon. The autocorrelation function of monthly returns is significantly positive at lags 1–11. This contradicts the random walk hypothesis, which predicts zero autocorrelation at all lags. The magnitude of the autocorrelation is small (typically 2–5%), but it is statistically significant and economically meaningful.

5.2 Behavioral Explanations

5.3 Python: Testing Momentum

Python
import numpy as np
import pandas as pd
import yfinance as yf
from scipy import stats

# Download a universe of ETFs as proxies for asset classes
tickers = ["XLK", "XLF", "XLE", "XLV", "XLI",
           "XLP", "XLU", "XLB", "XLY", "XLRE"]
data = yf.download(tickers, start="2005-01-01", end="2023-12-31")
prices = data["Adj Close"]

# Monthly returns
monthly_prices = prices.resample("M").last()
monthly_returns = monthly_prices.pct_change().dropna()

# ──────────────────────────────────────────────
# Momentum strategy: buy top 3 performers over past 12 months
# ──────────────────────────────────────────────
formation_period = 12  # months
holding_period = 1    # month
n_long = 3
n_short = 3

# Compute trailing returns (skip most recent month to avoid reversal)
trailing_ret = monthly_prices.pct_change(formation_period).shift(1)

momentum_returns = []
for date in monthly_returns.index[formation_period + 1:]:
    if date not in trailing_ret.index:
        continue

    ranks = trailing_ret.loc[date].dropna().rank(ascending=False)

    # Long winners, short losers
    winners = ranks[ranks <= n_long].index
    losers = ranks[ranks > len(ranks) - n_short].index

    if date in monthly_returns.index:
        long_ret = monthly_returns.loc[date, winners].mean()
        short_ret = monthly_returns.loc[date, losers].mean()
        momentum_returns.append({
            "date": date,
            "long": long_ret,
            "short": short_ret,
            "long_short": long_ret - short_ret,
            "long_only": long_ret,
        })

mom_df = pd.DataFrame(momentum_returns).set_index("date")

# ──────────────────────────────────────────────
# Statistical analysis
# ──────────────────────────────────────────────
for col in ["long_short", "long_only"]:
    ret = mom_df[col]
    ann_ret = ret.mean() * 12
    ann_vol = ret.std() * np.sqrt(12)
    sharpe = ann_ret / ann_vol
    t_stat, p_val = stats.ttest_1samp(ret, 0)

    print(f"\n=== {col.replace('_', ' ').title()} ===")
    print(f"Ann. Return:  {ann_ret:+.2%}")
    print(f"Ann. Vol:     {ann_vol:.2%}")
    print(f"Sharpe Ratio: {sharpe:.3f}")
    print(f"t-statistic:  {t_stat:.3f}")
    print(f"p-value:      {p_val:.4f}")
    print(f"Skewness:     {ret.skew():.3f}")
    print(f"Kurtosis:     {ret.kurtosis():.3f}")

# Test for serial correlation in momentum returns
from statsmodels.stats.diagnostic import acorr_ljungbox
lb = acorr_ljungbox(mom_df["long_short"].dropna(), lags=[6, 12], return_df=True)
print(f"\nLjung-Box test for autocorrelation in momentum returns:")
print(lb)

6. Mean Reversion: The Long-Run Counterpart

6.1 The Evidence

While momentum operates at the 3–12 month horizon, mean reversion operates at longer horizons (3–5 years). DeBondt and Thaler (1985) showed that past losers over 3–5 year periods subsequently outperform past winners. This is negative serial correlation at long lags.

Stats Bridge

The autocorrelation function of stock returns shows a characteristic pattern: positive at short lags (3–12 months), approximately zero at the 1–2 year horizon, and negative at 3–5 year lags. This is consistent with an initial underreaction (momentum) followed by an overreaction and correction (mean reversion). The full autocorrelation structure is what a time series statistician would use to characterize the DGP.

6.2 Autocorrelation Structure of Returns

HorizonAutocorrelationInterpretationTrading Strategy
1 daySlightly negativeBid-ask bounce; microstructureShort-term mean reversion
1 week – 1 month≈ 0 to slightly positiveNoise; weak continuationAmbiguous
3 – 12 monthsPositive (2–5%)Momentum (underreaction)Trend following
1 – 2 years≈ 0Transition zoneNone
3 – 5 yearsNegativeMean reversion (overreaction correction)Contrarian / value

7. The Value Premium

7.1 Definition

The value premium is the historical tendency for “cheap” stocks (low price relative to fundamentals) to outperform “expensive” stocks (high price relative to fundamentals). Common measures of value include:

MetricFormulaValue Stock Has
Price-to-Earnings (P/E)Price / Earnings per shareLow P/E
Price-to-Book (P/B)Market cap / Book valueLow P/B
Earnings YieldEarnings / Price = 1 / P/EHigh E/P
Dividend YieldDividends / PriceHigh dividend yield
Enterprise Value / EBITDA(Market cap + Debt − Cash) / EBITDALow EV/EBITDA

7.2 Behavioral Explanation

Behavioral finance attributes the value premium to systematic overextrapolation:

7.3 Risk-Based Explanation

The alternative explanation is that value stocks are genuinely riskier: they are often distressed companies with high leverage and uncertain futures. The value premium is compensation for bearing this risk, not a free lunch from behavioral mispricing.

Key Insight

The debate between behavioral and risk-based explanations for the value premium is one of the central unresolved questions in finance. For a statistician, the key point is that you cannot distinguish risk from mispricing using return data alone. A higher average return is consistent with either a risk premium (rational) or persistent overvaluation that eventually corrects (behavioral). You need additional identifying assumptions to separate the two.

Python
import numpy as np
import pandas as pd
import yfinance as yf
from scipy import stats

# Proxy for value premium: compare value vs growth ETFs
etfs = {
    "Value": "IWD",      # iShares Russell 1000 Value
    "Growth": "IWF",     # iShares Russell 1000 Growth
    "Market": "SPY",     # S&P 500
}

data = yf.download(list(etfs.values()), start="2005-01-01", end="2023-12-31")
prices = data["Adj Close"]
prices.columns = list(etfs.values())
monthly = prices.resample("M").last().pct_change().dropna()

# Value minus Growth spread (HML proxy)
hml_proxy = monthly["IWD"] - monthly["IWF"]

# Test if value premium is statistically significant
t_stat, p_val = stats.ttest_1samp(hml_proxy, 0)
ann_premium = hml_proxy.mean() * 12
ann_vol = hml_proxy.std() * np.sqrt(12)

print("=== Value Premium (Value - Growth) ===")
print(f"Annualized premium: {ann_premium:+.2%}")
print(f"Annualized vol:     {ann_vol:.2%}")
print(f"Sharpe ratio:       {ann_premium/ann_vol:.3f}")
print(f"t-statistic:        {t_stat:.3f}")
print(f"p-value:            {p_val:.4f}")

# Rolling 3-year value premium (to see time variation)
rolling_premium = hml_proxy.rolling(36).mean() * 12
print(f"\nRecent 3Y ann. premium: {rolling_premium.iloc[-1]:+.2%}")
print(f"Historical avg:        {rolling_premium.mean():+.2%}")

# Compare performance by decade
for period_name, start, end in [
    ("2005-2009", "2005", "2009"),
    ("2010-2014", "2010", "2014"),
    ("2015-2019", "2015", "2019"),
    ("2020-2023", "2020", "2023"),
]:
    subset = hml_proxy[start:end]
    print(f"{period_name}: ann. premium = {subset.mean()*12:+.2%}, "
          f"t = {stats.ttest_1samp(subset, 0)[0]:.2f}")

8. Are Anomalies Real Alpha or Risk Premiums?

8.1 The Debate Framework

For every market anomaly, there are three possible explanations:

ExplanationImplicationStatistical Test
Genuine mispricing (alpha)Exploitable; should diminish once discoveredAbnormal returns persist after risk adjustment
Compensation for riskNot exploitable risk-free; premium is payment for riskReturns explained by priced risk factors
Data mining artifactNot real; result of looking at too many patternsFails out-of-sample or in other markets
Stats Bridge

This debate maps directly to model specification in regression. If you regress strategy returns on known risk factors (market, size, value, momentum) and the intercept (α) is significantly positive, the strategy earns returns beyond what risk exposure explains. If α is zero after controlling for factors, the strategy was just taking factor risk. The Fama-French factor models are the financial equivalent of including control variables in a regression.

8.2 The Replication Crisis in Finance

Harvey, Liu, and Zhu (2016) documented over 400 published factors that allegedly explain the cross-section of stock returns. Many of these cannot be replicated out-of-sample. Applying multiple testing corrections, the majority of published factors have t-statistics that fail to reach the adjusted significance threshold.

Common Pitfall

The standard t-statistic threshold of 2.0 (p < 0.05) is far too lenient for factor discovery given the number of factors that have been tested across the history of finance research. Harvey et al. suggest a minimum t-statistic of 3.0 for new factor discoveries, accounting for the hundreds of factors already tested. This is the financial version of the multiple testing correction, applied at the literature level.

9. Calendar Anomalies

9.1 The January Effect

Historically, stock returns in January have been higher than other months, especially for small-cap stocks. The most common explanation is tax-loss selling: investors sell losing positions in December to harvest tax losses, depressing prices. When selling pressure subsides in January, prices rebound.

9.2 Day-of-Week Effect

Returns on Mondays have historically been lower than other days (the “Monday effect”). Possible explanations include the accumulation of negative news over weekends and institutional trading patterns.

9.3 Other Calendar Patterns

AnomalyPatternStatus (Post-Discovery)
January effectHigher returns in JanuaryWeakened significantly; mostly in small caps
Monday effectNegative Monday returnsLargely disappeared
Turn-of-monthHigher returns around month-end/startStill present; linked to payroll flows
Holiday effectHigher returns before holidaysWeak but persistent
Halloween effectNov–Apr outperforms May–OctSurprisingly robust across markets

9.4 Python: Testing Calendar Effects

Python
import numpy as np
import pandas as pd
import yfinance as yf
from scipy import stats

spy = yf.download("SPY", start="2000-01-01", end="2023-12-31")
returns = spy["Adj Close"].pct_change().dropna()

# ──────────────────────────────────────────────
# Test 1: January Effect
# ──────────────────────────────────────────────
monthly_returns = spy["Adj Close"].resample("M").last().pct_change().dropna()
monthly_returns.index = monthly_returns.index.month

jan_returns = monthly_returns[monthly_returns.index == 1]
other_returns = monthly_returns[monthly_returns.index != 1]

t_jan, p_jan = stats.ttest_ind(jan_returns, other_returns)
print("=== January Effect ===")
print(f"January mean return: {jan_returns.mean():+.4f}")
print(f"Other months mean:   {other_returns.mean():+.4f}")
print(f"t-statistic: {t_jan:.3f}, p-value: {p_jan:.4f}")

# Monthly return by month
monthly_returns_full = spy["Adj Close"].resample("M").last().pct_change().dropna()
by_month = monthly_returns_full.groupby(monthly_returns_full.index.month).agg(["mean", "std", "count"])
by_month.columns = ["Mean Return", "Std Dev", "Count"]
by_month["t-stat"] = by_month["Mean Return"] / (by_month["Std Dev"] / np.sqrt(by_month["Count"]))
by_month.index = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
print("\nMonthly return patterns:")
print(by_month.round(4))

# ──────────────────────────────────────────────
# Test 2: Day-of-Week Effect
# ──────────────────────────────────────────────
returns_dow = returns.copy()
returns_dow.index = returns_dow.index.dayofweek  # 0=Mon, 4=Fri

by_dow = returns.groupby(returns.index.dayofweek).agg(["mean", "std", "count"])
by_dow.columns = ["Mean Return", "Std Dev", "Count"]
by_dow["t-stat"] = by_dow["Mean Return"] / (by_dow["Std Dev"] / np.sqrt(by_dow["Count"]))
by_dow.index = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

print("\n=== Day-of-Week Effect ===")
print(by_dow.round(6))

# ANOVA test: are day-of-week returns significantly different?
groups = [returns[returns.index.dayofweek == d] for d in range(5)]
f_stat, p_anova = stats.f_oneway(*groups)
print(f"\nANOVA F-statistic: {f_stat:.3f}, p-value: {p_anova:.4f}")

# ──────────────────────────────────────────────
# Test 3: Halloween Effect (Nov-Apr vs May-Oct)
# ──────────────────────────────────────────────
winter = monthly_returns_full[monthly_returns_full.index.month.isin([11,12,1,2,3,4])]
summer = monthly_returns_full[monthly_returns_full.index.month.isin([5,6,7,8,9,10])]

t_hw, p_hw = stats.ttest_ind(winter, summer)
print("\n=== Halloween Effect (Nov-Apr vs May-Oct) ===")
print(f"Winter mean: {winter.mean():+.4f} ({winter.mean()*12:+.2%} ann.)")
print(f"Summer mean: {summer.mean():+.4f} ({summer.mean()*12:+.2%} ann.)")
print(f"t-statistic: {t_hw:.3f}, p-value: {p_hw:.4f}")

10. Chapter Summary

Cognitive BiasStatistical AnalogueMarket Anomaly
Loss aversionAsymmetric loss functionDisposition effect; equity premium puzzle
OverconfidenceUnderestimated varianceExcessive trading; concentrated portfolios
AnchoringBiased Bayesian priorUnderreaction; post-earnings drift
HerdingCorrelated errors (broken independence)Bubbles and crashes
Extrapolation biasOverfitting to recent dataValue premium; long-run mean reversion
ConservatismInsufficient updating (sticky prior)Momentum (3–12 month positive autocorrelation)
Availability biasNon-representative samplingOverreaction to salient news events
Key Insight

For a statistician, the deepest lesson of behavioral finance is this: the data-generating process in financial markets includes human psychology. The statistical properties of returns — fat tails, volatility clustering, momentum, mean reversion — are not arbitrary. They are the fingerprints of systematic human biases aggregated through market prices. Understanding the psychology does not just explain the statistics; it helps you predict when the statistics will change (because human nature does not change, even when market structure does).

Common Pitfall

Knowing about cognitive biases does not make you immune to them. The psychologist who studies overconfidence is still overconfident. The trader who knows about loss aversion still feels losses more keenly than gains. The value of behavioral finance is not in making better intuitive decisions — it is in building systematic processes (rules, models, checklists) that override biased intuition with disciplined analysis. This is where the statistician’s quantitative toolkit becomes a genuine competitive advantage.