Coverage for cvx/simulator/utils/month.py: 100%

22 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2025-01-10 14:11 +0000

1# Copyright 2023 Stanford University Convex Optimization Group 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14# # Copyright 2023 Thomas Schmelzer 

15# # 

16# # Licensed under the Apache License, Version 2.0 (the "License"); 

17# # you may not use this file except in compliance with the License. 

18# # You may obtain a copy of the License at 

19# # 

20# # http://www.apache.org/licenses/LICENSE-2.0 

21# # 

22# # Unless required by applicable law or agreed to in writing, software 

23# # distributed under the License is distributed on an "AS IS" BASIS, 

24# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

25# # See the License for the specific language governing permissions and 

26# # limitations under the License. 

27""" 

28Popular year vs month performance table. 

29 

30Supports compounded and cumulative (i.e. fixed AUM) returns logic. 

31""" 

32 

33from __future__ import annotations 

34 

35import calendar 

36from enum import Enum 

37 

38import numpy as np 

39import pandas as pd 

40 

41 

42def _compound_returns(returns): 

43 return (1.0 + returns).prod() - 1.0 

44 

45 

46def _cumulative_returns(returns): 

47 return returns.sum() 

48 

49 

50class Aggregate(Enum): 

51 COMPOUND = _compound_returns 

52 CUMULATIVE = _cumulative_returns 

53 

54 

55def monthlytable(returns: pd.Series, f: Aggregate) -> pd.DataFrame: 

56 """ 

57 Get a table of monthly returns. 

58 

59 Args: 

60 returns: Series of individual returns. 

61 f: Aggregate function to use. 

62 

63 Returns: 

64 DataFrame with monthly returns, their STDev and YTD. 

65 """ 

66 # Works better in the first month 

67 # Compute all the intramonth-returns 

68 # instead of reapplying some monthly resampling of the NAV 

69 r = pd.Series(returns) 

70 

71 return_monthly = r.groupby([r.index.year, r.index.month]).apply(f) 

72 

73 frame = return_monthly.unstack(level=1).rename(columns=lambda x: calendar.month_abbr[x]) 

74 

75 ytd = frame.apply(f, axis=1) 

76 frame["STDev"] = np.sqrt(12) * frame.std(axis=1) 

77 # make sure that you don't include the column for the STDev in your computation 

78 frame["YTD"] = ytd 

79 frame.index.name = "Year" 

80 frame.columns.name = None 

81 # most recent years on top 

82 return frame.iloc[::-1]