def optimization(weight_scheme): numberofday = 0 quarter_list = [] # Initialize matrix full of zeros resultMatrix = [[0 for x in range(len(ticker) + 5)] for y in range(len(timestamp) + 1)] # Change the first row of result matrix to show headers firstrow = resultMatrix[0] secondrow = resultMatrix[1] for i0 in range(len(firstrow)): if i0 == 0: firstrow[i0] = "" elif i0 < len(ticker) + 1: firstrow[i0] = ticker[i0 - 1] elif i0 == len(ticker) + 1: firstrow[i0] = "Daily Return" elif i0 == len(ticker) + 2: firstrow[i0] = "Cumulative" elif i0 == len(ticker) + 3: firstrow[i0] = "Stock Count" elif i0 == len(ticker) + 4: firstrow[i0] = "Portfolio" secondrow[i0] = initial_amount # Change the first column of result matrix to show time index for row in range(len(resultMatrix)): if row == 0: resultMatrix[row][0] = "" else: resultMatrix[row][0] = timestamp[row - 1] resultMatrix = np.array(resultMatrix) column_return = np.array(resultMatrix[:, -1][1:]) # Portfolio column_return = np.asfarray(column_return, float) column_return[0] = initial_amount # Loop through time index cash_amount = 0 for index in range(len(timestamp)): bool_quarter = False stockcount = 0 answer = 0 # search for index for weights month = int(timestamp[index].split("/")[1]) year = int(timestamp[index].split("/")[2]) if month < 7: quarter = "Q2" else: quarter = "Q4" current = str(year) + quarter # Q-2 quarter if month < 4: year -= 1 quarter = "Q2" elif month < 7: year -= 1 quarter = "Q4" elif month < 10: year -= 1 quarter = "Q4" else: quarter = "Q2" date = str(year) + quarter # Check if quarter is different from previous day's quarter quarter_list.append(current) if index == 0: store_index.append([index, current]) else: if quarter_list[index] != quarter_list[index - 1]: store_index.append([index, current]) if (index == 0) or (index != 0 and quarter_list[index] != quarter_list[index - 1]): bool_quarter = True # Search for index for weights for index2 in range(len(weight_scheme)): if date == weight_scheme[index2][0]: answer = index2 # Loop through stocks aggregate = 0 cash_hand = 100 for stock in range(len(ticker)): gain = functions.percentageChange( float(price[index - 1][stock + 1]), float(price[index][stock + 1])) if answer == 0: stockweight = 0 else: w = float(weight_scheme[answer][stock + 1]) stockweight = w / 100 if bool_quarter: # When quarter changes if index == 0: value = initial_amount * stockweight else: value = column_return[index - 1] * stockweight cash_hand -= w else: # When quarter does not change value = float( resultMatrix[index][stock + 1]) * (1 + gain / 100) resultMatrix[index + 1][ stock + 1] = value # Fill in the money allocation instead of percentage change aggregate += value # Calculate number of stocks to be invested if stockweight != 0 and float(price[index][stock + 1]) != 0: stockcount += 1 # Calculate cash in hand when remaining weight is not zero if bool_quarter and cash_hand < 100: cash_amount = cash_hand * column_return[index - 1] / 100 if bool_quarter and cash_hand == 100: cash_amount = 0 if aggregate == 0: aggregate = column_return[index - 1] if column_return[index - 1] == 0 or index == 0: aggregate = initial_amount aggregate += cash_amount column_return[index] = aggregate # Stock Count resultMatrix[index + 1][len(ticker) + 3] = stockcount numberofday += 1 resultMatrix[:, -1][1:] = column_return daily_return = functions.percentagelist(column_return) resultMatrix[:, -4][2:] = daily_return cumulative = functions.cumulative_list(daily_return) resultMatrix[:, -3][2:] = cumulative portfolio_list = column_return # Take the last index to get cumulative_return cumulative_return = cumulative[-1] # Final cumulative return list_cumulative.append(cumulative_return) # Calculate related stats sharpe_ratio = sharpe(daily_return) list_sharpe.append(sharpe_ratio) print(numberofday, "days;", round(cumulative_return, 4), "%, Sharpe = ", round(sharpe_ratio, 4)) return column_return
def trend_following(weight_scheme, number): quarter_list = [] # Weight Scheme 1: Third Last Column # Weight Scheme 2: Second Last Column # Weight Optimized: Last Column column_return = np.array(result_matrix[:, number - 4][1:]) column_return = np.asfarray(column_return, float) column_return[0] = initial_amount # Loop through time index cash_amount = 0 for index in range(len(timestamp)): bool_quarter = False answer = 0 # search for index for weights month = int(timestamp[index].split("/")[1]) year = int(timestamp[index].split("/")[2]) if month < 7: quarter = "Q2" else: quarter = "Q4" current = str(year) + quarter # Q-2 quarter if month < 4: year -= 1 quarter = "Q2" elif month < 7: year -= 1 quarter = "Q4" elif month < 10: year -= 1 quarter = "Q4" else: quarter = "Q2" date = str(year) + quarter # Check if quarter is different from previous day's quarter quarter_list.append(current) if number == 1: if index == 0: store_index.append([index, current]) else: if quarter_list[index] != quarter_list[index - 1]: store_index.append([index, current]) if (index == 0) or (index != 0 and quarter_list[index] != quarter_list[index - 1]): bool_quarter = True # Search for index for weights for index2 in range(len(weight_scheme)): if date == weight_scheme[index2][0]: answer = index2 # Loop through stocks aggregate = 0 cash_hand = 100 if number == 1: w_return = w1_matrix elif number == 2: w_return = w2_matrix else: w_return = w3_matrix for stock in range(len(tickers)): # Import results after market timing gain = float(w_return[index + 1][stock + 1]) if answer == 0: stockweight = 0 else: w = float(weight_scheme[answer][stock + 1]) stockweight = w / 100 if bool_quarter: # When quarter changes, change the initial amount and re-balance if index == 0: value = initial_amount * stockweight else: value = column_return[index - 1] * stockweight cash_hand -= w else: # When quarter doesn't change value = float( result_matrix1[index][stock + 1]) * (1 + gain / 100) result_matrix1[index + 1][ stock + 1] = value # Fill in the money allocation instead of percentage change aggregate += value # Calculate cash in hand when remaining weight is not zero if bool_quarter and cash_hand < 100: cash_amount = cash_hand * column_return[index - 1] / 100 if bool_quarter and cash_hand == 100: cash_amount = 0 if aggregate == 0: aggregate = column_return[index - 1] if column_return[index - 1] == 0 or index == 0: aggregate = initial_amount aggregate += cash_amount column_return[index] = aggregate result_matrix1[:, -2][1:] = column_return # Portfolio list_return = functions.percentagelist(column_return) result_matrix1[:, -1][2:] = list_return # Daily Return cumulative = functions.cumulative_list(list_return) result_matrix[:, number - 4][2:] = cumulative # Market Timing Strategy.csv if number == 1: # Write csv file of result matrix inside result folder with open(directory + 'Combined Strategy 1.csv', "w") as output: writer = csv.writer(output, lineterminator='\n') for val in result_matrix1: writer.writerow(val) elif number == 2: # Write csv file of result matrix inside result folder with open(directory + 'Combined Strategy 2.csv', "w") as output: writer = csv.writer(output, lineterminator='\n') for val in result_matrix1: writer.writerow(val) else: # Write csv file of result matrix inside result folder with open(directory + 'Combined Strategy Optimized Weight.csv', "w") as output: writer = csv.writer(output, lineterminator='\n') for val in result_matrix1: writer.writerow(val)
def backtest(weight_scheme, number): numberofday = 0 quarter_list = [] # Initialize matrix full of zeros resultMatrix = [[0 for x in range(len(ticker) + 5)] for y in range(len(timestamp) + 1)] # Change the first row of result matrix to show headers firstrow = resultMatrix[0] secondrow = resultMatrix[1] for i0 in range(len(firstrow)): if i0 == 0: firstrow[i0] = "" elif i0 < len(ticker) + 1: firstrow[i0] = ticker[i0 - 1] elif i0 == len(ticker) + 1: firstrow[i0] = "Daily Return" elif i0 == len(ticker) + 2: firstrow[i0] = "Cumulative" elif i0 == len(ticker) + 3: firstrow[i0] = "Stock Count" elif i0 == len(ticker) + 4: firstrow[i0] = "Portfolio" secondrow[i0] = initial_amount # Change the first column of result matrix to show time index for row in range(len(resultMatrix)): if row == 0: resultMatrix[row][0] = "" else: resultMatrix[row][0] = timestamp[row - 1] resultMatrix = np.array(resultMatrix) column_return = np.array(resultMatrix[:, -1][1:]) # Portfolio column_return = np.asfarray(column_return, float) column_return[0] = initial_amount # Loop through time index for index in range(len(timestamp)): bool_quarter = False stockcount = 0 answer = 0 # search for index for weights month = int(timestamp[index].split("/")[1]) year = int(timestamp[index].split("/")[2]) if month < 7: quarter = "Q2" else: quarter = "Q4" current = str(year) + quarter # Q-2 quarter if month < 4: year -= 1 quarter = "Q2" elif month < 7: year -= 1 quarter = "Q4" elif month < 10: year -= 1 quarter = "Q4" else: quarter = "Q2" date = str(year) + quarter # Check if quarter is different from previous day's quarter quarter_list.append(current) if number == 1: if index == 0: store_index.append([index, current]) else: if quarter_list[index] != quarter_list[index - 1]: store_index.append([index, current]) if (index == 0) or (index != 0 and quarter_list[index] != quarter_list[index - 1]): bool_quarter = True # Search for index for weights for index2 in range(len(weight_scheme)): if date == weight_scheme[index2][0]: answer = index2 # Loop through stocks aggregate = 0 for stock in range(len(ticker)): gain = functions.percentageChange( float(price[index - 1][stock + 1]), float(price[index][stock + 1])) if answer == 0: stockweight = 0 else: stockweight = float(weight_scheme[answer][stock + 1]) / 100 if bool_quarter: # When quarter changes if index == 0: value = initial_amount * stockweight else: value = column_return[index - 1] * stockweight else: # When quarter does not change value = float( resultMatrix[index][stock + 1]) * (1 + gain / 100) resultMatrix[index + 1][ stock + 1] = value # Fill in the money allocation instead of percentage change aggregate += value # Calculate number of stocks to be invested if stockweight != 0 and float(price[index][stock + 1]) != 0: stockcount += 1 if aggregate == 0: aggregate = column_return[index - 1] if column_return[index - 1] == 0 or index == 0: aggregate = initial_amount column_return[index] = aggregate # Stock Count resultMatrix[index + 1][len(ticker) + 3] = stockcount numberofday += 1 resultMatrix[:, -1][1:] = column_return daily_return = functions.percentagelist(column_return) resultMatrix[:, -4][2:] = daily_return cumulative = functions.cumulative_list(daily_return) resultMatrix[:, -3][2:] = cumulative portfolio_list = column_return # Take the last index to get cumulative_return cumulative_return = cumulative[-1] # Final cumulative return # Calculate related stats head = "Weight Scheme " + str(number) print(head, ":") print(numberofday, "days;", round(cumulative_return, 4), "%") print("\n") print("Average Daily Return =", round(average(daily_return), 4), "%") print("SD of Daily Return =", round(SD(daily_return), 4), "%") annual_return = average(daily_return) * oneyear print("Annualized Return =", round(annual_return, 4), "%") annual_volatility = SD(daily_return) * (oneyear**(1 / 2)) print("Annualized Volatility =", round(annual_volatility, 4), "%") sharpe_ratio = sharpe(daily_return) print("Annual Sharpe Ratio: ", round(sharpe_ratio, 4)) print("Max Consecutive Loss = ", maxconsecutive(daily_return), "days") print("Win Rate:", round(winrate(daily_return), 4), "%") max_drawdown = functions.findMin(daily_return) print("Max Drawdown:", round(max_drawdown, 4), "%") print("\n") stats_line = [ head, cumulative_return, annual_return, annual_volatility, sharpe_ratio, max_drawdown ] stats_matrix.append(stats_line) if number == 2: # Calculate stats for market index daily_return_index = functions.percentagelist(price_index) cumulative_index = functions.percentageChange(price_index[0], price_index[-1]) print(market, "Index: ") print("Cumulative =", round(cumulative_index, 4), "%") print("Average Daily Return =", round(average(daily_return_index), 4), "%") print("SD of Daily Return =", round(SD(daily_return_index), 4), "%") annual_return = average(daily_return_index) * oneyear print("Annualized Return =", round(annual_return, 4), "%") annual_volatility = SD(daily_return_index) * (oneyear**(1 / 2)) print("Annualized Volatility =", round(annual_volatility, 4), "%") sharpe_ratio = sharpe(daily_return_index) print("Annual Sharpe Ratio: ", round(sharpe_ratio, 4)) print("Max Consecutive Loss = ", maxconsecutive(daily_return_index), "days") print("Win Rate:", round(winrate(daily_return_index), 4), "%") max_drawdown = functions.findMin(daily_return) print("Max Drawdown:", round(max_drawdown, 4), "%") stats_line = [ market, cumulative_index, annual_return, annual_volatility, sharpe_ratio, max_drawdown ] stats_matrix.append(stats_line) # Find correct date to match dates for market index and our portfolio correctdate = [] correctdate2 = [] for i in range(len(timestamp)): for j in range(len(date_index)): if date_index[j] == timestamp[i]: correctdate.append(i) correctdate2.append(j) # Prepare for a graph x_axis = date_index y = [] # Strategy Portfolio y_index = [] # Market Index Portfolio # Normalize to initial amount and fill up values for y-axis by searching for correct dates relative_portfolio = functions.relative(portfolio_list) for i in range(len(correctdate)): correctindex = correctdate[i] - 1 y.append(relative_portfolio[correctindex]) for j in range(len(correctdate2)): correctindex = correctdate2[j] y_index.append(price_index[correctindex]) y_index = functions.relative(y_index) # Plot a graph fig = plt.figure() # Create a figure ax = plt.axes() # Create axis if len(x_axis) == len(y): plt.plot(x_axis, y, label='Weight Scheme ' + str(number)) plt.plot(x_axis, y_index, label=market) ax.xaxis.set_major_locator( plt.MaxNLocator(5)) # Set Maximum number of x-axis values to show fig.autofmt_xdate() # Rotate values to see more clearly title = "Stock Selection: Growth of " + str( initial_amount / 1000000) + " million" plt.title(title) plt.ylabel("Cumulative Return") fig.savefig(directory + market + " Stock Selection Weight Scheme " + str(number) + ".png") plt.show() # Write csv file of result matrix inside result folder title = directory + 'weight scheme ' + str(number) with open(title + ' result.csv', "w") as output: writer = csv.writer(output, lineterminator='\n') for val in resultMatrix: writer.writerow(val)
y.append(portfolio_pure[correctindex]) strategy1.append(portfolio_weight1[correctindex]) strategy2.append(portfolio_weight2[correctindex]) strategy3.append(portfolio_weight_optimized[correctindex]) for j in range(len(correctdate2)): correctindex = correctdate2[j] y_index.append(price_index[correctindex]) x_axis.append(date_index[correctindex]) title_stats = [ "Pure Market Trending", "Weight Scheme 1", "Weight Scheme 2", 'Weight Optimized', market ] stats = [y, strategy1, strategy2, strategy3, y_index] for count in range(len(stats)): calculate = functions.percentagelist(stats[count]) cumulative_return = functions.percentageChange(stats[count][0], stats[count][-1]) annualized_return = average(calculate) * 252 annuzlied_volatility = SD(calculate) * (252**(1 / 2)) sharpe_ratio = sharpe(calculate) max_drawdown = functions.findMin(calculate) print(title_stats[count]) print("Cumulative Return:", round(cumulative_return, 4), "%") print("Annualized Return:", round(annualized_return, 4), "%") print("Annualized Volatility:", round(annuzlied_volatility, 4), "%") print("Sharpe Ratio:", round(sharpe_ratio, 4)) print("Max Drawdown:", round(max_drawdown, 4), "%") print("\n") stats_line = [ title_stats[count], cumulative_return, annualized_return,
# Calculate related stats print(numberofday, "days;", round(cumulative_return, 4), "%") print("\n") print("Average Daily Return =", round(average(daily_return), 4), "%") print("SD of Daily Return =", round(SD(daily_return), 4), "%") print("Annualized Return =", round(average(daily_return) * oneyear, 4), "%") print("Annualized Volatility =", round(SD(daily_return) * (oneyear**(1 / 2)), 4), "%") print("Annual Sharpe Ratio: ", round(sharpe(daily_return), 4)) print("Max Consecutive Loss = ", maxconsecutive(daily_return), "days") print("Win Rate:", round(winrate(daily_return), 4), "%") print("Max Drawdown:", round(functions.findMin(daily_return), 4), "%") print("\n") # Calculate stats for market index daily_return_index = functions.percentagelist(price_index) cumulative_index = functions.percentageChange(price_index[0], price_index[-1]) print(market, "Index: ") print("Cumulative =", round(cumulative_index, 4), "%") print("Average Daily Return =", round(average(daily_return_index), 4), "%") print("SD of Daily Return =", round(SD(daily_return_index), 4), "%") print("Annualized Return =", round(average(daily_return_index) * oneyear, 4), "%") print("Annualized Volatility =", round(SD(daily_return_index) * (oneyear**(1 / 2)), 4), "%") print("Annual Sharpe Ratio: ", round(sharpe(daily_return_index), 4)) print("Max Consecutive Loss = ", maxconsecutive(daily_return_index), "days") print("Win Rate:", round(winrate(daily_return_index), 4), "%") print("Max Drawdown:", round(functions.findMin(daily_return_index), 4), "%") # Find correct date to match dates for market index and our portfolio