bottama
trading-strategy-backtest
Python

Backtesting of different trading strategies by applying different Modern Portfolio Theory (MPT) approaches on long-only ETFs portfolios in Python.

Last updated Dec 9, 2025
21
Stars
12
Forks
0
Issues
0
Stars/day
Attention Score
22
Language breakdown
Python 100.0%
Files click to expand
README

Backtesting trading strategies

Last Update February 25, 2021 ####

Matteo Bottacini, matteo.bottacini@usi.ch ####

Project description

This project is to backtest different trading strategies applying different approaches from the Modern Portfolio Tehory (MPT) in Python 3.

The strategies backtested are:

  • The Optimal Markowitz Portfolio;
  • The Global Minimum Variance Portfolio;
  • The Risk-Parity Portfolio;
  • The Equally Weighted Portfolio

The ETFs considered are:

  • EEM: iShares MSCI Emerging Markets ETF
  • EMLC: VanEck Vectors J.P. Morgan EM Local Currency Bond ETF
  • IAU: iShares Gold Trust
  • IEF: iShares 7-10 Year Treasury Bond ETF
  • IWM: iShares Russell 2000 ETF
  • SPY: SPDR S&P 500 ETF Trust
  • TIP: iShares TIPS Bond ETF
  • TLT: iShares 20+ Year Treasury Bond ETF
  • VGK: Vanguard FTSE Europe Index Fund ETF Shares

The scripts do the following:

  • Download and analyse financial data;
  • Find the optimal Markowtiz portfolio (mean-variance);
  • Find the Global Minimum Variance (GMV) portfolio (minimum variance);
  • Find the risk-parity portfolio (risk parity);
  • Find the equally weighted portfolio (equally weighted);
  • Backtest a trading strategy with monthly rebalance with out-of-the-sample results;
  • Compare the results.

Folder structure: ~~~~ trading-strategy-backtest/ deliverable/ run_backtest.py src/ equallyweightedportfolio.py meanvarianceportfolio.py minimumvarianceportfolio.py riskparityportoflio.py README.md ~~~~

Trading strategy configuration

Each model is setup in its specific scripts.

Equally weighted portfolio ###

def equallyweightedportfolio(ret):
    init_weights = [1 / len(ret.columns)] * len(ret.columns)
    optweights = initweights

return opt_weights

Risk parity portfolio ###

def riskparityportfolio(ret):
    init_guess = 1 / ret.std()
    optweights = list(initguess / init_guess.sum())

return opt_weights

Minimum variance portfolio ###

import numpy as np
from scipy.optimize import minimize

def minimumvarianceportfolio(ret):

# define objective function to minimize: variance def getportfoliovariance(weights): weights = np.array(weights) # check cov_mat = ret.cov() portvariance = np.dot(weights.T, np.dot(covmat, weights)) return port_variance

# equality constraint: sum of the weights = 1 def weight_cons(weights): return np.sum(weights) - 1

# model set-up # - long only portfolio # - initial guess # - constraints bounds_lim = ((0, 1),) * len(ret.columns) init_weights = [1 / len(ret.columns)] * len(ret.columns) constraint = {'type': 'eq', 'fun': weight_cons}

# find optimal portfolio optport = minimize(fun=getportfolio_variance, x0=init_weights, bounds=bounds_lim, constraints=constraint, method='SLSQP')

# find optimal weights optweights = list(optport['x'])

return opt_weights

Mean-variance portfolio ###

# import modules
import numpy as np
from scipy.optimize import minimize

def meanvarianceportfolio(ret):

# define objective function to minimize: sharpe ratio def getportfoliosr(weights):

weights = np.array(weights) # check

# expected returns port_ret = np.dot(ret, weights) meanret = portret.mean()

# volatility cov_mat = ret.cov() portstd = np.sqrt(np.dot(weights.T, np.dot(covmat, weights)))

# sharpe ratio portsr = meanret / port_std return port_sr

def objective_fun(weights): negsr = getportfolio_sr(weights) * (-1) return neg_sr

# equality constraint: sum of the weights = 1 def weight_cons(weights): return np.sum(weights) - 1

# model set-up # - long only portfolio # - initial guess # - constraints bounds_lim = ((0, 1),) * len(ret.columns) init_weights = [1 / len(ret.columns)] * len(ret.columns) constraint = {'type': 'eq', 'fun': weight_cons}

# find optimal portfolio optport = minimize(fun=objectivefun, x0=init_weights, bounds=bounds_lim, constraints=constraint, method='SLSQP')

# find optimal weights optweights = list(optport['x'])

return opt_weights

Backtest configuration

In the script ../deliverable/run_backtest.py you can change the main variables to spot your ideal asset allocation and strategy. The parameters you can change are the following:
  • Assets;
  • Length of the training set
# feel free to change the following parameters:
tickers = []
monthstrainingset = 12 * 5

Results

Supported versions

This configuration has been tested against Python 3.8
🔗 More in this category

© 2026 GitRepoTrend · bottama/trading-strategy-backtest · Updated daily from GitHub