Statistical Data Analysis and Inference › Confidence Intervals
Quantitative FinanceAll chapters Statistical Data Analysis and Inference › Confidence IntervalsOne section · Sections in this chapter5 / 9 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Hypothesis tests give binary decisions, while confidence intervals additionally communicate the precision of an estimate by providing a range of parameter values compatible with the procedure and assumptions.
For i.i.d. normal observations, the following interval has exact Student-t coverage. For a nonnormal sample, it is a large-sample approximation only when the standard error and regularity conditions justify it; dependent returns require an appropriate long-run-variance estimate. The interval is:
where:
- : sample mean (center of the interval)
- : positive upper critical value from the t-distribution with degrees of freedom (for 95% confidence with large , this is approximately 1.96)
- : sample size
- : significance level (for 95% confidence, )
- : estimated standard error of the mean, valid for the stated sampling model
- : margin of error
The construction follows from the sampling distribution of the standardized mean under those conditions. Across repeated samples, the procedure uses the positive critical magnitude so that 95% of the resulting intervals cover the fixed population mean when .
# Calculate 95% confidence interval for mean return
# Uses mean_daily, standard_error, and degrees_freedom computed in earlier sections
confidence_level = 0.95
alpha = 1 - confidence_level
# Critical value from t-distribution
t_critical = stats.t.ppf(1 - alpha / 2, degrees_freedom)
# Confidence interval
margin_of_error = t_critical * standard_error
ci_lower = mean_daily - margin_of_error
ci_upper = mean_daily + margin_of_error
# Annualized confidence interval
ci_lower_annual = ci_lower * 252
ci_upper_annual = ci_upper * 25295% Confidence Interval for Mean Log Return -------------------------------------------------- Daily: [-0.002203, 0.002600] Annualized: [-55.51%, 65.52%] Point estimate (annualized): 5.00% Width of CI (annualized): 121.04%

A 95% confidence interval means: if we repeated this sampling procedure many times, 95% of the constructed intervals would contain the true population mean. It does not mean there is a 95% probability the true mean lies in this specific interval. The true mean is fixed; our interval either contains it or it doesn't.
This distinction matters conceptually. The frequentist interpretation views probability as a long-run frequency. Across many repetitions of the sampling procedure, 95% of intervals would capture the true parameter. The Bayesian interpretation, which allows probability statements about parameters, requires additional assumptions about prior beliefs.
Confidence Intervals and Risk-Adjusted Returns
Confidence intervals are particularly useful for Sharpe ratios, which are notoriously imprecise. A strategy might show a Sharpe ratio of 1.0, but the confidence interval could span from 0.2 to 1.8, which would change our assessment of the strategy's quality.
The uncertainty of a ratio depends on both its estimated mean and its estimated dispersion. A normal-return model gives the familiar single-period standard-error approximation , where is the population differential-return ratio. Our worked return mixture is not normal, so we use a more general approximation.
For i.i.d. differential returns with positive variance and a finite fourth moment, define , population skewness , and raw kurtosis , where denotes expectation under the population return law. The delta method uses a linear expression to approximate how small estimation errors in the mean and standard deviation affect their ratio. Applying it jointly to the mean and variance gives:
Here combines mean uncertainty, dispersion uncertainty, and their covariance. Under a normal distribution, and , so . A Wald interval is the estimate plus or minus a normal critical value times its estimated standard error. A nondegenerate first-order interval also requires .
The code estimates the same coefficient as the mean square of , where uses sample centering and denominator- dispersion. These influence values approximate each observation's contribution to the ratio's first-order estimation error. Squaring avoids numerical cancellation in the expanded expression for . The point estimate retains the denominator- sample standard deviation; this changes only lower-order terms in the asymptotic calculation.
This interval is approximate, not an exact finite-sample 95% guarantee. Finite sample moments do not establish finite population moments. Serial dependence requires the long-run variance of the ratio's influence function rather than this i.i.d. coefficient.
def sharpe_confidence_interval(
returns, reference_return=0.0, confidence=0.95, periods_per_year=252
):
"""
Compute an approximate annualized Sharpe-ratio interval relative to a
matching-period reference return.
returns and reference_return must use the same period and return
convention. The default reference_return=0.0 makes the zero-reference
assumption explicit. Reference may be a finite scalar or a vector matching
returns exactly. The IID approximation requires positive population
variance, finite fourth moment, and nonzero first-order influence variance.
Annualize both the estimate and its moment-based standard error by
sqrt(periods_per_year). This is not an exact finite-sample interval;
serial dependence requires an influence-function long-run variance.
"""
returns = validate_return_sample(returns)
periods_per_year = validate_periods_per_year(periods_per_year)
confidence = np.asarray(confidence, dtype=float)
if confidence.ndim != 0 or not np.isfinite(confidence) or not 0 < confidence < 1:
raise ValueError(
"confidence must be a finite scalar strictly between zero and one"
)
confidence = float(confidence)
reference = np.asarray(reference_return, dtype=float)
if reference.ndim != 0 and reference.shape != returns.shape:
raise ValueError(
"reference_return must be a scalar or match the one-dimensional returns exactly"
)
if not np.all(np.isfinite(reference)):
raise ValueError("reference_return must contain only finite values")
excess_returns = validate_return_sample(returns - reference)
n = len(excess_returns)
mean_excess = np.mean(excess_returns)
std_return = np.std(excess_returns, ddof=1)
sharpe_period = mean_excess / std_return
sharpe = sharpe_period * np.sqrt(periods_per_year)
# Denominator-n moments and a nonnegative influence-square coefficient
z = (excess_returns - mean_excess) / np.std(excess_returns, ddof=0)
influence = z - 0.5 * sharpe_period * (z**2 - 1)
variance_coefficient = np.mean(influence**2)
if (
not np.isfinite(sharpe)
or not np.isfinite(variance_coefficient)
or variance_coefficient <= 0
):
raise ValueError(
"a finite ratio and positive finite influence variance are required"
)
se_sharpe_period = np.sqrt(variance_coefficient / n)
se_sharpe = se_sharpe_period * np.sqrt(periods_per_year)
z_critical = stats.norm.isf((1 - confidence) / 2)
if not np.isfinite(z_critical) or z_critical <= 0:
raise ValueError("confidence must produce a positive finite critical value")
ci_lower = sharpe - z_critical * se_sharpe
ci_upper = sharpe + z_critical * se_sharpe
if not np.all(np.isfinite([se_sharpe, ci_lower, ci_upper])) or ci_lower >= ci_upper:
raise ValueError(
"the interval must be finite and numerically distinguishable for these inputs"
)
return sharpe, ci_lower, ci_upper, se_sharpe
sharpe, sr_lower, sr_upper, se_sr = sharpe_confidence_interval(
log_returns, reference_return=0.0
)Approximate 95% IID-Moment Interval for Log-Return Ratio -------------------------------------------------- Sharpe Ratio: 0.1632 Standard Error: 1.0008 Approximate 95% IID-moment CI: [-1.7984, 2.1248] Under the IID finite-fourth-moment approximation, the CI includes zero.