From eee34509a76818dc73810366e7fd6868ebef8976 Mon Sep 17 00:00:00 2001 From: Katlego-Sekoele Date: Sat, 5 Aug 2023 12:01:01 +0200 Subject: [PATCH 1/2] Create .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9b4ad4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +*.png +.idea \ No newline at end of file From 205d76d213399f3cb9bc45ddd1ac687379e4d610 Mon Sep 17 00:00:00 2001 From: Katlego-Sekoele Date: Sat, 5 Aug 2023 13:54:10 +0200 Subject: [PATCH 2/2] Update solution_skeleton.py --- solution_skeleton.py | 111 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 14 deletions(-) diff --git a/solution_skeleton.py b/solution_skeleton.py index 7fc2fa5..ae11b2b 100644 --- a/solution_skeleton.py +++ b/solution_skeleton.py @@ -76,6 +76,9 @@ def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame): # <<--------------------- YOUR CODE GOES BELOW THIS LINE --------------------->> + #EXPLANATION + #https://maesela.notion.site/Prescient-48a940d3bff4497db8512468dbe7bc18?pvs=4 + # This is your playground. Delete/modify any of the code here and replace with # your methodology. Below we provide a simple, naive estimation to illustrate # how we think you should go about structuring your submission and your comments: @@ -83,23 +86,103 @@ def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame): # We use a static Inverse Volatility Weighting (https://en.wikipedia.org/wiki/Inverse-variance_weighting) # strategy to generate portfolio weights. # Use the latest available data at that point in time + + # Define the column names + columns = list_stocks + + # Create the empty DataFrame with specified columns + df_stock_accelerations = {key: [] for key in list_stocks} + count_a = 0 + for stock_iterator in range(len(list_stocks)): + + # stock k's returns + # k = stock_iterator + rk = df_returns[list_stocks[stock_iterator]] + + # ema = exponential moving average return + # alpha = smoothing factor + def ema(returns_k, previous_ema): + alpha = 0.2 + return (alpha * returns_k) + ( (1-alpha) * previous_ema ) + + ema_last_month = 0 + + for date_iterator in range(2, len(df_returns)): + # stock k's returns in month t-1 + # t = date_iterator + + rkt = rk[date_iterator-1] + + # change in exponential moving average + delta_w = ema (rkt, ema_last_month) - ema_last_month + + # acceleration at month t + beta = 15 # must be > 0 and a whole number. Beta is the time period + a_t = delta_w / beta + count_a += 1 + print(count_a) + + # append the acceleration + df_stock_accelerations[list_stocks[stock_iterator]].append(a_t) + + + # print(df_stock_accelerations) + num_accs = len(df_stock_accelerations[list_stocks[0]]) + for row in range(num_accs): + accelerations = {stock: df_stock_accelerations[stock][row] if df_stock_accelerations[stock] else None for stock in list_stocks} + + raw_weights = {key: 0 for key in list_stocks} + + max_acceleration_key = max(accelerations, key=accelerations.get) + + for key, single_acc in accelerations.items(): + if single_acc < 0: + raw_weights[key] = 0 + else: + raw_weight_k = 0.1 if (accelerations[key] / accelerations[max_acceleration_key] ) > 0.1 else (accelerations[key] / accelerations[max_acceleration_key] ) + raw_weights[key] = raw_weight_k + + + sum_raw_weights = sum(raw_weights.values()) + print("sum of raw weights", raw_weights) + weights = {key: 0 for key in list_stocks} + for key, value in raw_weights.items(): + weights[key] = value / sum_raw_weights + + + + print(weights) + df_weights = pd.DataFrame(columns=list_stocks) + + # Convert the dictionary to a DataFrame + new_row_df = pd.DataFrame([weights]) + + # Add the new row using the `loc` indexer + df_weights = pd.concat([df_weights, new_row_df], ignore_index=True) + + # df_weights = df_weights.append(weights, ignore_index=True) + + # 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) - for i in range(len(df_test)): + # # delete this loop + # 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'])] + # # latest data at this point + # df_latest = df_returns[(df_returns['month_end'] < df_test.loc[i, 'month_end'])] - # vol calc - df_w = pd.DataFrame() - 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') - - # 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) + # # vol calc + # df_w = pd.DataFrame() + # 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') + + # # 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 --------------------->>