market-tracker creates a portfolio of 10 to 25 stocks, from a larger pool, that is intended to mimic a benchmark index.
Approach taken is to use the previous years data and run a greedy algorithm that minimize the tracking error with respect to the porfolio weights using SciPy optimize.
The tracking error is measured as follows:
The greedy algorithm functions as follows:
Two are included due to constrainsts so we start with those two and determine the next stock to add by minimizing a 3 stock portfolio with respect to the weights for each of the availble candidate stocks. The stock that makes the 3 stock portfolio have the lowest tracking error is included and then we add a 4th stock and so one which produces the lowest tracking error. The algorithm is greedy in that it assumes the path take to get to an optiminal k will be to determine optimal n in order.
def eval_best_among_candidates(
X_all: pd.DataFrame,
y: np.ndarray,
current_selected: list[str],
candidate_pool: list[str],
K: int,
verbose: bool = False,
):
'''Evalutate the best stock from a candidate pool to add to the current selected list.'''
best_te = np.inf
best_ticker = None
best_weights = None
for ticker in candidate_pool:
tickers_sub = current_selected + [ticker]
X = X_all[tickers_sub].to_numpy()
ok, w_opt, te = minimize_te_best_weights(X, y, K, None, None) # find the optimal weights for
# if optimization failed skip this ticker
if not ok:
if verbose:
print(f" Skipping {ticker}: TE optimizer failed.")
continue
# if it the best tracking error than keep it otherwise do not keep it
if te < best_te:
best_te = te
best_ticker = ticker
best_weights = w_opt
if verbose:
print(f" Tested {ticker}: TE={te:.6f}")
return best_ticker, best_weights, best_teAfter each of the best 10, 11, 12 ... 25 stock portfolio is determined, it is just a matter of choosing which of those 15 is best.
This approach is determined to be better than calculating a portfolio beta closest to 1 as follows.
The reasons which involve diversification, compand and industry risk are outlined in the following academic papers.
Academic References:
https://www.sciencedirect.com/science/article/abs/pii/S1062976914000763
https://link.springer.com/article/10.1007/s10957-022-02116-w