https://github.com/amanda-ucc/market-tracker
Automated portfolio creator that generates a portoflio which mimics a bench mark index by minimizing the tracking error.
https://github.com/amanda-ucc/market-tracker
beta covariance numpy pandas scipy sharpe-ratio tracking-error variance yfinance
Last synced: 2 months ago
JSON representation
Automated portfolio creator that generates a portoflio which mimics a bench mark index by minimizing the tracking error.
- Host: GitHub
- URL: https://github.com/amanda-ucc/market-tracker
- Owner: amanda-ucc
- Created: 2025-12-22T00:23:33.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-22T02:37:36.000Z (6 months ago)
- Last Synced: 2026-04-11T06:42:23.552Z (2 months ago)
- Topics: beta, covariance, numpy, pandas, scipy, sharpe-ratio, tracking-error, variance, yfinance
- Language: Jupyter Notebook
- Homepage:
- Size: 370 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Portfolio creation that tracks an index
`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:
$$
TE = \sqrt{\mathrm{Var}(R_p - R_{\text{index}})}
$$
$$
TE = \sqrt{\frac{1}{T} \sum_{t=1}^{T} (R_{p,t} - R_{\text{index},t})^{2}}
$$
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.
```python
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_te
```
After 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.
$$
\min_{\mathbf{w}}
\left|
\sum_{i=1}^{N} w_i \beta_i - 1
\right|
$$
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