ML4T - 第8章第1节 蒙特卡洛估计夏普率 Monte Carlo Estimation of Sharpe Ratio
目录
一、Aim 目的
二、Analytical 解析法
三、Numerical 数值法
四、Compare 比对
五、Data Format 数据格式
六、All code 所有代码
原文:https://github.com/stefan-jansen/machine-learning-for-trading/blob/main/08_ml4t_workflow/01_multiple_testing/deflated_sharpe_ratio.py
一、Aim 目的
这个代码 用于计算和模拟在给定均值(mu
)和标准差(sigma
)的情况下,最大夏普比率(Sharpe Ratio)的解析解和数值解。
-
解析法(Analytical):基于极值理论,使用正态分布的分位数函数。
-
数值法(Numerical):通过蒙特卡洛模拟生成大量随机样本,取最大值并平均。
我们有两种方法,然后看能不能用蒙特卡洛的方法来代替解析法得到的结果。
二、Analytical 解析法
def get_analytical_max_sr(mu, sigma, num_trials):emc = 0.5772156649 # Euler-Mascheroni constantmaxZ = (1 - emc) * ss.norm.ppf(1 - 1. / num_trials) + emc * ss.norm.ppf(1 - 1 / (num_trials * np.e))return mu + sigma * maxZ
-
目的:使用解析公式估计最大夏普比率的期望值。
-
原理:基于极值理论,有对应的数学公式。
-
返回值:最大夏普比率的解析估计值。
三、Numerical 数值法
def get_numerical_max_sr(mu, sigma, num_trials, n_iter):max_sr, count = [], 0while count < n_iter:count += 1series = np.random.normal(mu, sigma, num_trials)max_sr.append(max(series))return np.mean(max_sr), np.std(max_sr)
-
目的:通过蒙特卡洛模拟估计最大夏普比率的期望值和标准差。
-
过程:
-
每次模拟生成
num_trials
个正态分布随机数。 -
取最大值并记录。
-
重复
n_iter
次,计算这些最大值的均值和标准差。
-
-
返回值:最大值的均值和标准差。
四、Compare 比对
def simulate(mu, sigma, num_trials, n_iter):"""Get analytical and numerical solutions"""expected_max_sr = get_analytical_max_sr(mu, sigma, num_trials)mean_max_sr, stdmean_max_sr = get_numerical_max_sr(mu, sigma, num_trials, n_iter)return expected_max_sr, mean_max_sr, stdmean_max_srdef main():n_iter, sigma, output, count = 1e4, 1, [], 0for i, prod_ in enumerate(product(np.linspace(-100, 100, 101), range(10, 1001, 10)), 1):if i % 10 == 0:print(i, end=' ', flush=True)mu, num_trials = prod_[0], prod_[1]expected_max_sr, mean_max_sr, std_max_sr = simulate(mu, sigma, num_trials, n_iter)err = expected_max_sr - mean_max_sroutput.append([mu, sigma, num_trials, n_iter,expected_max_sr, mean_max_sr,std_max_sr, err])output = pd.DataFrame(output,columns=['mu', 'sigma', 'num_trials', 'n_iter','expected_max_sr', 'mean_max_sr','std_max_sr', 'err'])
同时运行解析和数值方法,返回两者的结果。
-
参数范围:
-
mu
:从 -100 到 100,共 101 个点。 -
num_trials
:从 10 到 1000,步长为 10。 -
总共组合数:101 × 100 = 10100 组。
-
-
过程:
-
对每组参数运行模拟。
-
记录解析解、数值解、误差等信息。
-
注意:这里计算比较慢,所以改成了if i % 10 == 0:打印,否则很久没有输出,以为出问题了。
(我是电脑跑完大约要1~2小时)
五、Data Format 数据格式
列名 | 含义 |
---|---|
mu | 均值 |
sigma | 标准差(固定为 1) |
num_trials | 每次模拟的样本数量 |
n_iter | 蒙特卡洛模拟次数(固定为 1e4) |
expected_max_sr | 解析法估计的最大值 |
mean_max_sr | 数值法估计的最大值 |
std_max_sr | 数值法估计的标准差 |
err | 解析解与数值解的误差 |
六、All code 所有代码
#!/usr/bin/env python
# On 20140607 by lopezdeprado@lbl.gov
__modified_author__ = 'MangoQuant' # https://blog.csdn.net/2401_82851462from itertools import productimport numpy as np
import pandas as pd
import scipy.stats as ssdef get_analytical_max_sr(mu, sigma, num_trials):"""Compute the expected maximum Sharpe ratio (Analytically)"""# Euler-Mascheroni constantemc = 0.5772156649maxZ = (1 - emc) * ss.norm.ppf(1 - 1. / num_trials) + emc * ss.norm.ppf(1 - 1 / (num_trials * np.e))return mu + sigma * maxZdef get_numerical_max_sr(mu, sigma, num_trials, n_iter):"""Compute the expected maximum Sharpe ratio (Numerically)"""max_sr, count = [], 0while count < n_iter:count += 1series = np.random.normal(mu, sigma, num_trials)max_sr.append(max(series))return np.mean(max_sr), np.std(max_sr)def simulate(mu, sigma, num_trials, n_iter):"""Get analytical and numerical solutions"""expected_max_sr = get_analytical_max_sr(mu, sigma, num_trials)mean_max_sr, stdmean_max_sr = get_numerical_max_sr(mu, sigma, num_trials, n_iter)return expected_max_sr, mean_max_sr, stdmean_max_srdef main():n_iter, sigma, output, count = 1e4, 1, [], 0for i, prod_ in enumerate(product(np.linspace(-100, 100, 101), range(10, 1001, 10)), 1):if i % 10 == 0:print(i, end=' ', flush=True)mu, num_trials = prod_[0], prod_[1]expected_max_sr, mean_max_sr, std_max_sr = simulate(mu, sigma, num_trials, n_iter)err = expected_max_sr - mean_max_sroutput.append([mu, sigma, num_trials, n_iter,expected_max_sr, mean_max_sr,std_max_sr, err])output = pd.DataFrame(output,columns=['mu', 'sigma', 'num_trials', 'n_iter','expected_max_sr', 'mean_max_sr','std_max_sr', 'err'])print("info:")print(output.info())print("head:")print(output.head())output.to_csv('08_DSR.csv')print("DSR.csv saved")if __name__ == '__main__':main()
跑了很久,来之不易的结果。