"""R620:同一合成净值重算样本夏普,缺数据和零波动不填零。""" from math import sqrt, isclose, isfinite from statistics import mean, stdev, pstdev def recalc(equity, annual_sessions=252, annual_rf=0, population=False): if type(annual_sessions) is not int or annual_sessions<=0 or not isfinite(annual_rf) or annual_rf<=-1: raise ValueError('invalid annualization convention') if len(equity) < 3: return {'status': 'insufficient', 'sharpe': None} if any(x is None or not isfinite(x) or x <= 0 for x in equity): return {'status': 'invalid_or_missing', 'sharpe': None} returns = [b/a-1 for a,b in zip(equity,equity[1:])] rf = (1+annual_rf)**(1/annual_sessions)-1 excess = [r-rf for r in returns] volatility = (pstdev if population else stdev)(excess) if volatility == 0: return {'status': 'zero_volatility', 'sharpe': None} result = sqrt(annual_sessions)*mean(excess)/volatility return {'status': 'ok', 'returns': returns, 'sharpe': result} equity = [100,101,100,102,101] sample = recalc(equity) population = recalc(equity, population=True) calendar = recalc(equity, annual_sessions=365) r = sample['returns']; avg=sum(r)/len(r) manual_sd=sqrt(sum((x-avg)**2 for x in r)/(len(r)-1)) assert isclose(sample['sharpe'],sqrt(252)*avg/manual_sd,rel_tol=1e-12) assert isclose(population['sharpe']/sample['sharpe'],sqrt(4/3),rel_tol=1e-12) assert isclose(calendar['sharpe']/sample['sharpe'],sqrt(365/252),rel_tol=1e-12) assert recalc([100,100,100])['status']=='zero_volatility' assert recalc([100,101])['status']=='insufficient' assert recalc([100,None,101])['status']=='invalid_or_missing' assert isclose(101/100-1,.01,abs_tol=1e-12) print('returns='+str(r)) print('sample_252='+format(sample['sharpe'],'.8f')+' population_252='+format(population['sharpe'],'.8f')+' sample_365='+format(calendar['sharpe'],'.8f')) print('unified_formula_residual=within_1e-12 zero_vol=unavailable missing=unavailable insufficient=unavailable')