360 lines
8.1 KiB
Plaintext
360 lines
8.1 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "4e198165",
|
|
"metadata": {},
|
|
"source": [
|
|
"<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d0b4a98b",
|
|
"metadata": {},
|
|
"source": [
|
|
"This notebook demonstrates the use of portfolio optimization techniques to analyze and compare different investment strategies. It fetches historical price data for various sector ETFs, preprocesses it to obtain returns, and splits the data into training and testing sets. Three portfolio models—Maximum Diversification, Equal Weighted, and Random Weighted—are trained and their diversification metrics are compared. Finally, it visualizes portfolio compositions and cumulative returns to assess performance."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "15ec700b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from plotly.io import show\n",
|
|
"from sklearn.model_selection import train_test_split\n",
|
|
"from skfolio import Population\n",
|
|
"from skfolio.optimization import (\n",
|
|
" EqualWeighted, \n",
|
|
" MaximumDiversification,\n",
|
|
" Random\n",
|
|
")\n",
|
|
"from skfolio.preprocessing import prices_to_returns\n",
|
|
"from openbb import obb"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7e1ac742",
|
|
"metadata": {},
|
|
"source": [
|
|
"List of sector ETFs to fetch historical price data for analysis"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "64eb21b9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"sectors = [\n",
|
|
" \"XLE\", \n",
|
|
" \"XLF\", \n",
|
|
" \"XLU\", \n",
|
|
" \"XLI\", \n",
|
|
" \"GDX\", \n",
|
|
" \"XLK\", \n",
|
|
" \"XLV\", \n",
|
|
" \"XLY\", \n",
|
|
" \"XLP\", \n",
|
|
" \"XLB\", \n",
|
|
" \"XOP\", \n",
|
|
" \"IYR\", \n",
|
|
" \"XHB\", \n",
|
|
" \"ITB\", \n",
|
|
" \"VNQ\", \n",
|
|
" \"GDXJ\", \n",
|
|
" \"IYE\", \n",
|
|
" \"OIH\", \n",
|
|
" \"XME\", \n",
|
|
" \"XRT\", \n",
|
|
" \"SMH\", \n",
|
|
" \"IBB\", \n",
|
|
" \"KBE\", \n",
|
|
" \"KRE\", \n",
|
|
" \"XTL\", \n",
|
|
"]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e615f85f",
|
|
"metadata": {},
|
|
"source": [
|
|
"Fetch historical price data for the specified sector ETFs"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3f858885",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"df = obb.equity.price.historical(\n",
|
|
" sectors, \n",
|
|
" start_date=\"2010-01-01\", \n",
|
|
" provider=\"yfinance\"\n",
|
|
").to_df()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "40e2be93",
|
|
"metadata": {},
|
|
"source": [
|
|
"Pivot the fetched data to get closing prices for each ETF and drop missing values"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "f05a1194",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"pivoted = df.pivot(\n",
|
|
" columns=\"symbol\", \n",
|
|
" values=\"close\"\n",
|
|
").dropna()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "214068d8",
|
|
"metadata": {},
|
|
"source": [
|
|
"Convert the closing prices to returns"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e0c996bc",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"X = prices_to_returns(pivoted)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "dd117308",
|
|
"metadata": {},
|
|
"source": [
|
|
"Split the return data into training and testing sets without shuffling"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "74da06e0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"X_train, X_test = train_test_split(\n",
|
|
" X, \n",
|
|
" test_size=0.33, \n",
|
|
" shuffle=False\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9af78247",
|
|
"metadata": {},
|
|
"source": [
|
|
"Initialize and fit the Maximum Diversification model on the training data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "f31ffe88",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model = MaximumDiversification()\n",
|
|
"model.fit(X_train)\n",
|
|
"ptf_model_train = model.predict(X_train)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3e7a6590",
|
|
"metadata": {},
|
|
"source": [
|
|
"Initialize and fit the Equal Weighted model on the training data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2f3ce359",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"bench = EqualWeighted()\n",
|
|
"bench.fit(X_train)\n",
|
|
"ptf_bench_train = bench.predict(X_train)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b960ba03",
|
|
"metadata": {},
|
|
"source": [
|
|
"Initialize and fit the Random Weighted model on the training data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "042f0091",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"random = Random()\n",
|
|
"random.fit(X_train)\n",
|
|
"ptf_random_train = random.predict(X_train)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "68e585cc",
|
|
"metadata": {},
|
|
"source": [
|
|
"Print the diversification metrics for each trained model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "fe29bf6e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"print(f\"Maximum Diversification model: {ptf_model_train.diversification:0.2f}\")\n",
|
|
"print(f\"Equal Weighted model: {ptf_bench_train.diversification:0.2f}\")\n",
|
|
"print(f\"Random Weighted model: {ptf_random_train.diversification:0.2f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "223e8f31",
|
|
"metadata": {},
|
|
"source": [
|
|
"Predict the portfolio composition for the testing data using the trained models"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2a6517f7",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"ptf_model_test = model.predict(X_test)\n",
|
|
"ptf_bench_test = bench.predict(X_test)\n",
|
|
"ptf_random_test = random.predict(X_test)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3ebeb407",
|
|
"metadata": {},
|
|
"source": [
|
|
"Create a Population object with the predicted portfolios for comparison"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9452d1ec",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"population = Population([\n",
|
|
" ptf_model_test, \n",
|
|
" ptf_bench_test, \n",
|
|
" ptf_random_test\n",
|
|
"])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7bf2774e",
|
|
"metadata": {},
|
|
"source": [
|
|
"Plot the composition of the portfolios in the population"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "06d89e23",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"population.plot_composition()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "49cb1480",
|
|
"metadata": {},
|
|
"source": [
|
|
"Plot the cumulative returns of the portfolios in the population"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c01afb98",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"population.plot_cumulative_returns()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "5a0b21c1",
|
|
"metadata": {},
|
|
"source": [
|
|
"Display a summary of statistics for the portfolios in the population"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d3f4ed05",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"population.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3b9d2638",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"https://pyquantnews.com/\">PyQuant News</a> is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to <a href=\"https://gettingstartedwithpythonforquantfinance.com/\">get started with Python for quant finance</a>. For educational purposes. Not investment advise. Use at your own risk."
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"jupytext": {
|
|
"cell_metadata_filter": "-all",
|
|
"main_language": "python",
|
|
"notebook_metadata_filter": "-all"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|