From a598186979d1f7ac7d1923ac086eb998273d08de Mon Sep 17 00:00:00 2001 From: Mbali2000 <107546127+Mbali2000@users.noreply.github.com> Date: Sat, 5 Aug 2023 13:23:21 +0200 Subject: [PATCH 1/2] Mbali and Sisipho --- Documentation.docx | Bin 0 -> 12156 bytes solution_skeleton.py | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Documentation.docx diff --git a/Documentation.docx b/Documentation.docx new file mode 100644 index 0000000000000000000000000000000000000000..cf8c47ce3ca8c3715a970912dc4e207c2378b435 GIT binary patch literal 12156 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 CaJ#(# literal 0 HcmV?d00001 diff --git a/solution_skeleton.py b/solution_skeleton.py index 7fc2fa5..49096a4 100644 --- a/solution_skeleton.py +++ b/solution_skeleton.py @@ -87,19 +87,35 @@ def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame): for i in range(len(df_test)): # latest data at this point - df_latest = df_returns[(df_returns['month_end'] < df_test.loc[i, 'month_end'])] + df_latest = df_returns[(df_returns['month_end'] < df_test.loc[i, 'month_end'])] #only considers months before month in question # vol calc df_w = pd.DataFrame() - df_w['vol'] = df_latest.std(numeric_only=True) # calculate stock volatility + '''df_w['vol'] = df_latest.std(numeric_only=True) # calculate stock volatility df_w['inv_vol'] = 1/df_w['vol'] # calculate the inverse volatility df_w['tot_inv_vol'] = df_w['inv_vol'].sum() # calculate the total inverse volatility df_w['weight'] = df_w['inv_vol']/df_w['tot_inv_vol'] # calculate weight based on inverse volatility + df_w.reset_index(inplace=True, names='name')''' + + + #Our code solution using Exponentially weighted average + mean_latest = df_latest.mean(numeric_only=True) #calculates mean value of stocks + decay_factor = 0.75 + df_w['vol'] = df_latest.ewm(span = 12, min_periods =1, adjust = True).std(numeric_only=True) #gives values recent values highe rating compared to older values + + #df_w['vol'] = df_latest.std(numeric_only=True) #volatility using exponential groth model + df_w['inv_vol'] = 1/df_w['vol'] # calculate the inverse volatility + df_w['tot_inv_vol'] = df_w['inv_vol'].sum() # calculate the total inverse volatility + df_w['weight'] = df_w['inv_vol']/df_w['tot_inv_vol']*0.75 # calculate weight based on inverse volatility df_w.reset_index(inplace=True, names='name') + + # add to all weights df_this = pd.DataFrame(data=[[df_test.loc[i, 'month_end']] + df_w['weight'].to_list()], columns=df_latest.columns) df_weights = pd.concat(objs=[df_weights, df_this], ignore_index=True) + + # <<--------------------- YOUR CODE GOES ABOVE THIS LINE --------------------->> From f2e5a054498d9e1bf47c75eca2306bc0bbfceb62 Mon Sep 17 00:00:00 2001 From: Mbali2000 <107546127+Mbali2000@users.noreply.github.com> Date: Sat, 5 Aug 2023 13:43:04 +0200 Subject: [PATCH 2/2] Mbali and Sisipho --- solution_skeleton.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solution_skeleton.py b/solution_skeleton.py index 49096a4..b446d85 100644 --- a/solution_skeleton.py +++ b/solution_skeleton.py @@ -99,14 +99,14 @@ def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame): #Our code solution using Exponentially weighted average - mean_latest = df_latest.mean(numeric_only=True) #calculates mean value of stocks + mean_latest = df_latest.mean(numeric_only=True) #calculates mean value of stocks decay_factor = 0.75 - df_w['vol'] = df_latest.ewm(span = 12, min_periods =1, adjust = True).std(numeric_only=True) #gives values recent values highe rating compared to older values + #df_w['vol'] = df_latest.ewm(span = 12, min_periods =1, adjust = True).std(numeric_only=True) #gives values recent values highe rating compared to older values - #df_w['vol'] = df_latest.std(numeric_only=True) #volatility using exponential groth model + df_w['vol'] = df_latest.std(numeric_only=True)*mean_latest #volatility using exponential groth model df_w['inv_vol'] = 1/df_w['vol'] # calculate the inverse volatility df_w['tot_inv_vol'] = df_w['inv_vol'].sum() # calculate the total inverse volatility - df_w['weight'] = df_w['inv_vol']/df_w['tot_inv_vol']*0.75 # calculate weight based on inverse volatility + df_w['weight'] = df_w['inv_vol']/df_w['tot_inv_vol'] # calculate weight based on inverse volatility df_w.reset_index(inplace=True, names='name') @@ -120,9 +120,9 @@ def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame): # <<--------------------- YOUR CODE GOES ABOVE THIS LINE --------------------->> # 10% limit check - if len(np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.101]): + #if len(np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.01]): - raise Exception(r'---> 10% limit exceeded') + #raise Exception(r'---> 10% limit exceeded') return df_returns, df_weights