Skip to content

Commit

Permalink
Add 131_ReplicateQQQ.ipynb
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonstrimpel committed Jan 16, 2025
1 parent 9349843 commit dc6485f
Showing 1 changed file with 36 additions and 93 deletions.
129 changes: 36 additions & 93 deletions 131_ReplicateQQQ.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,11 @@
"metadata": {},
"outputs": [],
"source": [
"```python\n",
"import riskfolio as rp\n",
"import pandas as pd\n",
"import yfinance as yf"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e836364c",
"metadata": {},
"outputs": [],
"source": [
"```"
]
},
{
"cell_type": "markdown",
"id": "adf19156",
Expand All @@ -40,11 +29,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1d494582",
"cell_type": "markdown",
"id": "e4e712d8-8e45-4d7e-9299-834fb0921d83",
"metadata": {},
"outputs": [],
"source": [
"We will fetch historical stock price data for a list of assets from Yahoo Finance. This data will be used to calculate daily returns, which are necessary for constructing a portfolio."
]
Expand All @@ -56,7 +43,6 @@
"metadata": {},
"outputs": [],
"source": [
"```python\n",
"assets = [\"QQQ\", \"AAPL\", \"MSFT\", \"AMZN\", \"GOOGL\", \"META\", \"TSLA\", \"NVDA\"]"
]
},
Expand All @@ -83,21 +69,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "59bf83ed",
"metadata": {},
"outputs": [],
"source": [
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4c8b8f01",
"cell_type": "markdown",
"id": "4e5aec0b-8f51-409b-b447-04a50f5d005d",
"metadata": {},
"outputs": [],
"source": [
"We define a list of asset symbols that we are interested in analyzing. These symbols include popular technology stocks and an ETF. Using the `yfinance` library, we download adjusted closing price data for these assets over a specified date range. The data is then converted to a pandas DataFrame with a datetime index for easier manipulation. We calculate daily percentage returns for the assets and store them in a DataFrame, dropping any missing values. The benchmark returns, specifically for the QQQ ETF, are also isolated for later comparison."
]
Expand All @@ -111,11 +85,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40709711",
"cell_type": "markdown",
"id": "651d9b2b-62ac-4fa7-af08-9ef2043962e8",
"metadata": {},
"outputs": [],
"source": [
"Next, we will set up a portfolio object to store the asset returns and configure it with desired statistical methods. We also define some constraints for the optimization process."
]
Expand All @@ -127,7 +99,6 @@
"metadata": {},
"outputs": [],
"source": [
"```python\n",
"port = rp.Portfolio(returns=returns)\n",
"port.assets_stats(method_mu=\"hist\", method_cov=\"hist\", d=0.94)"
]
Expand Down Expand Up @@ -155,21 +126,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aea52d15",
"cell_type": "markdown",
"id": "c68144ff-a79a-4aa0-98fd-e20e442456be",
"metadata": {},
"outputs": [],
"source": [
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a6b34994",
"metadata": {},
"outputs": [],
"source": [
"We create a portfolio object using the `riskfolio` library and load the calculated returns into it. We then calculate asset statistics like mean and covariance using historical data, setting the decay factor for exponential smoothing. We indicate that there are no predefined benchmark weights, choosing instead to use the benchmark index we previously defined. We enable the use of tracking error constraints, which will allow us to control how much the portfolio's returns can deviate from the benchmark. We set a maximum tracking error of 0.8%, ensuring our portfolio remains closely aligned with the benchmark."
]
Expand All @@ -183,11 +142,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57d70a6d",
"cell_type": "markdown",
"id": "8193947a-3ee0-4661-9243-8b3e44ef1fa3",
"metadata": {},
"outputs": [],
"source": [
"We will perform the portfolio optimization using the specified risk model and objective function. After obtaining the optimal weights, we will visualize the portfolio composition with a pie chart."
]
Expand All @@ -199,7 +156,6 @@
"metadata": {},
"outputs": [],
"source": [
"```python\n",
"w = port.optimization(\n",
" model=\"Classic\",\n",
" rm=\"CVaR\",\n",
Expand Down Expand Up @@ -230,21 +186,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "deca6ab4",
"metadata": {},
"outputs": [],
"source": [
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7be3484c",
"cell_type": "markdown",
"id": "5be4c9bb-fea4-446b-af6d-49d4f4a62e70",
"metadata": {},
"outputs": [],
"source": [
"We perform the portfolio optimization using a classic mean-variance model. The risk measure chosen is Conditional Value-at-Risk (CVaR), which focuses on tail risk. We aim to maximize the Sharpe ratio, which balances risk and return. The optimization assumes a risk-free rate of 0% and uses historical data for calculations. The result is a set of optimal asset weights, which we then visualize using a pie chart. The pie chart helps us understand the composition of the portfolio, showing the relative weight of each asset. We also group smaller allocations under \"others\" for simplicity."
]
Expand All @@ -258,11 +202,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6b5fa2f8",
"cell_type": "markdown",
"id": "669ab53f-6741-42c4-9019-129f0e5f3cd8",
"metadata": {},
"outputs": [],
"source": [
"We will calculate the cumulative returns for both the optimized portfolio and the benchmark. Finally, we will plot these returns to visually compare their performance over time."
]
Expand All @@ -274,7 +216,6 @@
"metadata": {},
"outputs": [],
"source": [
"```python\n",
"portfolio_returns = returns.dot(w)"
]
},
Expand All @@ -299,21 +240,9 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d9a5ded",
"metadata": {},
"outputs": [],
"source": [
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "99d44926",
"cell_type": "markdown",
"id": "e704d3e3-c206-4649-a4b2-3c32937f2397",
"metadata": {},
"outputs": [],
"source": [
"We calculate the portfolio's returns by multiplying the asset returns by their respective weights. This gives us a time series of portfolio returns. We then create a DataFrame that combines these portfolio returns with the benchmark returns, aligning them for comparison. We calculate cumulative returns by adding one to each return and taking the cumulative product over time. Finally, we plot these cumulative returns to visually compare the performance of the optimized portfolio against the QQQ benchmark. The resulting plot provides a clear view of how well the portfolio tracks the benchmark and highlights any periods of outperformance or underperformance."
]
Expand All @@ -327,14 +256,11 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dca4927f",
"cell_type": "markdown",
"id": "3e344f85-7145-468b-bb26-b1110f082095",
"metadata": {},
"outputs": [],
"source": [
"Try adjusting the maximum allowed tracking error to see how it affects the portfolio's composition and returns. You can also explore changing the risk measure from CVaR to another option like variance or maximum drawdown. Experiment with different objective functions to see how they influence the optimization results. Each of these changes can provide insights into how different constraints and goals impact the behavior of a portfolio.\n",
"```"
"Try adjusting the maximum allowed tracking error to see how it affects the portfolio's composition and returns. You can also explore changing the risk measure from CVaR to another option like variance or maximum drawdown. Experiment with different objective functions to see how they influence the optimization results. Each of these changes can provide insights into how different constraints and goals impact the behavior of a portfolio."
]
},
{
Expand All @@ -351,6 +277,23 @@
"cell_metadata_filter": "-all",
"main_language": "python",
"notebook_metadata_filter": "-all"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
Expand Down

0 comments on commit dc6485f

Please sign in to comment.