Skip to main content

pymarkowitz

Project description

Pymarkowitz

python   MIT license  

Pymarkowitz is an open source library for implementing portfolio optimisation. This library extends beyond the classical mean-variance optimization and takes into account a variety of risk and reward metrics, as well as the skew/kurtosis of assets.

Pymarkowitz can aid your decision-making in portfolio allocation in a risk-efficient manner. Pymarkowitz covers major objectives and constraints related with major types of risk and reward metrics, as well as simulation to examine the relationship between all these metrics. The flexibility in its implementation gives you the maximum discretion to customize and suit it to your own needs.

*Disclaimer: This library is for educational and entertainment purpose only. Please invest with due diligence at your own risk.

Head over to the directory demos to get an in-depth look at the project and its functionalities, or continue below to check out some brief examples.


Table of Contents


Installation

Setup

install directly using pip

$ pip install pymarkowitz

install from github

$ pip install git+https://github.com/johnsoong216/pymarkowitz.git

Development

For development purposes you can clone or fork the repo and hack right away!

$ git clone https://github.com/johnsoong216/pymarkowitz.git

Features


Preprocessing

First step is to import all availble modules

import numpy as np
import pandas as pd
from pymarkowitz import *

Read data with pandas. The dataset is available in the datasets directory. I will select 15 random stocks with 1000 observations

sp500 = pd.read_csv("datasets/sp500_1990_2000.csv", index_col='DATE').drop(["Unnamed: 0"], axis=1)
selected = sp500.iloc[:1000, np.random.choice(np.arange(0, sp500.shape[1]), 15, replace=False)]

Use a ReturnGenerator to compute historical mean return and daily return. Note that there are a variety of options to compute rolling/continuous/discrete returns. Please refer to the Return.ipynb jupyter notebook in demo directory

ret_generator = ReturnGenerator(selected)
mu_return = ret_generator.calc_mean_return(method='geometric')
daily_return = ret_generator.calc_return(method='daily')

Use a MomentGenerator to compute covariance/coskewness/cokurtosis matrix and beta. Note that there are a variety of options to compute the comoment matrix and asset beta, such as with semivariance, exponential and customized weighting. Normalizing matrices are also supported. Please refer to the Moment(Covariance).ipynb jupyter notebook in demo directory

benchmark = sp500.iloc[:1000].pct_change().dropna(how='any').sum(axis=1)/sp500.shape[1]
cov_matrix = mom_generator.calc_cov_mat()
beta_vec = mom_generator.calc_beta(benchmark)

Construct higher moment matrices by calling

coskew_matrix = mom_generator.calc_coskew_mat()
cokurt_matrix = mom_generator.calc_cokurt_mat()
coseventh_matrix = mom_generator.calc_comoment_mat(7)

Construct an Optimizer

PortOpt = Optimizer(mu_return, cov_matrix, beta_vec)

Optimization

Please refer to the Optimization.ipynb jupyter notebook in demo directory for more detailed explanations.

Set your Objective.

### Call PortOpt.objective_options() to look at all available objectives

PortOpt.add_objective("min_volatility")

Set your Constraints.

### Call PortOpt.constraint_options() to look at all available constraints.

PortOpt.add_constraint("weight", weight_bound=(-1,1), leverage=1) # Portfolio Long/Short
PortOpt.add_constraint("concentration", top_holdings=2, top_concentration=0.5) # Portfolio Concentration

Solve and Check Summary

PortOpt.solve()
weight_dict, metric_dict = PortOpt.summary(risk_free=0.015, market_return=0.07, top_holdings=2)


# Metric Dict Sample Output
{'Expected Return': 0.085,
 'Leverage': 1.0001,
 'Number of Holdings': 5,
 'Top 2 Holdings Concentrations': 0.5779,
 'Volatility': 0.1253,
 'Portfolio Beta': 0.7574,
 'Sharpe Ratio': 0.5586,
 'Treynor Ratio': 0.0924,
 "Jenson's Alpha": 0.0283}
 
# Weight Dict Sample Output
{'GIS': 0.309, 'CINF': 0.0505, 'USB': 0.104, 'HES': 0.2676, 'AEP': 0.269}

Simulation

Simulate and Select the Return Format (Seaborn, Plotly, DataFrame). DataFrame Option will also have the random weights used in each iteration.

Please refer to the Simulation.ipynb jupyter notebook in demo directory for more detailed explanations.

### Call Portopt.metric_options to see all available options for x, y axis

PortOpt.simulate(x='expected_return', y='sharpe', y_var={"risk_free": 0.02}, iters=10000, weight_bound=(-1, 1), leverage=1, ret_format='sns')

Sharpe VS Return

Backtesting

Use pymarkowitz to construct optimized weights and backtest with real life portfolio. In this example, I am using SPDR sector ETFs to construct an optimized portfolio and compare against buy & hold SPY.


import bt

data = bt.get('spy, rwr, xlb, xli, xly, xlp, xle, xlf, xlu, xlv, xlk', start='2005-01-01')

The configurations can be adjusted flexibly, please check backtesting.ipynb in demo directory for more detail. In this case we are minimizing volatility with a capped weight of 25% on each sector.

strategy = WeighMarkowitz(Config) #Imported from pymarkowitz.backtester.py

# Personal Strategy
s1 = bt.Strategy('s1', [bt.algos.RunWeekly(),
                       bt.algos.SelectAll(),
                       strategy,
                       bt.algos.Rebalance()])
test1 = bt.Backtest(s1, data)

# Buy & Hold
s2 = bt.Strategy('s2', [bt.algos.RunWeekly(),
                       bt.algos.SelectAll(),
                       bt.algos.WeighEqually(),
                       bt.algos.Rebalance()])
test2 = bt.Backtest(s2, data[['spy']].iloc[Config.lookback:])
res = bt.run(test1, test2)
res.plot()

Backtest_Result


Reference

Calculations of Correlation, Diversifcation & Risk Parity Factors:
https://investresolve.com/file/pdf/Portfolio-Optimization-Whitepaper.pdf

Calculations for Sharpe, Sortino, Beta, Treynor, Jenson's Alpha:
https://www.cfainstitute.org/-/media/documents/support/programs/investment-foundations/19-performance-evaluation.ashx?la=en&hash=F7FF3085AAFADE241B73403142AAE0BB1250B311
https://www.investopedia.com/terms/j/jensensmeasure.asp
https://www.investopedia.com/ask/answers/070615/what-formula-calculating-beta.asp

Calculations for Higher Moment Matrices:
https://cran.r-project.org/web/packages/PerformanceAnalytics/vignettes/EstimationComoments.pdf


License

License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymarkowitz-1.1.5.tar.gz (23.2 kB view details)

Uploaded Source

File details

Details for the file pymarkowitz-1.1.5.tar.gz.

File metadata

  • Download URL: pymarkowitz-1.1.5.tar.gz
  • Upload date:
  • Size: 23.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.6.13

File hashes

Hashes for pymarkowitz-1.1.5.tar.gz
Algorithm Hash digest
SHA256 1e66e5085ccb85923903903a68b702b668ae80b103edd614b6442a6460056c5c
MD5 079542eea6be8c9df3bfecdf75c800f3
BLAKE2b-256 0a17e35c83a8bbdfd4d6e7b0a39e72c4ee6dc00311cb9f8de8ef9333aae423e8

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page