Skip to content

Commit 7d797d2

Browse files
Add Performance Analysis utils (Hurst, Omega, Tail, Gain-Pain, Active Performance), update main README to v2.0.0, and ensure emoji-free documentation
1 parent 7aafc5b commit 7d797d2

14 files changed

Lines changed: 337 additions & 6 deletions

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Learn-Quant: Master Quantitative Finance & Python (v1.9.0)
1+
# Learn-Quant: Master Quantitative Finance & Python (v2.0.0)
22

33
[![Lint](https://github.com/MeridianAlgo/Learn-Quant/actions/workflows/lint.yml/badge.svg)](https://github.com/MeridianAlgo/Learn-Quant/actions/workflows/lint.yml)
44

@@ -8,7 +8,7 @@
88

99
## Overview
1010

11-
Learn-Quant is a massive, curated collection of over 55+ self-contained modules designed to bridge the gap between academic theory and production-grade code. Whether you are a student, a software engineer moving into finance, or a trader learning to code, this repository provides the building blocks you need.
11+
Learn-Quant is a massive, curated collection of over 60+ self-contained modules designed to bridge the gap between academic theory and production-grade code. Whether you are a student, a software engineer moving into finance, or a trader learning to code, this repository provides the building blocks you need.
1212

1313
### Key Learning Outcomes
1414
- **Master Quant Strategies**: Implement Pairs Trading, Momentum, Mean Reversion, Position Sizing, and more.
@@ -55,6 +55,7 @@ Every folder is a fully functional lesson. Pick a topic and run the code.
5555
- `UTILS - Quantitative Methods - Regression`: Factor models & Alpha generation.
5656
- `UTILS - Quantitative Methods - Linear Algebra`: Portfolio optimization & risk modelling.
5757
- `UTILS - Quantitative Methods - Factor Models`: Fama-French 3-Factor model, factor regression, alpha decomposition, and performance attribution.
58+
- `UTILS - Quantitative Methods - Performance Analysis`: Hurst Exponent, Omega Ratio, Tail Ratio, and Active Metrics.
5859

5960
### Level 5: Strategies & Finance
6061
*Applied quantitative finance.*
@@ -100,10 +101,10 @@ cd "UTILS - Strategies - Momentum Trading"
100101
python momentum_strategy.py
101102
```
102103

103-
**Example: Learning Context Managers**
104+
**Example: Learning Performance Metrics**
104105
```bash
105-
cd "UTILS - Advanced Python - Context Managers"
106-
python context_managers_tutorial.py
106+
cd "UTILS - Quantitative Methods - Performance Analysis"
107+
python hurst_exponent.py
107108
```
108109

109110
---
@@ -121,6 +122,6 @@ This project is open-sourced under the MIT License.
121122

122123
---
123124

124-
**Learn-Quant v1.9.0**
125+
**Learn-Quant v2.0.0**
125126
*Quantitative Finance | Algorithmic Trading | Python Mastery*
126127
**Maintained by MeridianAlgo**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Performance Analysis Utilities
2+
3+
## Overview
4+
This module provides quantitative performance metrics to evaluate risk-adjusted returns and the quality of investment strategies. Beyond simple metrics like the Sharpe Ratio, these tools help quants analyze tail risk, active management skill, and the statistical properties of return series.
5+
6+
## Key Metrics Included
7+
8+
### 1. Hurst Exponent
9+
Characterizes the long-term memory of a time series.
10+
- **H < 0.5**: Mean-reverting series.
11+
- **H = 0.5**: Random walk.
12+
- **H > 0.5**: Trending series.
13+
Files: `hurst_exponent.py`
14+
15+
### 2. Omega Ratio
16+
Measures the risk-adjusted return relative to a target return level. It considers the entire return distribution, representing the ratio of probability-weighted gains to probability-weighted losses.
17+
Files: `omega_ratio.py`
18+
19+
### 3. Tail Ratio
20+
Highlights the relationship between the extreme positive and negative outliers of a return distribution. It is the absolute value of the 95th percentile return divided by the absolute value of the 5th percentile return.
21+
Files: `tail_ratio.py`
22+
23+
### 4. Gain-to-Pain Ratio
24+
A metric popularized by market wizards like Jack Schwager, representing the sum of all returns divided by the absolute sum of all negative returns. It provides a quick way to gauge the consistency of a strategy.
25+
Files: `gain_to_pain_ratio.py`
26+
27+
### 5. Tracking Error and Information Ratio
28+
Metrics for active portfolio management.
29+
- **Tracking Error**: The standard deviation of the difference between the portfolio and its benchmark.
30+
- **Information Ratio**: The active return per unit of tracking error, measuring a manager's skill in outperforming the index.
31+
Files: `active_performance.py`
32+
33+
## Usage
34+
Each script contains a baseline implementation and a sample execution in the `if __name__ == "__main__":` block. To run any utility, execute it from the command line:
35+
36+
```bash
37+
python hurst_exponent.py
38+
```
39+
40+
## Portfolio Performance
41+
These utilities are designed to be used in conjunction with risk metrics like Value at Risk (VaR) and Drawdown to provide a holistic view of portfolio performance and risk of ruin.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Active Performance Metrics Utility
3+
----------------------------------
4+
Information Ratio and Tracking Error measure a portfolio manager's skill
5+
at outperforming a benchmark.
6+
7+
- Tracking Error: Standard deviation of active returns.
8+
- Information Ratio: Active return divided by Tracking Error.
9+
"""
10+
11+
import numpy as np
12+
13+
14+
def active_metrics(returns, benchmark_returns):
15+
"""
16+
Computes Tracking Error and Information Ratio.
17+
18+
Args:
19+
returns (list or np.array): Series of portfolio returns.
20+
benchmark_returns (list or np.array): Series of benchmark returns.
21+
22+
Returns:
23+
dict: A dictionary containing 'tracking_error' and 'information_ratio'.
24+
"""
25+
returns = np.array(returns)
26+
benchmark_returns = np.array(benchmark_returns)
27+
28+
if len(returns) != len(benchmark_returns):
29+
raise ValueError("Return series and benchmark series must be the same length.")
30+
31+
active_returns = returns - benchmark_returns
32+
tracking_error = np.std(active_returns)
33+
34+
if tracking_error == 0:
35+
return {"tracking_error": 0, "information_ratio": 0}
36+
37+
information_ratio = np.mean(active_returns) / tracking_error
38+
39+
return {
40+
"tracking_error": tracking_error,
41+
"information_ratio": information_ratio
42+
}
43+
44+
45+
if __name__ == "__main__":
46+
# Simulate a benchmark index (e.g. S&P 500)
47+
benchmark = np.random.normal(0.0005, 0.01, 252)
48+
# Simulate an active manager with some "alpha"
49+
alpha = 0.0001
50+
portfolio = benchmark + alpha + np.random.normal(0, 0.002, 252)
51+
52+
stats = active_metrics(portfolio, benchmark)
53+
for k, v in stats.items():
54+
print(f"{k.replace('_', ' ').title()}: {v:.4f}")
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Gain-to-Pain Ratio Calculation Utility
3+
--------------------------------------
4+
The Gain-to-Pain Ratio measures the cumulative return divided by the absolute
5+
loss sum of a return series. It's used to identify strategies with smooth paths.
6+
Created by Jack Schwager for his Market Wizards interviews.
7+
"""
8+
9+
import numpy as np
10+
11+
12+
def gain_to_pain_ratio(returns):
13+
"""
14+
Computes the Gain-to-Pain Ratio.
15+
16+
Args:
17+
returns (list or np.array): Series of returns.
18+
19+
Returns:
20+
float: Gain-to-Pain Ratio.
21+
"""
22+
returns = np.array(returns)
23+
total_returns = np.sum(returns)
24+
abs_loss_sum = np.abs(np.sum(returns[returns < 0]))
25+
26+
if abs_loss_sum == 0:
27+
return 0
28+
29+
return total_returns / abs_loss_sum
30+
31+
32+
if __name__ == "__main__":
33+
# Simulate some normally distributed returns
34+
daily = np.random.normal(0.001, 0.01, 252)
35+
print(f"Gain-to-Pain Ratio: {gain_to_pain_ratio(daily):.4f}")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""
2+
Hurst Exponent Calculation Utility
3+
----------------------------------
4+
The Hurst exponent (H) characterizes the long-term memory of a time series.
5+
6+
Interpretation:
7+
- H < 0.5: Mean-reverting (anti-persistent) series
8+
- H = 0.5: Random walk (Geometric Brownian Motion)
9+
- H > 0.5: Trending (persistent) series
10+
"""
11+
12+
import numpy as np
13+
14+
15+
def compute_hurst(ts):
16+
"""
17+
Computes the Hurst exponent of a time series using rescaled range (R/S) analysis.
18+
19+
Args:
20+
ts (list or np.array): Time series of price data.
21+
22+
Returns:
23+
float: Hurst exponent.
24+
"""
25+
ts = np.array(ts)
26+
lags = range(2, 20)
27+
28+
# Calculate the variance of the lagged differences
29+
tau = [np.sqrt(np.std(np.subtract(ts[lag:], ts[:-lag]))) for lag in lags]
30+
31+
# Use a linear fit to estimate the Hurst exponent
32+
poly = np.polyfit(np.log(lags), np.log(tau), 1)
33+
34+
# The Hurst exponent is the slope of the fit
35+
return poly[0] * 2.0
36+
37+
38+
if __name__ == "__main__":
39+
# Create a trending series
40+
trending = np.cumsum(np.random.randn(1000) + 0.1)
41+
# Create a mean-reverting series
42+
reverting = np.random.randn(1000)
43+
44+
print(f"Trending Hurst: {compute_hurst(trending):.4f}")
45+
print(f"Mean-Reverting Hurst: {compute_hurst(reverting):.4f}")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Omega Ratio Calculation Utility
3+
-------------------------------
4+
The Omega Ratio measures the risk-adjusted return relative to a target return.
5+
It's calculated as the probability-weighted gains divided by probability-weighted losses.
6+
Used to identify the performance relative to a benchmark (minimum acceptable return).
7+
"""
8+
9+
import numpy as np
10+
11+
12+
def omega_ratio(returns, target=0):
13+
"""
14+
Computes the Omega Ratio.
15+
16+
Args:
17+
returns (list or np.array): Series of returns.
18+
target (float): Minimum acceptable return level.
19+
20+
Returns:
21+
float: Omega Ratio.
22+
"""
23+
returns = np.array(returns)
24+
gains = returns[returns > target] - target
25+
losses = target - returns[returns < target]
26+
27+
if len(losses) == 0 or np.sum(losses) == 0:
28+
return np.inf
29+
30+
return np.sum(gains) / np.sum(losses)
31+
32+
33+
if __name__ == "__main__":
34+
# Simulate some normally distributed returns
35+
daily = np.random.normal(0.001, 0.01, 252)
36+
print(f"Omega Ratio at target 0%: {omega_ratio(daily):.4f}")
37+
print(f"Omega Ratio at target 0.1%: {omega_ratio(daily, target=0.001):.4f}")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Tail Ratio Calculation Utility
3+
------------------------------
4+
The Tail Ratio measures the relationship between positive and negative outliers.
5+
It's calculated as the absolute value of the 95th percentile (right tail)
6+
divided by the absolute value of the 5th percentile (left tail).
7+
"""
8+
9+
import numpy as np
10+
11+
12+
def compute_tail_ratio(returns):
13+
"""
14+
Computes the Tail Ratio.
15+
16+
Args:
17+
returns (list or np.array): Series of returns.
18+
19+
Returns:
20+
float: Tail Ratio.
21+
"""
22+
returns = np.array(returns)
23+
right_tail = np.percentile(returns, 95)
24+
left_tail = np.abs(np.percentile(returns, 5))
25+
26+
if left_tail == 0:
27+
return 0
28+
29+
return right_tail / left_tail
30+
31+
32+
if __name__ == "__main__":
33+
# Simulate some fat-tailed returns or normal ones
34+
daily = np.random.standard_t(df=5, size=1000) * 0.01
35+
print(f"Tail Ratio (T-Dist with df=5): {compute_tail_ratio(daily):.4f}")
36+
37+
normal = np.random.normal(0.0005, 0.01, 1000)
38+
print(f"Tail Ratio (Normal): {compute_tail_ratio(normal):.4f}")
70 Bytes
Binary file not shown.
-114 Bytes
Binary file not shown.
-60 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)