333 lines
7.5 KiB
Plaintext
333 lines
7.5 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7a0be8d0",
|
|
"metadata": {},
|
|
"source": [
|
|
"<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9159b91e",
|
|
"metadata": {},
|
|
"source": [
|
|
"This code uses the OpenBB Terminal and Riskfolio libraries to create and optimize a financial portfolio based on historical stock data. It first screens for stocks hitting new highs, filters them, and retrieves their historical prices. It calculates the returns, uses them to create a portfolio, and applies mean-variance optimization to determine the optimal asset allocation. The results are then visualized and detailed with the number of shares to purchase based on a specified investment amount."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ef4428e3",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from openbb_terminal.sdk import openbb, TerminalStyle\n",
|
|
"theme = TerminalStyle(\"light\", \"light\", \"light\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "08c0afb0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import riskfolio as rp"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "4f3bdc68",
|
|
"metadata": {},
|
|
"source": [
|
|
"Screen for stocks hitting new highs using OpenBB Terminal."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "106cb79a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"new_highs = openbb.stocks.screener.screener_data(\"new_high\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6a71c50c",
|
|
"metadata": {},
|
|
"source": [
|
|
"Filter stocks with a price above $15 and located in the USA."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d2f32e31",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"port_data = new_highs[\n",
|
|
" (new_highs.Price > 15) & (new_highs.Country == \"USA\")\n",
|
|
"]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "0109063b",
|
|
"metadata": {},
|
|
"source": [
|
|
"Retrieve the list of ticker symbols from the filtered data."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "aea54a4d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"tickers = port_data.Ticker.tolist()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2f647c98",
|
|
"metadata": {},
|
|
"source": [
|
|
"Fetch historical price data for the selected tickers from 2016-01-01 to 2022-12-31."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "5adbca4a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"data = openbb.economy.index(\n",
|
|
" tickers, \n",
|
|
" start_date=\"2016-01-01\", \n",
|
|
" end_date=\"2022-12-31\"\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "76163388",
|
|
"metadata": {},
|
|
"source": [
|
|
"Calculate the daily percentage returns of the stock prices and drop columns with any NaN values."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "785d23f5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"returns = data.pct_change()[1:]\n",
|
|
"returns.dropna(how=\"any\", axis=1, inplace=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "35afdcfe",
|
|
"metadata": {},
|
|
"source": [
|
|
"Create a portfolio object using the calculated returns."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c92245e0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"port = rp.Portfolio(returns=returns)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c06747d1",
|
|
"metadata": {},
|
|
"source": [
|
|
"Compute asset statistics such as historical mean and covariance."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3ecfd866",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"port.assets_stats(method_mu='hist', method_cov='hist', d=0.94)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b7b7529f",
|
|
"metadata": {},
|
|
"source": [
|
|
"Set the lower return constraint for the optimization problem."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "808168b2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"port.lowerret = 0.0008"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a7fed1c3",
|
|
"metadata": {},
|
|
"source": [
|
|
"Perform mean-variance optimization using historical data and no risk-free rate."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "85a8ec29",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"w_rp_c = port.rp_optimization(\n",
|
|
" model=\"Classic\", # use historical\n",
|
|
" rm=\"MV\", # use mean-variance optimization\n",
|
|
" hist=True, # use historical scenarios\n",
|
|
" rf=0, # set risk-free rate to 0\n",
|
|
" b=None # don't use constraints\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e7df27bc",
|
|
"metadata": {},
|
|
"source": [
|
|
"Plot the optimized portfolio allocation as a pie chart."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "22d9a70c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"ax = rp.plot_pie(w=w_rp_c)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "78e3c04c",
|
|
"metadata": {},
|
|
"source": [
|
|
"Plot the risk contributions of each asset in the portfolio."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e3d2307b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"ax = rp.plot_risk_con(\n",
|
|
" w_rp_c,\n",
|
|
" cov=port.cov,\n",
|
|
" returns=port.returns,\n",
|
|
" rm=\"MV\",\n",
|
|
" rf=0,\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e077bdaf",
|
|
"metadata": {},
|
|
"source": [
|
|
"Calculate the investment amount and number of shares to purchase for each asset."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e23ce3c7",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"port_val = 10_000\n",
|
|
"w_rp_c[\"invest_amt\"] = w_rp_c * port_val\n",
|
|
"w_rp_c[\"last_price\"] = data.iloc[-1]\n",
|
|
"w_rp_c[\"shares\"] = (w_rp_c.invest_amt / w_rp_c.last_price).astype(int)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "086649c5",
|
|
"metadata": {},
|
|
"source": [
|
|
"Display the optimized portfolio with investment amounts and number of shares."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0ce0af32",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"w_rp_c"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "4c5e18cb",
|
|
"metadata": {},
|
|
"source": [
|
|
"Sort the portfolio by asset weights in ascending order."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "707e8c1f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"w_rp_c.sort_values(by=\"weights\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ed9a0034",
|
|
"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
|
|
}
|