Skip to content

Commit

Permalink
Revert "Vectorized operations"
Browse files Browse the repository at this point in the history
This reverts commit 72c609a.
  • Loading branch information
silvavn committed Sep 11, 2020
1 parent 72c609a commit b09e227
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 187 deletions.
71 changes: 31 additions & 40 deletions backtester.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ class BackTester:
"""
Backtester module that does both backward and forward testing for our portfolios.
"""

def __init__(self):
print("\n--# Backtester has been initialized")

def price_delta(self, prices):
def calculate_percentage_change(self, old, new):
"""
Percentage change
"""

return ((prices - prices.shift()) * 100 / prices.shift())[1:]
return ((new - old) * 100) / old

def portfolio_weight_manager(self, weight, is_long_only):
"""
Expand All @@ -48,80 +46,73 @@ def back_test(self, symbol_names, portfolio_weights_dictionary, portfolio_data_d
"""

# Get market returns during the backtesting time
historical_prices = historical_price_market["Close"]
market_returns = self.price_delta(historical_prices)
historical_price_market = list(historical_price_market["Close"])
market_returns = [self.calculate_percentage_change(historical_price_market[i - 1], historical_price_market[i]) for i in range(1, len(historical_price_market))]
market_returns_cumulative = np.cumsum(market_returns)

# Get invidiual returns for each stock in our portfolio
normal_returns_matrix = []
for symbol in symbol_names:
symbol_historical_prices = portfolio_data_dictionary[symbol]["historical"]["Close"]
symbol_historical_returns = self.price_delta(
symbol_historical_prices)
symbol_historical_prices = list(portfolio_data_dictionary[symbol]["historical_prices"]["Close"])
symbol_historical_returns = [self.calculate_percentage_change(symbol_historical_prices[i - 1], symbol_historical_prices[i]) for i in range(1, len(symbol_historical_prices))]
normal_returns_matrix.append(symbol_historical_returns)

# Get portfolio returns
normal_returns_matrix = np.array(normal_returns_matrix).transpose()
portfolio_weights_vector = np.array([self.portfolio_weight_manager(
portfolio_weights_dictionary[symbol], is_long_only) for symbol in portfolio_weights_dictionary]).transpose()
portfolio_returns = np.dot(
normal_returns_matrix, portfolio_weights_vector)
portfolio_weights_vector = np.array([self.portfolio_weight_manager(portfolio_weights_dictionary[symbol], is_long_only) for symbol in portfolio_weights_dictionary]).transpose()
portfolio_returns = np.dot(normal_returns_matrix, portfolio_weights_vector)
portfolio_returns_cumulative = np.cumsum(portfolio_returns)

# Plot returns
x = np.arange(len(portfolio_returns_cumulative))
plt.plot(x, portfolio_returns_cumulative,
linewidth=2.0, label=strategy_name)
plt.axhline(y=0, linestyle='dotted', alpha=0.3, color='black')
plt.plot(x, portfolio_returns_cumulative, linewidth = 2.0, label = strategy_name)
plt.axhline(y = 0, linestyle = 'dotted', alpha = 0.3, color = 'black')
if market_chart:
x = np.arange(len(market_returns_cumulative))
plt.plot(x, market_returns_cumulative, linewidth=2.0,
color='#282828', label='Market Index', linestyle='--')
plt.plot(x, market_returns_cumulative, linewidth = 2.0, color = '#282828', label = 'Market Index', linestyle = '--')

# Plotting styles
plt.title("Backtest Results", fontsize=14)
plt.xlabel("Bars (Time Sorted)", fontsize=14)
plt.ylabel("Cumulative Percentage Return", fontsize=14)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.title("Backtest Results", fontsize = 14)
plt.xlabel("Bars (Time Sorted)", fontsize = 14)
plt.ylabel("Cumulative Percentage Return", fontsize = 14)
plt.xticks(fontsize = 14)
plt.yticks(fontsize = 14)

def future_test(self, symbol_names, portfolio_weights_dictionary, portfolio_data_dictionary, future_price_market, is_long_only, market_chart, strategy_name):
"""
Main future test function. If future data is available i.e is_test is set to 1 and future_bars set to > 0, this takes in the portfolio weights and compares the portfolio returns with a market index of your choice in the future.
"""

# Get future prices
market_returns = self.price_delta(future_price_market["Close"])
print(future_price_market)
future_price_market = [item[4] for item in list(future_price_market)]
market_returns = [self.calculate_percentage_change(future_price_market[i - 1], future_price_market[i]) for i in range(1, len(future_price_market))]
market_returns_cumulative = np.cumsum(market_returns)

# Get invidiual returns for each stock in our portfolio
normal_returns_matrix = []
for symbol in symbol_names:
symbol_historical_prices = portfolio_data_dictionary[symbol]["future"]["Close"]
symbol_historical_returns = self.price_delta(symbol_historical_prices)
symbol_historical_prices = [item[4] for item in list(portfolio_data_dictionary[symbol]["future_prices"])]
symbol_historical_returns = [self.calculate_percentage_change(symbol_historical_prices[i - 1], symbol_historical_prices[i]) for i in range(1, len(symbol_historical_prices))]
normal_returns_matrix.append(symbol_historical_returns)

