Skip to content

Commit

Permalink
Working backtester with comparison to equally-weighted portfolio.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sinbad-The-Sailor committed Feb 24, 2024
1 parent ae02ccc commit 0fc7741
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 11 deletions.
30 changes: 26 additions & 4 deletions backtest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
import time

import numpy as np
import pandas as pd

from matplotlib import pyplot as plt

from tests.test_config import TEST_YAHOO_STOCK_UNIVERSE_16, TEST_YAHOO_STOCK_UNIVERSE_8, TEST_YAHOO_STOCK_UNIVERSE_4
from src.abacus.utils.portfolio import Portfolio
from src.abacus.utils.universe import Universe
Expand All @@ -12,7 +16,8 @@
# Backtesting setup.
instrument_specification = {}
inital_weights = {}
wealth = []
wealth = [100]
wealth_n = [100]
number_of_start_assets = 5
for i, ticker in enumerate(sorted(TEST_YAHOO_STOCK_UNIVERSE_8)):
file = f"tests/data/{ticker}.csv"
Expand All @@ -24,7 +29,7 @@

# Date range for backtesting.
start_date = "2020-01-02"
end_date = "2020-01-05" # "2023-05-31"
end_date = "2020-05-02" # "2023-05-31"
date_range = pd.date_range(start=start_date, end=end_date, freq='B')
solutions = {"2020-01-01": inital_weights}
times = {}
Expand All @@ -34,15 +39,32 @@
universe.date_today = date
simulator = Simulator(universe)
simulator.calibrate()
simulator.run_simulation(time_steps=10, number_of_simulations=1_000)
optimizer = MPCMaximumReturn(universe, portfolio, simulator.return_tensor, gamma=2, l1_penalty=0, l2_penalty=0.15,
simulator.run_simulation(time_steps=5, number_of_simulations=1000)
optimizer = MPCMaximumReturn(universe, portfolio, simulator.return_tensor, gamma=2, l1_penalty=0, l2_penalty=0.02,
covariance_matrix=simulator.covariance_matrix)
optimizer.solve()
solution = optimizer.solution
times[date] = time.time() - t1
portfolio.weights = solution
solutions[date] = solution

universe_returns = universe.todays_returns
portfolio_weights = np.array(list(solution.values()))
equal_weights = (1/8) * np.ones(8)
portfolio_return = np.dot(universe_returns, portfolio_weights)
equal_return = np.dot(universe_returns, equal_weights)
wealth.append(wealth[-1] * (1 + portfolio_return))
wealth_n.append(wealth_n[-1] * (1 + equal_return))

dates = ["2024-01-01"]
for date in date_range:
dates.append(str(date)[0:10])

np.savetxt('data.csv', np.array(wealth), delimiter=',')

plt.plot(dates, wealth)
plt.plot(dates, wealth_n)
plt.show()

print('\n' * 10)
for date, solution in solutions.items():
Expand Down
4 changes: 2 additions & 2 deletions src/abacus/legacy/leg_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from utils.stock_factory import StockFactory
from utils.data_handler import YahooDataHandler
from utils.portfolio import Portfolio
from utils.risk_assessor import RiskAssessor
from abacus.assessor.risk_assessor import RiskAssessor
from simulator.simulator import Simulator
from optimizer.optimizer import Optimizer
from abacus.optimizer.leg_optimizer import Optimizer
from optimizer.enums import OptimizationModels


Expand Down
5 changes: 1 addition & 4 deletions src/abacus/optimizer/leg_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ def _set_ampl_data(self):
tensor_size = price_tensor.shape
number_of_assets = tensor_size[0]
number_of_scenarios = tensor_size[1]

price_dict = {(j+1, asset.identifier): price_tensor[asset.id][j] for asset in assets
for j in range(number_of_scenarios)}

price_dict = {(j+1, asset.identifier): price_tensor[asset.id][j] for asset in assets for j in range(number_of_scenarios)}
self._ampl.get_set("assets").set_values(asset_identifiers)
self._ampl.param["gamma"] = -24
self._ampl.param["risk_free_rate"] = 0.04
Expand Down
2 changes: 1 addition & 1 deletion src/abacus/utils/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def log_returns(self) -> pd.DataFrame:

@property
def art_returns(self) -> pd.DataFrame:
return self.price_history.pct_change()[1:]
return np.array(self.price_history.pct_change())[1:]

@property
def log_returns_tensor(self) -> torch.Tensor:
Expand Down
5 changes: 5 additions & 0 deletions src/abacus/utils/universe.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import numpy as np

from pandas import DataFrame
from datetime import date
Expand Down Expand Up @@ -38,6 +39,10 @@ def instruments(self) -> list[Instrument]:
built_instruments.append(ins)
return built_instruments

@property
def todays_returns(self):
return np.array([instrument.art_returns[-1] for instrument in self.instruments]).flatten()

def has_updated_cache(self) -> bool:
has_cache = self._instruments is not None
has_last_build = self._instrument_build_date is not None
Expand Down

0 comments on commit 0fc7741

Please sign in to comment.