# Get portfolio returns
normal_returns_matrix = np.array(normal_returns_matrix).transpose()
portfolio_weights_vector = np.array([self.portfolio_weight_manager(
portfolio_weights_dictionary[symbol], is_long_only) for symbol in portfolio_weights_dictionary]).transpose()
portfolio_returns = np.dot(
normal_returns_matrix, portfolio_weights_vector)
portfolio_weights_vector = np.array([self.portfolio_weight_manager(portfolio_weights_dictionary[symbol], is_long_only) for symbol in portfolio_weights_dictionary]).transpose()
portfolio_returns = np.dot(normal_returns_matrix, portfolio_weights_vector)
portfolio_returns_cumulative = np.cumsum(portfolio_returns)

# Plot
x = np.arange(len(portfolio_returns_cumulative))
plt.axhline(y=0, linestyle='dotted', alpha=0.3, color='black')
plt.plot(x, portfolio_returns_cumulative,
linewidth=2.0, label=strategy_name)
plt.axhline(y = 0, linestyle = 'dotted', alpha = 0.3, color = 'black')
plt.plot(x, portfolio_returns_cumulative, linewidth = 2.0, label = strategy_name)
if market_chart:
x = np.arange(len(market_returns_cumulative))
plt.plot(x, market_returns_cumulative, linewidth=2.0,
color='#282828', label='Market Index', linestyle='--')
plt.plot(x, market_returns_cumulative, linewidth = 2.0, color = '#282828', label = 'Market Index', linestyle = '--')

# Plotting styles
plt.title("Future Test Results", fontsize=14)
plt.xlabel("Bars (Time Sorted)", fontsize=14)
plt.ylabel("Cumulative Percentage Return", fontsize=14)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.title("Future Test Results", fontsize = 14)
plt.xlabel("Bars (Time Sorted)", fontsize = 14)
plt.ylabel("Cumulative Percentage Return", fontsize = 14)
plt.xticks(fontsize = 14)
plt.yticks(fontsize = 14)
36 changes: 16 additions & 20 deletions eiten.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

class Eiten:
def __init__(self, args):

plt.style.use('seaborn-white')
plt.rc('grid', linestyle="dotted", color='#a0a0a0')
plt.rcParams['axes.edgecolor'] = "#04383F"
plt.rcParams['figure.figsize'] = (12, 6)

print("\n--* Eiten has been initialized...")
self.args = args
Expand All @@ -33,11 +36,11 @@ def __init__(self, args):

print('\n')

def price_delta(self, prices):
def calculate_percentage_change(self, old, new):
"""
Calculate percentage change
"""
return ((prices - prices.shift()) * 100 / prices.shift())[1:]
return ((new - old) * 100) / old

def create_returns(self, historical_price_info):
"""
Expand All @@ -48,16 +51,18 @@ def create_returns(self, historical_price_info):
returns_matrix = []
returns_matrix_percentages = []
predicted_return_vectors = []

for i in range(0, len(historical_price_info)):
close_prices = historical_price_info[i]["Close"]
log_returns = np.log((close_prices / close_prices.shift())[1:])
percentage_returns = self.price_delta(close_prices)
close_prices = list(historical_price_info[i]["Close"])
log_returns = [math.log(close_prices[i] / close_prices[i - 1])
for i in range(1, len(close_prices))]
percentage_returns = [self.calculate_percentage_change(
close_prices[i - 1], close_prices[i]) for i in range(1, len(close_prices))]

total_data = close_prices.shape[0]
total_data = len(close_prices)

# Expected returns in future. We can either use historical returns as future returns on try to simulate future returns and take the mean. For simulation, you can modify the functions in simulator to use here.
future_expected_returns = np.mean((self.price_delta(close_prices)) / (total_data - i)) # More focus on recent returns
future_expected_returns = np.mean([(self.calculate_percentage_change(close_prices[i - 1], close_prices[i])) / (
total_data - i) for i in range(1, len(close_prices))]) # More focus on recent returns

# Add to matrices
returns_matrix.append(log_returns)
Expand Down Expand Up @@ -87,8 +92,8 @@ def load_data(self):
historical_price_info, future_prices = [], []
for symbol in symbol_names:
historical_price_info.append(
self.data_dictionary[symbol]["historical"])
future_prices.append(self.data_dictionary[symbol]["future"])
self.data_dictionary[symbol]["historical_prices"])
future_prices.append(self.data_dictionary[symbol]["future_prices"])

# Get return matrices and vectors
predicted_return_vectors, returns_matrix, returns_matrix_percentages = self.create_returns(
Expand Down Expand Up @@ -233,10 +238,6 @@ def draw_plot(self, filename="output/graph.png"):
Draw plots
"""
# Styling for plots
plt.style.use('seaborn-white')
plt.rc('grid', linestyle="dotted", color='#a0a0a0')
plt.rcParams['axes.edgecolor'] = "#04383F"
plt.rcParams['figure.figsize'] = (12, 6)

plt.grid()
plt.legend(fontsize=14)
Expand All @@ -247,11 +248,6 @@ def draw_plot(self, filename="output/graph.png"):
plt.show()

def print_and_plot_portfolio_weights(self, weights_dictionary: dict, strategy, plot_num: int) -> None:
plt.style.use('seaborn-white')
plt.rc('grid', linestyle="dotted", color='#a0a0a0')
plt.rcParams['axes.edgecolor'] = "#04383F"
plt.rcParams['figure.figsize'] = (12, 6)

print("\n-------- Weights for %s --------" % strategy)
symbols = list(sorted(weights_dictionary.keys()))
symbol_weights = []
Expand Down
Loading

0 comments on commit b09e227

Please sign in to comment.