huggingface112 commited on
Commit
576c56b
1 Parent(s): cd1bf03

remove unused files

Browse files
api_data_samples.ipynb CHANGED
@@ -1,15 +1,20 @@
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": 1,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
9
- "from sqlalchemy import create_engine\n",
10
- "import pandas as pd\n",
11
- "from datetime import timedelta\n",
12
- "import jqdatasdk as jq\n"
13
  ]
14
  },
15
  {
@@ -829,37 +834,6 @@
829
  "source": [
830
  "jq.get_all_securities()"
831
  ]
832
- },
833
- {
834
- "cell_type": "code",
835
- "execution_count": 4,
836
- "metadata": {},
837
- "outputs": [
838
- {
839
- "ename": "NameError",
840
- "evalue": "name 'engine' is not defined",
841
- "output_type": "error",
842
- "traceback": [
843
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
844
- "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
845
- "Cell \u001b[0;32mIn[4], line 9\u001b[0m\n\u001b[1;32m 7\u001b[0m df[\u001b[39m'\u001b[39m\u001b[39mdate\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39mto_datetime(df[\u001b[39m'\u001b[39m\u001b[39mdate\u001b[39m\u001b[39m'\u001b[39m])\n\u001b[1;32m 8\u001b[0m \u001b[39mreturn\u001b[39;00m df\n\u001b[0;32m----> 9\u001b[0m get_most_recent_profile(\u001b[39m'\u001b[39;49m\u001b[39mportfolio\u001b[39;49m\u001b[39m'\u001b[39;49m)\n",
846
- "Cell \u001b[0;32mIn[4], line 5\u001b[0m, in \u001b[0;36mget_most_recent_profile\u001b[0;34m(type)\u001b[0m\n\u001b[1;32m 3\u001b[0m table_name \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39mbenchmark_profile\u001b[39m\u001b[39m'\u001b[39m \u001b[39mif\u001b[39;00m \u001b[39mtype\u001b[39m \u001b[39m==\u001b[39m \u001b[39m'\u001b[39m\u001b[39mbenchmark\u001b[39m\u001b[39m'\u001b[39m \u001b[39melse\u001b[39;00m \u001b[39m'\u001b[39m\u001b[39mportfolio_profile\u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m 4\u001b[0m query \u001b[39m=\u001b[39m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mSELECT * FROM \u001b[39m\u001b[39m{\u001b[39;00mtable_name\u001b[39m}\u001b[39;00m\u001b[39m WHERE date = (SELECT MAX(date) FROM \u001b[39m\u001b[39m{\u001b[39;00mtable_name\u001b[39m}\u001b[39;00m\u001b[39m)\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m----> 5\u001b[0m df \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39mread_sql(query, con\u001b[39m=\u001b[39mengine)\n\u001b[1;32m 6\u001b[0m \u001b[39m# convert date to datetime object\u001b[39;00m\n\u001b[1;32m 7\u001b[0m df[\u001b[39m'\u001b[39m\u001b[39mdate\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39mto_datetime(df[\u001b[39m'\u001b[39m\u001b[39mdate\u001b[39m\u001b[39m'\u001b[39m])\n",
847
- "\u001b[0;31mNameError\u001b[0m: name 'engine' is not defined"
848
- ]
849
- }
850
- ],
851
- "source": [
852
- "# when update stock price just need the latest portfolio frame\n",
853
- "def get_most_recent_profile(type):\n",
854
- " table_name = 'benchmark_profile' if type == 'benchmark' else 'portfolio_profile'\n",
855
- " query = f\"SELECT * FROM {table_name} WHERE date = (SELECT MAX(date) FROM {table_name})\"\n",
856
- " with create_engine(db_url).connect() as conn:\n",
857
- " df = pd.read_sql(query, con=engine)\n",
858
- " # convert date to datetime object\n",
859
- " df['date'] = pd.to_datetime(df['date'])\n",
860
- " return df\n",
861
- "get_most_recent_profile('portfolio')"
862
- ]
863
  }
864
  ],
865
  "metadata": {
 
1
  {
2
  "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Example data from jq api call\n",
8
+ "### This notebook contain samples of jq api call. The purpose of this is to prvide a reference when developing the pipeline. "
9
+ ]
10
+ },
11
  {
12
  "cell_type": "code",
13
  "execution_count": 1,
14
  "metadata": {},
15
  "outputs": [],
16
  "source": [
17
+ "import jqdatasdk as jq"
 
 
 
18
  ]
19
  },
20
  {
 
834
  "source": [
835
  "jq.get_all_securities()"
836
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
837
  }
838
  ],
839
  "metadata": {
app.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
appComponents.py CHANGED
@@ -8,8 +8,8 @@ import numpy as np
8
  import hvplot.pandas # noqa
9
  from panel.viewable import Viewer
10
  import param
11
- from script import styling
12
- from script import description
13
  import plotly.graph_objs as go
14
  # import warnings
15
  pn.extension('mathjax')
 
8
  import hvplot.pandas # noqa
9
  from panel.viewable import Viewer
10
  import param
11
+ import styling
12
+ import description
13
  import plotly.graph_objs as go
14
  # import warnings
15
  pn.extension('mathjax')
app_ini.ipynb DELETED
@@ -1,723 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
11
- "application/vnd.holoviews_load.v0+json": ""
12
- },
13
- "metadata": {},
14
- "output_type": "display_data"
15
- },
16
- {
17
- "data": {
18
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
19
- "application/vnd.holoviews_load.v0+json": ""
20
- },
21
- "metadata": {},
22
- "output_type": "display_data"
23
- },
24
- {
25
- "data": {
26
- "text/html": [
27
- "<style>*[data-root-id],\n",
28
- "*[data-root-id] > * {\n",
29
- " box-sizing: border-box;\n",
30
- " font-family: var(--jp-ui-font-family);\n",
31
- " font-size: var(--jp-ui-font-size1);\n",
32
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
33
- "}\n",
34
- "\n",
35
- "/* Override VSCode background color */\n",
36
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
37
- " > .lm-Widget\n",
38
- " > *[data-root-id]),\n",
39
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
40
- " background-color: transparent !important;\n",
41
- "}\n",
42
- "</style>"
43
- ]
44
- },
45
- "metadata": {},
46
- "output_type": "display_data"
47
- }
48
- ],
49
- "source": [
50
- "import pandas as pd\n",
51
- "from datetime import datetime, timedelta\n",
52
- "from script import processing\n",
53
- "from script import api\n",
54
- "from sqlalchemy import create_engine\n",
55
- "import pytz\n",
56
- "import numpy as np\n",
57
- "import hvplot.pandas\n",
58
- "db_url = 'sqlite:///instance/local.db'\n",
59
- "engine = create_engine(db_url)\n"
60
- ]
61
- },
62
- {
63
- "cell_type": "code",
64
- "execution_count": 14,
65
- "metadata": {},
66
- "outputs": [
67
- {
68
- "name": "stdout",
69
- "output_type": "stream",
70
- "text": [
71
- "The autoreload extension is already loaded. To reload it, use:\n",
72
- " %reload_ext autoreload\n"
73
- ]
74
- }
75
- ],
76
- "source": [
77
- "%load_ext autoreload\n",
78
- "%autoreload 2"
79
- ]
80
- },
81
- {
82
- "cell_type": "code",
83
- "execution_count": 2,
84
- "metadata": {},
85
- "outputs": [
86
- {
87
- "ename": "FileNotFoundError",
88
- "evalue": "[Errno 2] No such file or directory: './data/p_profile.pkl'",
89
- "output_type": "error",
90
- "traceback": [
91
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
92
- "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
93
- "Cell \u001b[0;32mIn[2], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[39m## initialize by batchprocess to have initial result \u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m p_profile \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39;49mread_pickle(\u001b[39m'\u001b[39;49m\u001b[39m./data/p_profile.pkl\u001b[39;49m\u001b[39m'\u001b[39;49m)\n\u001b[1;32m 3\u001b[0m start_date \u001b[39m=\u001b[39m p_profile\u001b[39m.\u001b[39mdate\u001b[39m.\u001b[39mmin()\n\u001b[1;32m 4\u001b[0m end_date \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39mto_datetime(datetime\u001b[39m.\u001b[39mnow()\u001b[39m-\u001b[39mtimedelta(days\u001b[39m=\u001b[39m\u001b[39m7\u001b[39m))\n",
94
- "File \u001b[0;32m/opt/homebrew/Caskroom/miniforge/base/envs/portfolio_risk_assesment/lib/python3.11/site-packages/pandas/io/pickle.py:179\u001b[0m, in \u001b[0;36mread_pickle\u001b[0;34m(filepath_or_buffer, compression, storage_options)\u001b[0m\n\u001b[1;32m 115\u001b[0m \u001b[39m\u001b[39m\u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 116\u001b[0m \u001b[39mLoad pickled pandas object (or any object) from file.\u001b[39;00m\n\u001b[1;32m 117\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[39m4 4 9\u001b[39;00m\n\u001b[1;32m 177\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 178\u001b[0m excs_to_catch \u001b[39m=\u001b[39m (\u001b[39mAttributeError\u001b[39;00m, \u001b[39mImportError\u001b[39;00m, \u001b[39mModuleNotFoundError\u001b[39;00m, \u001b[39mTypeError\u001b[39;00m)\n\u001b[0;32m--> 179\u001b[0m \u001b[39mwith\u001b[39;00m get_handle(\n\u001b[1;32m 180\u001b[0m filepath_or_buffer,\n\u001b[1;32m 181\u001b[0m \u001b[39m\"\u001b[39;49m\u001b[39mrb\u001b[39;49m\u001b[39m\"\u001b[39;49m,\n\u001b[1;32m 182\u001b[0m compression\u001b[39m=\u001b[39;49mcompression,\n\u001b[1;32m 183\u001b[0m is_text\u001b[39m=\u001b[39;49m\u001b[39mFalse\u001b[39;49;00m,\n\u001b[1;32m 184\u001b[0m storage_options\u001b[39m=\u001b[39;49mstorage_options,\n\u001b[1;32m 185\u001b[0m ) \u001b[39mas\u001b[39;00m handles:\n\u001b[1;32m 186\u001b[0m \u001b[39m# 1) try standard library Pickle\u001b[39;00m\n\u001b[1;32m 187\u001b[0m \u001b[39m# 2) try pickle_compat (older pandas version) to handle subclass changes\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[39m# 3) try pickle_compat with latin-1 encoding upon a UnicodeDecodeError\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m 191\u001b[0m \u001b[39m# TypeError for Cython complaints about object.__new__ vs Tick.__new__\u001b[39;00m\n\u001b[1;32m 192\u001b[0m \u001b[39mtry\u001b[39;00m:\n",
95
- "File \u001b[0;32m/opt/homebrew/Caskroom/miniforge/base/envs/portfolio_risk_assesment/lib/python3.11/site-packages/pandas/io/common.py:868\u001b[0m, in \u001b[0;36mget_handle\u001b[0;34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001b[0m\n\u001b[1;32m 859\u001b[0m handle \u001b[39m=\u001b[39m \u001b[39mopen\u001b[39m(\n\u001b[1;32m 860\u001b[0m handle,\n\u001b[1;32m 861\u001b[0m ioargs\u001b[39m.\u001b[39mmode,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 864\u001b[0m newline\u001b[39m=\u001b[39m\u001b[39m\"\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[1;32m 865\u001b[0m )\n\u001b[1;32m 866\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[1;32m 867\u001b[0m \u001b[39m# Binary mode\u001b[39;00m\n\u001b[0;32m--> 868\u001b[0m handle \u001b[39m=\u001b[39m \u001b[39mopen\u001b[39;49m(handle, ioargs\u001b[39m.\u001b[39;49mmode)\n\u001b[1;32m 869\u001b[0m handles\u001b[39m.\u001b[39mappend(handle)\n\u001b[1;32m 871\u001b[0m \u001b[39m# Convert BytesIO or file objects passed with an encoding\u001b[39;00m\n",
96
- "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: './data/p_profile.pkl'"
97
- ]
98
- }
99
- ],
100
- "source": [
101
- "## initialize by batchprocess to have initial result \n",
102
- "p_profile = pd.read_pickle('./data/p_profile.pkl')\n",
103
- "start_date = p_profile.date.min()\n",
104
- "end_date = pd.to_datetime(datetime.now()-timedelta(days=7))\n",
105
- "# collect data upto 7 days ago \n",
106
- "b_profile, error = api.update_benchmark_profile(start_date, end_date)\n",
107
- "p_stocks, error = api.get_stocks_price(p_profile, start_date, end_date)\n",
108
- "b_stocks, error = api.get_stocks_price(b_profile, start_date, end_date)"
109
- ]
110
- },
111
- {
112
- "cell_type": "code",
113
- "execution_count": 13,
114
- "metadata": {},
115
- "outputs": [],
116
- "source": [
117
- "# save result \n",
118
- "# p_profile.to_pickle('./data/p_profile.pkl')\n",
119
- "# b_profile.to_pickle('./data/b_profile.pkl')\n",
120
- "p_stocks.to_pickle('./data/p_stocks.pkl')\n",
121
- "b_stocks.to_pickle('./data/b_stocks.pkl')\n"
122
- ]
123
- },
124
- {
125
- "cell_type": "code",
126
- "execution_count": 12,
127
- "metadata": {},
128
- "outputs": [
129
- {
130
- "name": "stderr",
131
- "output_type": "stream",
132
- "text": [
133
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:262: SettingWithCopyWarning: \n",
134
- "A value is trying to be set on a copy of a slice from a DataFrame\n",
135
- "\n",
136
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
137
- " df.fillna(0, inplace=True)\n",
138
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:263: SettingWithCopyWarning: \n",
139
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
140
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
141
- "\n",
142
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
143
- " df['active_return'] = df.pct_p * \\\n",
144
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:266: SettingWithCopyWarning: \n",
145
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
146
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
147
- "\n",
148
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
149
- " df['allocation'] = (df.prev_w_in_p_p - df.prev_w_in_p_b) * df.pct_b\n",
150
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:267: SettingWithCopyWarning: \n",
151
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
152
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
153
- "\n",
154
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
155
- " df['selection'] = (df.pct_p - df.pct_b) * df.prev_w_in_p_b\n",
156
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:268: SettingWithCopyWarning: \n",
157
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
158
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
159
- "\n",
160
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
161
- " df['interaction'] = (df.pct_p - df.pct_b) * \\\n",
162
- "/Users/lamonkey/Desktop/risk monitor/script/processing.py:270: SettingWithCopyWarning: \n",
163
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
164
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
165
- "\n",
166
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
167
- " df['notinal_return'] = df.allocation + df.selection + df.interaction\n"
168
- ]
169
- }
170
- ],
171
- "source": [
172
- "## batch processing \n",
173
- "calculated_p_stock = processing.get_processing_result_of_stocks_df(p_stocks, p_profile)\n",
174
- "calculated_b_stock = processing.get_processing_result_of_stocks_df(b_stocks, b_profile)\n",
175
- "p_eval_df = processing.get_portfolio_evaluation(calculated_p_stock, calculated_b_stock, p_profile)\n",
176
- "sector_eval_df = processing.get_portfolio_sector_evaluation(calculated_p_stock, calculated_b_stock)\n",
177
- "attribution_result_df = processing.calculate_total_attribution(calculated_p_stock, calculated_b_stock)\n",
178
- "s_attribution_result_df = processing.calculate_total_attribution_by_sector(calculated_p_stock, calculated_b_stock)"
179
- ]
180
- },
181
- {
182
- "cell_type": "code",
183
- "execution_count": 15,
184
- "metadata": {},
185
- "outputs": [],
186
- "source": [
187
- "## save result to db\n",
188
- "with engine.connect() as connection:\n",
189
- " # all_stock_info.to_sql('all_stock_info', con=connection, if_exists='replace', index=False)\n",
190
- " calculated_b_stock.to_sql('calculated_b_stock', con=connection, if_exists='replace', index=False)\n",
191
- " calculated_p_stock.to_sql('calculated_p_stock', con=connection, if_exists='replace', index=False)\n",
192
- " p_eval_df.to_sql('p_eval_result', con=connection, if_exists='replace', index=False)\n",
193
- " sector_eval_df.to_sql('sector_eval_result', con=connection, if_exists='replace', index=False)\n",
194
- " attribution_result_df.to_sql('attribution_result', con=connection, if_exists='replace', index=False)\n",
195
- " s_attribution_result_df.to_sql('s_attribution_result', con=connection, if_exists='replace', index=False)"
196
- ]
197
- },
198
- {
199
- "cell_type": "code",
200
- "execution_count": 63,
201
- "metadata": {},
202
- "outputs": [],
203
- "source": [
204
- "# load from sql\n",
205
- "name_df_map = dict()\n",
206
- "with engine.connect() as connection:\n",
207
- " for table in ['calculated_b_stock','calculated_p_stock','p_eval_result','sector_eval_result']:\n",
208
- " try:\n",
209
- " df = pd.read_sql_table(table, con=connection)\n",
210
- " name_df_map[table] = df\n",
211
- " except:\n",
212
- " pass\n",
213
- " # TODO load data from api and calculate result \n",
214
- " "
215
- ]
216
- },
217
- {
218
- "cell_type": "code",
219
- "execution_count": 91,
220
- "metadata": {},
221
- "outputs": [],
222
- "source": [
223
- "# load data upto now\n",
224
- "# Get the current time in UTC\n",
225
- "current_time = datetime.datetime.utcnow()\n",
226
- "# Set the timezone to Beijing\n",
227
- "beijing_timezone = pytz.timezone('Asia/Shanghai')\n",
228
- "# Convert the current time to Beijing time\n",
229
- "end_time = pd.to_datetime(current_time.astimezone(beijing_timezone).date())\n",
230
- "start_time = name_df_map['p_eval_result'].date.max() + timedelta(days=1)\n",
231
- "\n",
232
- "# get data up to today\n",
233
- "b_profile, error = api.update_benchmark_profile(start_time, end_time)\n",
234
- "p_stocks, error = api.get_stocks_price(p_profile, start_time, end_time)\n",
235
- "b_stocks, error = api.get_stocks_price(b_profile, start_time, end_time)"
236
- ]
237
- },
238
- {
239
- "cell_type": "code",
240
- "execution_count": 185,
241
- "metadata": {},
242
- "outputs": [
243
- {
244
- "ename": "ValueError",
245
- "evalue": "The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().",
246
- "output_type": "error",
247
- "traceback": [
248
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
249
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
250
- "\u001b[0;32m/var/folders/v5/2108rh5964q9j741wg_s8r1w0000gn/T/ipykernel_35506/2587190678.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mmost_recent_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname_df_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'calculated_p_stock'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroupby\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ticker'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreset_index\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mconcat_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconcat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmost_recent_df\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mp_stocks\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjoin\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'outer'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mprocessing\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_processing_result_of_stocks_df\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconcat_df\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mp_profile\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
251
- "\u001b[0;32m~/Desktop/risk monitor/script/processing.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(stock_df, profile_df)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mindex\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrow\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mgroup\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miterrows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mcur_w\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'nan'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[0;31m# if has initial weight, the following row all use this initial weight\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 42\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misna\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrow\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'initial_weight'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 43\u001b[0m \u001b[0mini_w\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrow\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'initial_weight'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0mcur_w\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mini_w\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
252
- "\u001b[0;32m/opt/homebrew/Caskroom/miniforge/base/envs/portfolio_risk_assesment/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1464\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mfinal\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1465\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__nonzero__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mNoReturn\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1466\u001b[0;31m raise ValueError(\n\u001b[0m\u001b[1;32m 1467\u001b[0m \u001b[0;34mf\"The truth value of a {type(self).__name__} is ambiguous. \"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1468\u001b[0m \u001b[0;34m\"Use a.empty, a.bool(), a.item(), a.any() or a.all().\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1469\u001b[0m )\n",
253
- "\u001b[0;31mValueError\u001b[0m: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()."
254
- ]
255
- }
256
- ],
257
- "source": [
258
- "most_recent_df = name_df_map['calculated_p_stock'].groupby('ticker').last().reset_index()\n",
259
- "concat_df = pd.concat([most_recent_df, p_stocks], axis=0, join='outer')\n",
260
- "processing.get_processing_result_of_stocks_df(concat_df, p_profile)"
261
- ]
262
- },
263
- {
264
- "cell_type": "code",
265
- "execution_count": 182,
266
- "metadata": {},
267
- "outputs": [
268
- {
269
- "data": {
270
- "text/html": [
271
- "<div>\n",
272
- "<style scoped>\n",
273
- " .dataframe tbody tr th:only-of-type {\n",
274
- " vertical-align: middle;\n",
275
- " }\n",
276
- "\n",
277
- " .dataframe tbody tr th {\n",
278
- " vertical-align: top;\n",
279
- " }\n",
280
- "\n",
281
- " .dataframe thead th {\n",
282
- " text-align: right;\n",
283
- " }\n",
284
- "</style>\n",
285
- "<table border=\"1\" class=\"dataframe\">\n",
286
- " <thead>\n",
287
- " <tr style=\"text-align: right;\">\n",
288
- " <th></th>\n",
289
- " <th>date</th>\n",
290
- " <th>ticker</th>\n",
291
- " <th>open</th>\n",
292
- " <th>close</th>\n",
293
- " <th>high</th>\n",
294
- " <th>low</th>\n",
295
- " <th>volume</th>\n",
296
- " <th>money</th>\n",
297
- " <th>display_name</th>\n",
298
- " <th>name</th>\n",
299
- " <th>...</th>\n",
300
- " <th>portfolio_pct</th>\n",
301
- " <th>prev_w_in_sectore</th>\n",
302
- " <th>ini_w_in_sector</th>\n",
303
- " <th>sector_pct</th>\n",
304
- " <th>portfolio_return</th>\n",
305
- " <th>cum_pct</th>\n",
306
- " <th>return</th>\n",
307
- " <th>sector_return</th>\n",
308
- " <th>cur_w_in_p</th>\n",
309
- " <th>pre_w_in_sector</th>\n",
310
- " </tr>\n",
311
- " </thead>\n",
312
- " <tbody>\n",
313
- " <tr>\n",
314
- " <th>0</th>\n",
315
- " <td>2021-01-05</td>\n",
316
- " <td>600409.XSHG</td>\n",
317
- " <td>9.23</td>\n",
318
- " <td>9.57</td>\n",
319
- " <td>9.66</td>\n",
320
- " <td>9.08</td>\n",
321
- " <td>82669289.0</td>\n",
322
- " <td>7.803391e+08</td>\n",
323
- " <td>三友化工</td>\n",
324
- " <td>SYHG</td>\n",
325
- " <td>...</td>\n",
326
- " <td>NaN</td>\n",
327
- " <td>NaN</td>\n",
328
- " <td>1.0</td>\n",
329
- " <td>NaN</td>\n",
330
- " <td>NaN</td>\n",
331
- " <td>NaN</td>\n",
332
- " <td>NaN</td>\n",
333
- " <td>NaN</td>\n",
334
- " <td>NaN</td>\n",
335
- " <td>NaN</td>\n",
336
- " </tr>\n",
337
- " <tr>\n",
338
- " <th>1</th>\n",
339
- " <td>2021-01-05</td>\n",
340
- " <td>300274.XSHE</td>\n",
341
- " <td>76.03</td>\n",
342
- " <td>76.45</td>\n",
343
- " <td>80.20</td>\n",
344
- " <td>75.27</td>\n",
345
- " <td>51384827.0</td>\n",
346
- " <td>3.961995e+09</td>\n",
347
- " <td>阳光电源</td>\n",
348
- " <td>YGDY</td>\n",
349
- " <td>...</td>\n",
350
- " <td>NaN</td>\n",
351
- " <td>NaN</td>\n",
352
- " <td>0.5</td>\n",
353
- " <td>NaN</td>\n",
354
- " <td>NaN</td>\n",
355
- " <td>NaN</td>\n",
356
- " <td>NaN</td>\n",
357
- " <td>NaN</td>\n",
358
- " <td>NaN</td>\n",
359
- " <td>NaN</td>\n",
360
- " </tr>\n",
361
- " <tr>\n",
362
- " <th>2</th>\n",
363
- " <td>2021-01-05</td>\n",
364
- " <td>002920.XSHE</td>\n",
365
- " <td>85.44</td>\n",
366
- " <td>87.25</td>\n",
367
- " <td>87.95</td>\n",
368
- " <td>84.07</td>\n",
369
- " <td>3852674.0</td>\n",
370
- " <td>3.322598e+08</td>\n",
371
- " <td>德赛西威</td>\n",
372
- " <td>DSXW</td>\n",
373
- " <td>...</td>\n",
374
- " <td>NaN</td>\n",
375
- " <td>NaN</td>\n",
376
- " <td>1.0</td>\n",
377
- " <td>NaN</td>\n",
378
- " <td>NaN</td>\n",
379
- " <td>NaN</td>\n",
380
- " <td>NaN</td>\n",
381
- " <td>NaN</td>\n",
382
- " <td>NaN</td>\n",
383
- " <td>NaN</td>\n",
384
- " </tr>\n",
385
- " <tr>\n",
386
- " <th>3</th>\n",
387
- " <td>2021-01-05</td>\n",
388
- " <td>002709.XSHE</td>\n",
389
- " <td>32.54</td>\n",
390
- " <td>33.89</td>\n",
391
- " <td>34.22</td>\n",
392
- " <td>31.39</td>\n",
393
- " <td>59152352.0</td>\n",
394
- " <td>1.942406e+09</td>\n",
395
- " <td>天赐材料</td>\n",
396
- " <td>TCCL</td>\n",
397
- " <td>...</td>\n",
398
- " <td>NaN</td>\n",
399
- " <td>NaN</td>\n",
400
- " <td>0.5</td>\n",
401
- " <td>NaN</td>\n",
402
- " <td>NaN</td>\n",
403
- " <td>NaN</td>\n",
404
- " <td>NaN</td>\n",
405
- " <td>NaN</td>\n",
406
- " <td>NaN</td>\n",
407
- " <td>NaN</td>\n",
408
- " </tr>\n",
409
- " <tr>\n",
410
- " <th>4</th>\n",
411
- " <td>2021-01-05</td>\n",
412
- " <td>603882.XSHG</td>\n",
413
- " <td>125.25</td>\n",
414
- " <td>124.64</td>\n",
415
- " <td>128.31</td>\n",
416
- " <td>121.68</td>\n",
417
- " <td>6803710.0</td>\n",
418
- " <td>8.458543e+08</td>\n",
419
- " <td>金域医学</td>\n",
420
- " <td>JYYX</td>\n",
421
- " <td>...</td>\n",
422
- " <td>NaN</td>\n",
423
- " <td>NaN</td>\n",
424
- " <td>1.0</td>\n",
425
- " <td>NaN</td>\n",
426
- " <td>NaN</td>\n",
427
- " <td>NaN</td>\n",
428
- " <td>NaN</td>\n",
429
- " <td>NaN</td>\n",
430
- " <td>NaN</td>\n",
431
- " <td>NaN</td>\n",
432
- " </tr>\n",
433
- " <tr>\n",
434
- " <th>...</th>\n",
435
- " <td>...</td>\n",
436
- " <td>...</td>\n",
437
- " <td>...</td>\n",
438
- " <td>...</td>\n",
439
- " <td>...</td>\n",
440
- " <td>...</td>\n",
441
- " <td>...</td>\n",
442
- " <td>...</td>\n",
443
- " <td>...</td>\n",
444
- " <td>...</td>\n",
445
- " <td>...</td>\n",
446
- " <td>...</td>\n",
447
- " <td>...</td>\n",
448
- " <td>...</td>\n",
449
- " <td>...</td>\n",
450
- " <td>...</td>\n",
451
- " <td>...</td>\n",
452
- " <td>...</td>\n",
453
- " <td>...</td>\n",
454
- " <td>...</td>\n",
455
- " <td>...</td>\n",
456
- " </tr>\n",
457
- " <tr>\n",
458
- " <th>3609</th>\n",
459
- " <td>2023-06-27</td>\n",
460
- " <td>600415.XSHG</td>\n",
461
- " <td>8.52</td>\n",
462
- " <td>8.69</td>\n",
463
- " <td>8.78</td>\n",
464
- " <td>8.40</td>\n",
465
- " <td>151396630.0</td>\n",
466
- " <td>1.305075e+09</td>\n",
467
- " <td>小商品城</td>\n",
468
- " <td>XSPC</td>\n",
469
- " <td>...</td>\n",
470
- " <td>NaN</td>\n",
471
- " <td>NaN</td>\n",
472
- " <td>NaN</td>\n",
473
- " <td>0.027187</td>\n",
474
- " <td>NaN</td>\n",
475
- " <td>NaN</td>\n",
476
- " <td>NaN</td>\n",
477
- " <td>NaN</td>\n",
478
- " <td>0.301143</td>\n",
479
- " <td>1.0</td>\n",
480
- " </tr>\n",
481
- " <tr>\n",
482
- " <th>3610</th>\n",
483
- " <td>2023-06-28</td>\n",
484
- " <td>600415.XSHG</td>\n",
485
- " <td>8.60</td>\n",
486
- " <td>8.63</td>\n",
487
- " <td>8.68</td>\n",
488
- " <td>8.37</td>\n",
489
- " <td>103167271.0</td>\n",
490
- " <td>8.798186e+08</td>\n",
491
- " <td>小商品城</td>\n",
492
- " <td>XSPC</td>\n",
493
- " <td>...</td>\n",
494
- " <td>NaN</td>\n",
495
- " <td>NaN</td>\n",
496
- " <td>NaN</td>\n",
497
- " <td>-0.006904</td>\n",
498
- " <td>NaN</td>\n",
499
- " <td>NaN</td>\n",
500
- " <td>NaN</td>\n",
501
- " <td>NaN</td>\n",
502
- " <td>0.299958</td>\n",
503
- " <td>1.0</td>\n",
504
- " </tr>\n",
505
- " <tr>\n",
506
- " <th>3611</th>\n",
507
- " <td>2023-06-29</td>\n",
508
- " <td>600415.XSHG</td>\n",
509
- " <td>8.60</td>\n",
510
- " <td>8.74</td>\n",
511
- " <td>8.88</td>\n",
512
- " <td>8.58</td>\n",
513
- " <td>128969467.0</td>\n",
514
- " <td>1.125704e+09</td>\n",
515
- " <td>小商品城</td>\n",
516
- " <td>XSPC</td>\n",
517
- " <td>...</td>\n",
518
- " <td>NaN</td>\n",
519
- " <td>NaN</td>\n",
520
- " <td>NaN</td>\n",
521
- " <td>0.012746</td>\n",
522
- " <td>NaN</td>\n",
523
- " <td>NaN</td>\n",
524
- " <td>NaN</td>\n",
525
- " <td>NaN</td>\n",
526
- " <td>0.301804</td>\n",
527
- " <td>1.0</td>\n",
528
- " </tr>\n",
529
- " <tr>\n",
530
- " <th>3612</th>\n",
531
- " <td>2023-06-30</td>\n",
532
- " <td>600415.XSHG</td>\n",
533
- " <td>8.74</td>\n",
534
- " <td>8.53</td>\n",
535
- " <td>8.77</td>\n",
536
- " <td>8.48</td>\n",
537
- " <td>103029932.0</td>\n",
538
- " <td>8.844883e+08</td>\n",
539
- " <td>小商品城</td>\n",
540
- " <td>XSPC</td>\n",
541
- " <td>...</td>\n",
542
- " <td>NaN</td>\n",
543
- " <td>NaN</td>\n",
544
- " <td>NaN</td>\n",
545
- " <td>-0.024027</td>\n",
546
- " <td>NaN</td>\n",
547
- " <td>NaN</td>\n",
548
- " <td>NaN</td>\n",
549
- " <td>NaN</td>\n",
550
- " <td>0.293612</td>\n",
551
- " <td>1.0</td>\n",
552
- " </tr>\n",
553
- " <tr>\n",
554
- " <th>3613</th>\n",
555
- " <td>2023-07-03</td>\n",
556
- " <td>600415.XSHG</td>\n",
557
- " <td>8.45</td>\n",
558
- " <td>8.37</td>\n",
559
- " <td>8.46</td>\n",
560
- " <td>8.05</td>\n",
561
- " <td>133732493.0</td>\n",
562
- " <td>1.108033e+09</td>\n",
563
- " <td>小商品城</td>\n",
564
- " <td>XSPC</td>\n",
565
- " <td>...</td>\n",
566
- " <td>NaN</td>\n",
567
- " <td>NaN</td>\n",
568
- " <td>NaN</td>\n",
569
- " <td>-0.018757</td>\n",
570
- " <td>NaN</td>\n",
571
- " <td>NaN</td>\n",
572
- " <td>NaN</td>\n",
573
- " <td>NaN</td>\n",
574
- " <td>0.286010</td>\n",
575
- " <td>1.0</td>\n",
576
- " </tr>\n",
577
- " </tbody>\n",
578
- "</table>\n",
579
- "<p>3614 rows × 27 columns</p>\n",
580
- "</div>"
581
- ],
582
- "text/plain": [
583
- " date ticker open close high low volume \\\n",
584
- "0 2021-01-05 600409.XSHG 9.23 9.57 9.66 9.08 82669289.0 \n",
585
- "1 2021-01-05 300274.XSHE 76.03 76.45 80.20 75.27 51384827.0 \n",
586
- "2 2021-01-05 002920.XSHE 85.44 87.25 87.95 84.07 3852674.0 \n",
587
- "3 2021-01-05 002709.XSHE 32.54 33.89 34.22 31.39 59152352.0 \n",
588
- "4 2021-01-05 603882.XSHG 125.25 124.64 128.31 121.68 6803710.0 \n",
589
- "... ... ... ... ... ... ... ... \n",
590
- "3609 2023-06-27 600415.XSHG 8.52 8.69 8.78 8.40 151396630.0 \n",
591
- "3610 2023-06-28 600415.XSHG 8.60 8.63 8.68 8.37 103167271.0 \n",
592
- "3611 2023-06-29 600415.XSHG 8.60 8.74 8.88 8.58 128969467.0 \n",
593
- "3612 2023-06-30 600415.XSHG 8.74 8.53 8.77 8.48 103029932.0 \n",
594
- "3613 2023-07-03 600415.XSHG 8.45 8.37 8.46 8.05 133732493.0 \n",
595
- "\n",
596
- " money display_name name ... portfolio_pct prev_w_in_sectore \\\n",
597
- "0 7.803391e+08 三友化工 SYHG ... NaN NaN \n",
598
- "1 3.961995e+09 阳光电源 YGDY ... NaN NaN \n",
599
- "2 3.322598e+08 德赛西威 DSXW ... NaN NaN \n",
600
- "3 1.942406e+09 天赐材料 TCCL ... NaN NaN \n",
601
- "4 8.458543e+08 金域医学 JYYX ... NaN NaN \n",
602
- "... ... ... ... ... ... ... \n",
603
- "3609 1.305075e+09 小商品城 XSPC ... NaN NaN \n",
604
- "3610 8.798186e+08 小商品城 XSPC ... NaN NaN \n",
605
- "3611 1.125704e+09 小商品城 XSPC ... NaN NaN \n",
606
- "3612 8.844883e+08 小商品城 XSPC ... NaN NaN \n",
607
- "3613 1.108033e+09 小商品城 XSPC ... NaN NaN \n",
608
- "\n",
609
- " ini_w_in_sector sector_pct portfolio_return cum_pct return \\\n",
610
- "0 1.0 NaN NaN NaN NaN \n",
611
- "1 0.5 NaN NaN NaN NaN \n",
612
- "2 1.0 NaN NaN NaN NaN \n",
613
- "3 0.5 NaN NaN NaN NaN \n",
614
- "4 1.0 NaN NaN NaN NaN \n",
615
- "... ... ... ... ... ... \n",
616
- "3609 NaN 0.027187 NaN NaN NaN \n",
617
- "3610 NaN -0.006904 NaN NaN NaN \n",
618
- "3611 NaN 0.012746 NaN NaN NaN \n",
619
- "3612 NaN -0.024027 NaN NaN NaN \n",
620
- "3613 NaN -0.018757 NaN NaN NaN \n",
621
- "\n",
622
- " sector_return cur_w_in_p pre_w_in_sector \n",
623
- "0 NaN NaN NaN \n",
624
- "1 NaN NaN NaN \n",
625
- "2 NaN NaN NaN \n",
626
- "3 NaN NaN NaN \n",
627
- "4 NaN NaN NaN \n",
628
- "... ... ... ... \n",
629
- "3609 NaN 0.301143 1.0 \n",
630
- "3610 NaN 0.299958 1.0 \n",
631
- "3611 NaN 0.301804 1.0 \n",
632
- "3612 NaN 0.293612 1.0 \n",
633
- "3613 NaN 0.286010 1.0 \n",
634
- "\n",
635
- "[3614 rows x 27 columns]"
636
- ]
637
- },
638
- "execution_count": 182,
639
- "metadata": {},
640
- "output_type": "execute_result"
641
- }
642
- ],
643
- "source": [
644
- "most_recent_df = name_df_map['calculated_p_stock'].groupby('ticker').last().reset_index()\n",
645
- "\n",
646
- "def get_last_values(row):\n",
647
- " ticker = row['ticker']\n",
648
- " if ticker in p_profile['ticker'].values:\n",
649
- " return p_profile.loc[p_profile['ticker'] == ticker, ['display_name', 'name', 'aggregate_sector']].iloc[-1]\n",
650
- " else:\n",
651
- " return pd.Series([np.nan, np.nan, np.nan], index=['display_name', 'name', 'aggregate_sector'])\n",
652
- "# dispaly_name, name and aggregate_sector\n",
653
- "p_stocks[['display_name', 'name', 'aggregate_sector']] = p_stocks.apply(get_last_values, axis=1)\n",
654
- "\n",
655
- "# use the most recent result to resume calculation\n",
656
- "concat_df = pd.concat([most_recent_df, p_stocks], axis=0, join='outer')\n",
657
- "\n",
658
- "# pct\n",
659
- "concat_df['pct'] = concat_df.groupby('ticker')['close'].pct_change()\n",
660
- "\n",
661
- "# calculate not normalized previous weight and current weight\n",
662
- "groups = concat_df.groupby('ticker')\n",
663
- "for _, group in groups:\n",
664
- " cur_weight = np.nan\n",
665
- " for index, row in group.iterrows():\n",
666
- " if pd.notna(row['current_weight']):\n",
667
- " cur_weight = row['current_weight']\n",
668
- " else:\n",
669
- " concat_df.loc[index, 'previous_weight'] = cur_weight\n",
670
- " cur_weight = cur_weight * (1 + row['pct'])\n",
671
- " concat_df.loc[index, 'current_weight'] = cur_weight\n",
672
- "\n",
673
- "# calculate normalized previous and current weight\n",
674
- "concat_df['prev_w_in_p'] = concat_df['previous_weight'] / \\\n",
675
- " concat_df.groupby('date')['previous_weight'].transform('sum')\n",
676
- "concat_df['cur_w_in_p'] = concat_df['current_weight'] / \\\n",
677
- " concat_df.groupby('date')['current_weight'].transform('sum')\n",
678
- "\n",
679
- "# calculate previous weight in sector\n",
680
- "concat_df['pre_w_in_sector'] = concat_df['prev_w_in_p'] / \\\n",
681
- " concat_df.groupby(['date', 'aggregate_sector'])['prev_w_in_p'].transform('sum')\n",
682
- "\n",
683
- "# calculate pct in sector\n",
684
- "concat_df['sector_pct'] = concat_df['pct'] * concat_df['pre_w_in_sector']\n",
685
- "\n",
686
- "\n",
687
- "\n",
688
- "\n",
689
- "\n",
690
- "# remove group with first date\n",
691
- "min_date_group = concat_df.groupby('date')['date'].idxmin()\n",
692
- "concat_df = concat_df.drop(min_date_group)\n",
693
- "\n",
694
- "# merge back to calculated_stock\n",
695
- "pd.concat([name_df_map['calculated_p_stock'],concat_df]).reset_index(drop=True)\n",
696
- "\n",
697
- "# concat_df[concat_df.ticker == '002709.XSHE'][['date','pct','current_weight','previous_weight','prev_w_in_p','cur_w_in_p']]"
698
- ]
699
- }
700
- ],
701
- "metadata": {
702
- "kernelspec": {
703
- "display_name": "portfolio_risk_assesment",
704
- "language": "python",
705
- "name": "python3"
706
- },
707
- "language_info": {
708
- "codemirror_mode": {
709
- "name": "ipython",
710
- "version": 3
711
- },
712
- "file_extension": ".py",
713
- "mimetype": "text/x-python",
714
- "name": "python",
715
- "nbconvert_exporter": "python",
716
- "pygments_lexer": "ipython3",
717
- "version": "3.11.4"
718
- },
719
- "orig_nbformat": 4
720
- },
721
- "nbformat": 4,
722
- "nbformat_minor": 2
723
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/description.py → description.py RENAMED
@@ -3,6 +3,7 @@ This file store the tooltip to show in the GUI
3
 
4
  '''
5
  #周期回报
 
6
  periodic_return_report = '''
7
  选择周期查看每个周期的回报率,以及每个周期主动回报的归因。
8
  周期回报的数据点代表周期结束。
 
3
 
4
  '''
5
  #周期回报
6
+
7
  periodic_return_report = '''
8
  选择周期查看每个周期的回报率,以及每个周期主动回报的归因。
9
  周期回报的数据点代表周期结束。
index_page.py CHANGED
@@ -1,57 +1,35 @@
1
  import panel as pn
2
- import pandas as pd
3
- from datetime import datetime, timedelta
4
- import plotly.express as px
5
- import holoviews as hv
6
- import numpy as np
7
  from sidebar import SideNavBar
8
- import random
9
- import scipy.stats as stats
10
- import hvplot.pandas # noqa
11
  from sqlalchemy import create_engine
12
- import api
13
- # from backgroundTask import stocks_stream
14
- from functools import partial
15
- import plotly.graph_objects as go
16
- from panel.viewable import Viewer
17
- import processing
18
  import appComponents
19
- import param
20
  import db_operation as db
21
- # import warnings
22
  pn.extension('mathjax')
23
- # warnings.filterwarnings("ignore", category=pd.core.common.SettingWithCopyWarning)
24
  pn.extension('plotly')
25
  pn.extension('tabulator')
26
  db_url = 'sqlite:///instance/local.db'
27
  engine = create_engine(db_url)
28
 
29
 
30
-
31
  analytic_p = db.get_portfolio_analytic_df()
32
  analytic_b = db.get_benchmark_analytic_df()
33
- # load benchmark stock
34
- # with engine.connect() as connection:
35
- # analytics_df = pd.read
36
- # calculated_b_stock = pd.read_sql('calculated_b_stock', con=connection)
37
- # calculated_p_stock = pd.read_sql('calculated_p_stock', con=connection)
38
- # p_eval_df = pd.read_sql('p_eval_result', con=connection)
39
 
40
  stock_overview = appComponents.BestAndWorstStocks(
41
  analytic_df=analytic_p)
42
  composation_card = appComponents.PortfolioComposationCard(
43
  analytic_p)
44
  monthly_return_card = appComponents.HistReturnCard(
45
- calculated_p_stock=analytic_p, calculated_b_stock=analytic_b)
46
- total_return_card = appComponents.TotalReturnCard(name='Range',
47
  b_stock_df=analytic_b,
48
  p_stock_df=analytic_p,
49
  value=(0, 20))
50
  drawdown_card = appComponents.DrawDownCard(
51
- calculated_p_stock=analytic_p)
52
 
53
  top_header = appComponents.TopHeader(
54
- eval_df = analytic_p,
55
  )
56
 
57
  template = pn.template.FastListTemplate(
 
1
  import panel as pn
 
 
 
 
 
2
  from sidebar import SideNavBar
 
 
 
3
  from sqlalchemy import create_engine
 
 
 
 
 
 
4
  import appComponents
 
5
  import db_operation as db
6
+
7
  pn.extension('mathjax')
8
+
9
  pn.extension('plotly')
10
  pn.extension('tabulator')
11
  db_url = 'sqlite:///instance/local.db'
12
  engine = create_engine(db_url)
13
 
14
 
 
15
  analytic_p = db.get_portfolio_analytic_df()
16
  analytic_b = db.get_benchmark_analytic_df()
 
 
 
 
 
 
17
 
18
  stock_overview = appComponents.BestAndWorstStocks(
19
  analytic_df=analytic_p)
20
  composation_card = appComponents.PortfolioComposationCard(
21
  analytic_p)
22
  monthly_return_card = appComponents.HistReturnCard(
23
+ calculated_p_stock=analytic_p, calculated_b_stock=analytic_b)
24
+ total_return_card = appComponents.TotalReturnCard(name='Range',
25
  b_stock_df=analytic_b,
26
  p_stock_df=analytic_p,
27
  value=(0, 20))
28
  drawdown_card = appComponents.DrawDownCard(
29
+ calculated_p_stock=analytic_p)
30
 
31
  top_header = appComponents.TopHeader(
32
+ eval_df=analytic_p,
33
  )
34
 
35
  template = pn.template.FastListTemplate(
instance/local.db CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:cbb513c601ed039cdf11c093c2192afc7383eaa8f9db8f7dead5fba68a94ff0d
3
- size 164798464
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:77911978f609eea6d1dc9285228549b79a1f05a040207d28af2abb4fe7a37063
3
+ size 261677056
pipeline.py CHANGED
@@ -12,7 +12,7 @@ import processing
12
  # import settings
13
  # fetch new stock price
14
  stock_price_stream = Stream()
15
-
16
 
17
  # log
18
  log = Log('instance/log.json')
@@ -187,7 +187,9 @@ def save_stock_price_to_db(df: pd.DataFrame):
187
 
188
 
189
  def update_portfolio_profile_to_db(portfolio_df):
190
- '''overwrite the portfolio profile table in db'''
 
 
191
 
192
  if (_validate_schema(portfolio_df, ts.PORTFOLIO_TABLE_SCHEMA)):
193
  raise ValueError(
@@ -198,10 +200,14 @@ def update_portfolio_profile_to_db(portfolio_df):
198
  try:
199
  portfolio_df[ts.PORTFOLIO_TABLE_SCHEMA.keys()].to_sql(
200
  ts.PORTFOLIO_TABLE, con=conn, if_exists='append', index=False)
 
 
 
 
201
  return True
202
  except:
203
  return False
204
- # TODO trigger recomputation of analysis
205
 
206
 
207
  def right_fill_stock_price():
@@ -413,6 +419,26 @@ def batch_processing():
413
  db.save_benchmark_analytic_df(analytic_b)
414
 
415
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  async def daily_update():
417
  '''
418
  left and right fill stock price and benchmark weight based on portfolio
@@ -423,7 +449,7 @@ async def daily_update():
423
 
424
  '''
425
  last_update = log.get_time('daily_update')
426
- # check if need to update
427
  if last_update is None or utils.time_in_beijing() - last_update >= dt.timedelta(days=1):
428
  print("running daily update")
429
 
@@ -475,16 +501,11 @@ async def run():
475
  # print(stock_df)
476
  stock_price_stream.emit(stock_df)
477
 
478
- # # latest stock price
479
- # stock_df = update_stocks_price()
480
- # # add display name and sector to stock_df
481
- # stock_df = add_details_to_stock_df(stock_df)
482
- # save_stock_price_to_db(stock_df)
483
- # stock_price_stream.emit(stock_df)
484
- # update sotck_price
485
-
486
- # send fetched data
487
 
488
- # run processing
 
 
 
 
489
 
490
- # send fetched data
 
12
  # import settings
13
  # fetch new stock price
14
  stock_price_stream = Stream()
15
+ event = Stream()
16
 
17
  # log
18
  log = Log('instance/log.json')
 
187
 
188
 
189
  def update_portfolio_profile_to_db(portfolio_df):
190
+ '''overwrite the portfolio profile table in db, and trigger a left fill on benchmark, stock price
191
+ and recomputation of analysis
192
+ '''
193
 
194
  if (_validate_schema(portfolio_df, ts.PORTFOLIO_TABLE_SCHEMA)):
195
  raise ValueError(
 
200
  try:
201
  portfolio_df[ts.PORTFOLIO_TABLE_SCHEMA.keys()].to_sql(
202
  ts.PORTFOLIO_TABLE, con=conn, if_exists='append', index=False)
203
+
204
+ event.emit('update_portfolio')
205
+ # handle_portfolio_update()
206
+
207
  return True
208
  except:
209
  return False
210
+
211
 
212
 
213
  def right_fill_stock_price():
 
419
  db.save_benchmark_analytic_df(analytic_b)
420
 
421
 
422
+ def left_fill():
423
+ left_fill_benchmark_profile()
424
+ left_fill_stocks_price()
425
+
426
+
427
+ def handle_portfolio_update():
428
+ '''
429
+ execute when portfolio is updated,
430
+ left fill benchmark and stock price
431
+
432
+ update method is idempotent, so it is safe to call multiple times
433
+ '''
434
+ left_fill_benchmark_profile()
435
+ print("left fill benchmark profile")
436
+ left_fill_stocks_price()
437
+ print('left fill stock price db')
438
+ batch_processing()
439
+ print('done processing')
440
+
441
+
442
  async def daily_update():
443
  '''
444
  left and right fill stock price and benchmark weight based on portfolio
 
449
 
450
  '''
451
  last_update = log.get_time('daily_update')
452
+ # less than today 9am, since it need to force to update at 9
453
  if last_update is None or utils.time_in_beijing() - last_update >= dt.timedelta(days=1):
454
  print("running daily update")
455
 
 
501
  # print(stock_df)
502
  stock_price_stream.emit(stock_df)
503
 
 
 
 
 
 
 
 
 
 
504
 
505
+ def handle_event(e):
506
+ if e == "update_portfolio":
507
+ print("handling portfolio update")
508
+ handle_portfolio_update()
509
+ print("done handling portfolio update")
510
 
511
+ event.sink(handle_event)
pipeline/bhb.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
pipeline/create_dumpy_data.ipynb DELETED
@@ -1,36 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "from test_db_peration import db_operator\n",
10
- "from datetime import datetime\n"
11
- ]
12
- }
13
- ],
14
- "metadata": {
15
- "kernelspec": {
16
- "display_name": "portfolio_risk_assesment",
17
- "language": "python",
18
- "name": "python3"
19
- },
20
- "language_info": {
21
- "codemirror_mode": {
22
- "name": "ipython",
23
- "version": 3
24
- },
25
- "file_extension": ".py",
26
- "mimetype": "text/x-python",
27
- "name": "python",
28
- "nbconvert_exporter": "python",
29
- "pygments_lexer": "ipython3",
30
- "version": "3.11.4"
31
- },
32
- "orig_nbformat": 4
33
- },
34
- "nbformat": 4,
35
- "nbformat_minor": 2
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pipeline/db_operation.py DELETED
@@ -1,35 +0,0 @@
1
- from model import Stock
2
- from sqlalchemy import create_engine
3
- from sqlalchemy.orm import Session
4
-
5
-
6
- class db_operator():
7
- def __init__(self, db_url):
8
- self.engine = create_engine(db_url)
9
-
10
- def get_stocks_between(self, d1, d2):
11
- with Session(self.engine) as session:
12
- return session.query(Stock).filter(
13
- Stock.date.between(d1, d2)
14
- ).all()
15
-
16
- def add_stock(self, stock_data: dict):
17
- with Session(self.engine) as session:
18
- new_stock = Stock(**stock_data)
19
- session.add(new_stock)
20
- session.commit()
21
-
22
- def delete_stocks_between(self, d1, d2):
23
- with Session(self.engine) as session:
24
- session.query(Stock).filter(
25
- Stock.date.between(d1, d2)
26
- ).delete()
27
- session.commit()
28
-
29
- def delete_all_stocks(self):
30
- with Session(self.engine) as session:
31
- session.query(Stock).delete()
32
- session.commit()
33
-
34
-
35
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pipeline/model.py DELETED
@@ -1,41 +0,0 @@
1
- from sqlalchemy import Column, Integer, String, Float, create_engine, DateTime, PickleType
2
- from sqlalchemy.ext.declarative import declarative_base
3
- from sqlalchemy.orm import sessionmaker
4
-
5
- Base = declarative_base()
6
-
7
- class Stock(Base):
8
- __tablename__ = 'stock'
9
-
10
- id = Column(Integer, primary_key=True)
11
- ticker = Column(String(50))
12
- weight = Column(Float, nullable=True)
13
- display_name = Column(String(50), nullable=False)
14
- date = Column(DateTime, nullable=False)
15
- order = Column(Integer, autoincrement=True, nullable=True)
16
-
17
- def __repr__(self):
18
- return f"<{self.ticker}\
19
- {self.date}\
20
- {self.display_name}\
21
- {round(self.weight * 100)}%>"
22
-
23
-
24
- class Portfolio(Base):
25
- __tablename__ = 'portfolio'
26
-
27
- id = Column(Integer, primary_key=True)
28
- stocks = Column(PickleType, nullable=False)
29
- cached_result = Column(PickleType, nullable=True)
30
- # data = Column(PickleType, nullable=False)
31
- date = Column(DateTime, nullable=False)
32
- order = Column(Integer, autoincrement=True, nullable=True)
33
-
34
-
35
- # db_url = 'sqlite:///local_db.db' # Replace 'stocks.db' with the desired database name and location
36
-
37
- # engine = create_engine(db_url)
38
- # Base.metadata.create_all(engine)
39
-
40
- # Session = sessionmaker(bind=engine)
41
- # session = Session()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pipeline/test_db_peration.py DELETED
@@ -1,107 +0,0 @@
1
- from unittest import TestCase, main
2
- from db_operation import db_operator
3
- from datetime import datetime
4
- class test_db_operation(TestCase):
5
- def setUp(self) -> None:
6
- self.db_operator = db_operator('sqlite:///local_db.db')
7
- self.db_operator.delete_all_stocks()
8
- self.stock1 = {
9
- "ticker": 'AAPL',
10
- "weight": 1.0,
11
- "display_name": 'Apple Inc.',
12
- "date": datetime(2021, 1, 1)
13
- }
14
- self.stock2 = {
15
- "ticker": 'MSFT',
16
- "weight": 1.0,
17
- "display_name": 'Microsoft Corporation',
18
- "date": datetime(2021, 1, 1)
19
- }
20
-
21
- def test_insert(self):
22
- stock1 = {
23
- "ticker": 'AAPL',
24
- "weight": 1.0,
25
- "display_name": 'Apple Inc.',
26
- "date": datetime(2021, 1, 1)
27
- }
28
- self.db_operator.add_stock(stock1)
29
- retrieved_stock = self.db_operator.get_stocks_between(datetime(2021, 1, 1), datetime(2021, 1, 1))[0]
30
- self.assertEqual(retrieved_stock.ticker, 'AAPL')
31
- self.assertEqual(retrieved_stock.weight, 1.0)
32
- self.assertEqual(retrieved_stock.display_name, 'Apple Inc.')
33
- self.assertEqual(retrieved_stock.date, datetime(2021, 1, 1))
34
-
35
- def test_delete(self):
36
- self.db_operator.add_stock(self.stock1)
37
- self.db_operator.add_stock(self.stock2)
38
- self.db_operator.delete_stocks_between(
39
- datetime(2021, 1, 1),
40
- datetime(2021, 1, 1))
41
- retrieved_stocks = self.db_operator.get_stocks_between(
42
- datetime(2021, 1, 1),
43
- datetime(2021, 1, 1))
44
- self.assertEqual(len(retrieved_stocks), 0)
45
-
46
- def test_query_window_1d(self):
47
- # insert 2 stocks between 2021-01-01 and 2021-01-01 every hour
48
- for i in range(24):
49
- self.stock1['date'] = datetime(2021, 1, 1, i)
50
- self.stock2['date'] = datetime(2021, 1, 1, i)
51
- self.db_operator.add_stock(self.stock1)
52
- self.db_operator.add_stock(self.stock2)
53
- # insert two on 2021-01-02
54
- self.stock1['date'] = datetime(2021, 1, 2)
55
- self.stock2['date'] = datetime(2021, 1, 2)
56
- self.db_operator.add_stock(self.stock1)
57
- self.db_operator.add_stock(self.stock2)
58
- # query 1d
59
- retrieved_stocks = self.db_operator.get_stocks_between(
60
- datetime(2021, 1, 1),
61
- datetime(2021, 1, 2))
62
- self.assertEqual(len(retrieved_stocks), 50)
63
-
64
- def test_query_window_12h(self):
65
- # insert 2 stocks every hour between 2021-01-01 and 2021-01-01
66
- for i in range(24):
67
- self.stock1['date'] = datetime(2021, 1, 1, i)
68
- self.stock2['date'] = datetime(2021, 1, 1, i)
69
- self.db_operator.add_stock(self.stock1)
70
- self.db_operator.add_stock(self.stock2)
71
- # query 12h
72
- retrieved_stocks = self.db_operator.get_stocks_between(
73
- datetime(2021, 1, 1, 0),
74
- datetime(2021, 1, 1, 12))
75
- self.assertEqual(len(retrieved_stocks), 26)
76
- # self.assertTrue(False)
77
-
78
- def test_query_window_1h(self):
79
- # insert 2 stocks every mins between 2021-01-01 and 2021-01-01
80
- for i in range(60):
81
- self.stock1['date'] = datetime(2021, 1, 1, 0, i)
82
- self.stock2['date'] = datetime(2021, 1, 1, 0, i)
83
- self.db_operator.add_stock(self.stock1)
84
- self.db_operator.add_stock(self.stock2)
85
- # query 1h
86
- retrieved_stocks = self.db_operator.get_stocks_between(
87
- datetime(2021, 1, 1, 0),
88
- datetime(2021, 1, 1, 1))
89
- self.assertEqual(len(retrieved_stocks), 120)
90
-
91
- def test_query_window_30m(self):
92
- # insert 2 stocks every 1 between 2021-01-01-00:00 and 2021-01-01-00:20
93
- for i in range(20):
94
- self.stock1['date'] = datetime(2021, 1, 1, 0, i)
95
- self.stock2['date'] = datetime(2021, 1, 1, 0, i)
96
- self.db_operator.add_stock(self.stock1)
97
- self.db_operator.add_stock(self.stock2)
98
- # query 30m
99
- retrieved_stocks = self.db_operator.get_stocks_between(
100
- datetime(2021, 1, 1, 0),
101
- datetime(2021, 1, 1, 0, 30))
102
- self.assertEqual(len(retrieved_stocks), 40)
103
-
104
-
105
-
106
- if __name__ == '__main__':
107
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
portfolioEditingPage.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
portfolioEditingPage.py CHANGED
@@ -160,9 +160,9 @@ def app():
160
  # patch all synced_to_db to true
161
  indices = history_tabulator.value[
162
  ~history_tabulator.value['change_saved']].index.to_list()
163
-
164
  # add an offset to address the issue when df is empty index start from 1
165
-
166
  history_tabulator.patch({
167
  'change_saved': [(index, True) for index in indices]
168
  }, as_index=True)
@@ -237,11 +237,11 @@ def app():
237
  shares=row[2].value,
238
  ave_price=row[3].value,
239
  date=datetime_picker.value) for row in stock_column]
240
-
241
  if len(new_entry) == 0:
242
  print("no entry added")
243
- return
244
-
245
  new_profile = pipeline.create_portfolio_profile_df(new_entry)
246
  # calculate share changes
247
  tmp_profile = pd.concat([p_profile, new_profile], ignore_index=True)
@@ -294,12 +294,12 @@ def app():
294
  # update history tabulator and portfolio tabulator
295
  if successed:
296
  # mark changes as saved
297
- indices = selected_portfolio[~selected_portfolio['change_saved']].index.to_list()
 
298
  portfolio_tabulator.patch({
299
  'change_saved': [(index, True) for index in indices]
300
  }, as_index=True)
301
 
302
-
303
  _update_history_tabulator('sync')
304
 
305
  def handle_edit_portfolio_tabulator(e):
 
160
  # patch all synced_to_db to true
161
  indices = history_tabulator.value[
162
  ~history_tabulator.value['change_saved']].index.to_list()
163
+
164
  # add an offset to address the issue when df is empty index start from 1
165
+
166
  history_tabulator.patch({
167
  'change_saved': [(index, True) for index in indices]
168
  }, as_index=True)
 
237
  shares=row[2].value,
238
  ave_price=row[3].value,
239
  date=datetime_picker.value) for row in stock_column]
240
+
241
  if len(new_entry) == 0:
242
  print("no entry added")
243
+ return
244
+
245
  new_profile = pipeline.create_portfolio_profile_df(new_entry)
246
  # calculate share changes
247
  tmp_profile = pd.concat([p_profile, new_profile], ignore_index=True)
 
294
  # update history tabulator and portfolio tabulator
295
  if successed:
296
  # mark changes as saved
297
+ indices = selected_portfolio[~selected_portfolio['change_saved']].index.to_list(
298
+ )
299
  portfolio_tabulator.patch({
300
  'change_saved': [(index, True) for index in indices]
301
  }, as_index=True)
302
 
 
303
  _update_history_tabulator('sync')
304
 
305
  def handle_edit_portfolio_tabulator(e):
script/__init__.py DELETED
File without changes
script/api_test.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
script/bnb_sector_result.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:dc104daae7afcd56a05f8aff9fa4d80d139a7db33d271fd69fbacb29db22283a
3
- size 152021
 
 
 
 
script/downloadData.ipynb DELETED
@@ -1,751 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "import pandas as pd\n",
10
- "from api import create_portfolio, get_portfile_data, get_benchmark_portfolio\n",
11
- "from datetime import datetime"
12
- ]
13
- },
14
- {
15
- "cell_type": "code",
16
- "execution_count": 2,
17
- "metadata": {},
18
- "outputs": [],
19
- "source": [
20
- "# df = pd.read_pickle('../dummy_portfolio.pkl')\n",
21
- "# df.head(20)"
22
- ]
23
- },
24
- {
25
- "cell_type": "code",
26
- "execution_count": 3,
27
- "metadata": {},
28
- "outputs": [],
29
- "source": [
30
- "# ## create a portfolio\n",
31
- "\n",
32
- "# # weight can use mony\n",
33
- "# portfolio_profile_data = [\n",
34
- "# {'ticker': '002709.XSHE', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
35
- "# {'ticker': '002920.XSHE', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
36
- "# {'ticker': '300274.XSHE', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
37
- "# {'ticker': '600409.XSHG', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
38
- "# {'ticker': '600415.XSHG', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
39
- "# {'ticker': '603882.XSHG', 'date': datetime(2021, 1, 5), 'weight': 100},\n",
40
- "# ]\n",
41
- "# # ten thousand\n",
42
- "# mkt_cap = 100000\n",
43
- "# portfolio_profile, error = create_portfolio(portfolio_profile_data, mkt_cap)"
44
- ]
45
- },
46
- {
47
- "cell_type": "code",
48
- "execution_count": 4,
49
- "metadata": {},
50
- "outputs": [],
51
- "source": [
52
- "# print(error)\n",
53
- "# # save \n",
54
- "# portfolio_profile.to_pickle('../data/portfolio_portfile.pkl')\n",
55
- "# portfolio_profile.head(10)"
56
- ]
57
- },
58
- {
59
- "cell_type": "code",
60
- "execution_count": 5,
61
- "metadata": {},
62
- "outputs": [
63
- {
64
- "data": {
65
- "text/html": [
66
- "<div>\n",
67
- "<style scoped>\n",
68
- " .dataframe tbody tr th:only-of-type {\n",
69
- " vertical-align: middle;\n",
70
- " }\n",
71
- "\n",
72
- " .dataframe tbody tr th {\n",
73
- " vertical-align: top;\n",
74
- " }\n",
75
- "\n",
76
- " .dataframe thead th {\n",
77
- " text-align: right;\n",
78
- " }\n",
79
- "</style>\n",
80
- "<table border=\"1\" class=\"dataframe\">\n",
81
- " <thead>\n",
82
- " <tr style=\"text-align: right;\">\n",
83
- " <th></th>\n",
84
- " <th>ticker</th>\n",
85
- " <th>date</th>\n",
86
- " <th>weight</th>\n",
87
- " <th>display_name</th>\n",
88
- " <th>name</th>\n",
89
- " <th>sector</th>\n",
90
- " <th>aggregate_sector</th>\n",
91
- " </tr>\n",
92
- " </thead>\n",
93
- " <tbody>\n",
94
- " <tr>\n",
95
- " <th>0</th>\n",
96
- " <td>002709.XSHE</td>\n",
97
- " <td>2021-01-05</td>\n",
98
- " <td>100</td>\n",
99
- " <td>天赐材料</td>\n",
100
- " <td>TCCL</td>\n",
101
- " <td>电气设备I 电池II 电池化学品III 化学原料和化学制品制造业 电池部件及材料 工业</td>\n",
102
- " <td>工业</td>\n",
103
- " </tr>\n",
104
- " <tr>\n",
105
- " <th>1</th>\n",
106
- " <td>002920.XSHE</td>\n",
107
- " <td>2021-01-05</td>\n",
108
- " <td>100</td>\n",
109
- " <td>德赛西威</td>\n",
110
- " <td>DSXW</td>\n",
111
- " <td>计算机I 软件开发II 垂直应用软件III 汽车制造业 汽车电子 可选消费</td>\n",
112
- " <td>信息与通信</td>\n",
113
- " </tr>\n",
114
- " <tr>\n",
115
- " <th>2</th>\n",
116
- " <td>300274.XSHE</td>\n",
117
- " <td>2021-01-05</td>\n",
118
- " <td>100</td>\n",
119
- " <td>阳光电源</td>\n",
120
- " <td>YGDY</td>\n",
121
- " <td>电气设备I 光伏设备II 逆变器III 电气机械和器材制造业 光伏设备 工业</td>\n",
122
- " <td>工业</td>\n",
123
- " </tr>\n",
124
- " <tr>\n",
125
- " <th>3</th>\n",
126
- " <td>600409.XSHG</td>\n",
127
- " <td>2021-01-05</td>\n",
128
- " <td>100</td>\n",
129
- " <td>三友化工</td>\n",
130
- " <td>SYHG</td>\n",
131
- " <td>化工I 化学原料II 纯碱III 化学原料和化学制品制造业 粘胶 原材料</td>\n",
132
- " <td>原料与能源</td>\n",
133
- " </tr>\n",
134
- " <tr>\n",
135
- " <th>4</th>\n",
136
- " <td>600415.XSHG</td>\n",
137
- " <td>2021-01-05</td>\n",
138
- " <td>100</td>\n",
139
- " <td>小商品城</td>\n",
140
- " <td>XSPC</td>\n",
141
- " <td>商业贸易I 一般零售II 商业物业经营III 商务服务业 市场服务 工业</td>\n",
142
- " <td>消费</td>\n",
143
- " </tr>\n",
144
- " <tr>\n",
145
- " <th>5</th>\n",
146
- " <td>603882.XSHG</td>\n",
147
- " <td>2021-01-05</td>\n",
148
- " <td>100</td>\n",
149
- " <td>金域医学</td>\n",
150
- " <td>JYYX</td>\n",
151
- " <td>医药生物I 医疗服务II 诊断服务III 卫生 体外诊断 医药卫生</td>\n",
152
- " <td>医药卫生</td>\n",
153
- " </tr>\n",
154
- " </tbody>\n",
155
- "</table>\n",
156
- "</div>"
157
- ],
158
- "text/plain": [
159
- " ticker date weight display_name name \\\n",
160
- "0 002709.XSHE 2021-01-05 100 天赐材料 TCCL \n",
161
- "1 002920.XSHE 2021-01-05 100 德赛西威 DSXW \n",
162
- "2 300274.XSHE 2021-01-05 100 阳光电源 YGDY \n",
163
- "3 600409.XSHG 2021-01-05 100 三友化工 SYHG \n",
164
- "4 600415.XSHG 2021-01-05 100 小商品城 XSPC \n",
165
- "5 603882.XSHG 2021-01-05 100 金域医学 JYYX \n",
166
- "\n",
167
- " sector aggregate_sector \n",
168
- "0 电气设备I 电池II 电池化学品III 化学原料和化学制品制造业 电池部件及材料 工业 工业 \n",
169
- "1 计算机I 软件开发II 垂直应用软件III 汽车制造业 汽车电子 可选消费 信息与通信 \n",
170
- "2 电气设备I 光伏设备II 逆变器III 电气机械和器材制造业 光伏设备 工业 工业 \n",
171
- "3 化工I 化学原料II 纯碱III 化学原料和化学制品制造业 粘胶 原材料 原料与能源 \n",
172
- "4 商业贸易I 一般零售II 商业物业经营III 商务服务业 市场服务 工业 消费 \n",
173
- "5 医药生物I 医疗服务II 诊断服务III 卫生 体外诊断 医药卫生 医药卫生 "
174
- ]
175
- },
176
- "execution_count": 5,
177
- "metadata": {},
178
- "output_type": "execute_result"
179
- }
180
- ],
181
- "source": [
182
- "## load portfolio_profile\n",
183
- "portfolio_profile = pd.read_pickle('../data/portfolio_portfile.pkl')\n",
184
- "portfolio_profile.head(10)"
185
- ]
186
- },
187
- {
188
- "cell_type": "code",
189
- "execution_count": 6,
190
- "metadata": {},
191
- "outputs": [],
192
- "source": [
193
- "start_date = datetime(2021, 1, 5)\n",
194
- "end_date = datetime(2022, 1, 10)"
195
- ]
196
- },
197
- {
198
- "cell_type": "code",
199
- "execution_count": 7,
200
- "metadata": {},
201
- "outputs": [
202
- {
203
- "name": "stdout",
204
- "output_type": "stream",
205
- "text": [
206
- "auth success \n"
207
- ]
208
- }
209
- ],
210
- "source": [
211
- "# get portfolio data\n",
212
- "portfile_data, error = get_portfile_data(portfolio_profile, start_date, end_date)"
213
- ]
214
- },
215
- {
216
- "cell_type": "code",
217
- "execution_count": 8,
218
- "metadata": {},
219
- "outputs": [
220
- {
221
- "name": "stdout",
222
- "output_type": "stream",
223
- "text": [
224
- "[]\n",
225
- "(1482, 8)\n"
226
- ]
227
- },
228
- {
229
- "data": {
230
- "text/html": [
231
- "<div>\n",
232
- "<style scoped>\n",
233
- " .dataframe tbody tr th:only-of-type {\n",
234
- " vertical-align: middle;\n",
235
- " }\n",
236
- "\n",
237
- " .dataframe tbody tr th {\n",
238
- " vertical-align: top;\n",
239
- " }\n",
240
- "\n",
241
- " .dataframe thead th {\n",
242
- " text-align: right;\n",
243
- " }\n",
244
- "</style>\n",
245
- "<table border=\"1\" class=\"dataframe\">\n",
246
- " <thead>\n",
247
- " <tr style=\"text-align: right;\">\n",
248
- " <th></th>\n",
249
- " <th>ticker</th>\n",
250
- " <th>date</th>\n",
251
- " <th>open</th>\n",
252
- " <th>close</th>\n",
253
- " <th>high</th>\n",
254
- " <th>low</th>\n",
255
- " <th>volume</th>\n",
256
- " <th>money</th>\n",
257
- " </tr>\n",
258
- " </thead>\n",
259
- " <tbody>\n",
260
- " <tr>\n",
261
- " <th>2022-01-07</th>\n",
262
- " <td>603882.XSHG</td>\n",
263
- " <td>2022-01-07</td>\n",
264
- " <td>91.13</td>\n",
265
- " <td>87.99</td>\n",
266
- " <td>91.17</td>\n",
267
- " <td>87.72</td>\n",
268
- " <td>6971998.0</td>\n",
269
- " <td>6.176535e+08</td>\n",
270
- " </tr>\n",
271
- " <tr>\n",
272
- " <th>2022-01-07</th>\n",
273
- " <td>002709.XSHE</td>\n",
274
- " <td>2022-01-07</td>\n",
275
- " <td>51.28</td>\n",
276
- " <td>51.72</td>\n",
277
- " <td>52.62</td>\n",
278
- " <td>50.47</td>\n",
279
- " <td>32210458.0</td>\n",
280
- " <td>1.661823e+09</td>\n",
281
- " </tr>\n",
282
- " <tr>\n",
283
- " <th>2022-01-07</th>\n",
284
- " <td>600409.XSHG</td>\n",
285
- " <td>2022-01-07</td>\n",
286
- " <td>8.23</td>\n",
287
- " <td>8.22</td>\n",
288
- " <td>8.29</td>\n",
289
- " <td>8.19</td>\n",
290
- " <td>35003739.0</td>\n",
291
- " <td>2.884990e+08</td>\n",
292
- " </tr>\n",
293
- " <tr>\n",
294
- " <th>2022-01-07</th>\n",
295
- " <td>600415.XSHG</td>\n",
296
- " <td>2022-01-07</td>\n",
297
- " <td>4.74</td>\n",
298
- " <td>4.70</td>\n",
299
- " <td>4.79</td>\n",
300
- " <td>4.68</td>\n",
301
- " <td>24902567.0</td>\n",
302
- " <td>1.178837e+08</td>\n",
303
- " </tr>\n",
304
- " <tr>\n",
305
- " <th>2022-01-10</th>\n",
306
- " <td>300274.XSHE</td>\n",
307
- " <td>2022-01-10</td>\n",
308
- " <td>127.49</td>\n",
309
- " <td>124.09</td>\n",
310
- " <td>127.49</td>\n",
311
- " <td>123.29</td>\n",
312
- " <td>17238708.0</td>\n",
313
- " <td>2.148032e+09</td>\n",
314
- " </tr>\n",
315
- " <tr>\n",
316
- " <th>2022-01-10</th>\n",
317
- " <td>600409.XSHG</td>\n",
318
- " <td>2022-01-10</td>\n",
319
- " <td>8.24</td>\n",
320
- " <td>8.35</td>\n",
321
- " <td>8.39</td>\n",
322
- " <td>8.21</td>\n",
323
- " <td>32516017.0</td>\n",
324
- " <td>2.699300e+08</td>\n",
325
- " </tr>\n",
326
- " <tr>\n",
327
- " <th>2022-01-10</th>\n",
328
- " <td>002920.XSHE</td>\n",
329
- " <td>2022-01-10</td>\n",
330
- " <td>130.36</td>\n",
331
- " <td>138.43</td>\n",
332
- " <td>141.96</td>\n",
333
- " <td>130.11</td>\n",
334
- " <td>5005400.0</td>\n",
335
- " <td>6.901614e+08</td>\n",
336
- " </tr>\n",
337
- " <tr>\n",
338
- " <th>2022-01-10</th>\n",
339
- " <td>002709.XSHE</td>\n",
340
- " <td>2022-01-10</td>\n",
341
- " <td>51.63</td>\n",
342
- " <td>50.73</td>\n",
343
- " <td>51.93</td>\n",
344
- " <td>50.03</td>\n",
345
- " <td>29821246.0</td>\n",
346
- " <td>1.518902e+09</td>\n",
347
- " </tr>\n",
348
- " <tr>\n",
349
- " <th>2022-01-10</th>\n",
350
- " <td>600415.XSHG</td>\n",
351
- " <td>2022-01-10</td>\n",
352
- " <td>4.70</td>\n",
353
- " <td>4.75</td>\n",
354
- " <td>4.85</td>\n",
355
- " <td>4.67</td>\n",
356
- " <td>39278041.0</td>\n",
357
- " <td>1.859827e+08</td>\n",
358
- " </tr>\n",
359
- " <tr>\n",
360
- " <th>2022-01-10</th>\n",
361
- " <td>603882.XSHG</td>\n",
362
- " <td>2022-01-10</td>\n",
363
- " <td>88.45</td>\n",
364
- " <td>95.53</td>\n",
365
- " <td>95.59</td>\n",
366
- " <td>88.39</td>\n",
367
- " <td>6991445.0</td>\n",
368
- " <td>6.468392e+08</td>\n",
369
- " </tr>\n",
370
- " </tbody>\n",
371
- "</table>\n",
372
- "</div>"
373
- ],
374
- "text/plain": [
375
- " ticker date open close high low \\\n",
376
- "2022-01-07 603882.XSHG 2022-01-07 91.13 87.99 91.17 87.72 \n",
377
- "2022-01-07 002709.XSHE 2022-01-07 51.28 51.72 52.62 50.47 \n",
378
- "2022-01-07 600409.XSHG 2022-01-07 8.23 8.22 8.29 8.19 \n",
379
- "2022-01-07 600415.XSHG 2022-01-07 4.74 4.70 4.79 4.68 \n",
380
- "2022-01-10 300274.XSHE 2022-01-10 127.49 124.09 127.49 123.29 \n",
381
- "2022-01-10 600409.XSHG 2022-01-10 8.24 8.35 8.39 8.21 \n",
382
- "2022-01-10 002920.XSHE 2022-01-10 130.36 138.43 141.96 130.11 \n",
383
- "2022-01-10 002709.XSHE 2022-01-10 51.63 50.73 51.93 50.03 \n",
384
- "2022-01-10 600415.XSHG 2022-01-10 4.70 4.75 4.85 4.67 \n",
385
- "2022-01-10 603882.XSHG 2022-01-10 88.45 95.53 95.59 88.39 \n",
386
- "\n",
387
- " volume money \n",
388
- "2022-01-07 6971998.0 6.176535e+08 \n",
389
- "2022-01-07 32210458.0 1.661823e+09 \n",
390
- "2022-01-07 35003739.0 2.884990e+08 \n",
391
- "2022-01-07 24902567.0 1.178837e+08 \n",
392
- "2022-01-10 17238708.0 2.148032e+09 \n",
393
- "2022-01-10 32516017.0 2.699300e+08 \n",
394
- "2022-01-10 5005400.0 6.901614e+08 \n",
395
- "2022-01-10 29821246.0 1.518902e+09 \n",
396
- "2022-01-10 39278041.0 1.859827e+08 \n",
397
- "2022-01-10 6991445.0 6.468392e+08 "
398
- ]
399
- },
400
- "execution_count": 8,
401
- "metadata": {},
402
- "output_type": "execute_result"
403
- }
404
- ],
405
- "source": [
406
- "print(error)\n",
407
- "print(portfile_data.shape)\n",
408
- "portfile_data.sort_values(by=['date'], inplace=True)\n",
409
- "portfile_data.tail(10)"
410
- ]
411
- },
412
- {
413
- "cell_type": "code",
414
- "execution_count": 26,
415
- "metadata": {},
416
- "outputs": [],
417
- "source": [
418
- "# save\n",
419
- "portfile_data.to_pickle('../data/portfolio_data.pkl')"
420
- ]
421
- },
422
- {
423
- "cell_type": "code",
424
- "execution_count": 27,
425
- "metadata": {},
426
- "outputs": [],
427
- "source": [
428
- "# load benchmark portfolio\n",
429
- "benchmark_portfolio, error = get_benchmark_portfolio(start_date, end_date)"
430
- ]
431
- },
432
- {
433
- "cell_type": "code",
434
- "execution_count": 28,
435
- "metadata": {},
436
- "outputs": [
437
- {
438
- "name": "stdout",
439
- "output_type": "stream",
440
- "text": [
441
- "[]\n",
442
- "(185500, 15)\n"
443
- ]
444
- },
445
- {
446
- "data": {
447
- "text/html": [
448
- "<div>\n",
449
- "<style scoped>\n",
450
- " .dataframe tbody tr th:only-of-type {\n",
451
- " vertical-align: middle;\n",
452
- " }\n",
453
- "\n",
454
- " .dataframe tbody tr th {\n",
455
- " vertical-align: top;\n",
456
- " }\n",
457
- "\n",
458
- " .dataframe thead th {\n",
459
- " text-align: right;\n",
460
- " }\n",
461
- "</style>\n",
462
- "<table border=\"1\" class=\"dataframe\">\n",
463
- " <thead>\n",
464
- " <tr style=\"text-align: right;\">\n",
465
- " <th></th>\n",
466
- " <th>date</th>\n",
467
- " <th>weight</th>\n",
468
- " <th>display_name_x</th>\n",
469
- " <th>actual_data</th>\n",
470
- " <th>ticker</th>\n",
471
- " <th>open</th>\n",
472
- " <th>close</th>\n",
473
- " <th>high</th>\n",
474
- " <th>low</th>\n",
475
- " <th>volume</th>\n",
476
- " <th>money</th>\n",
477
- " <th>display_name_y</th>\n",
478
- " <th>name</th>\n",
479
- " <th>sector</th>\n",
480
- " <th>aggregate_sector</th>\n",
481
- " </tr>\n",
482
- " </thead>\n",
483
- " <tbody>\n",
484
- " <tr>\n",
485
- " <th>185163</th>\n",
486
- " <td>2022-01-10</td>\n",
487
- " <td>0.274</td>\n",
488
- " <td>厦门钨业</td>\n",
489
- " <td>2021-12-31</td>\n",
490
- " <td>600549.XSHG</td>\n",
491
- " <td>21.50</td>\n",
492
- " <td>21.59</td>\n",
493
- " <td>21.75</td>\n",
494
- " <td>21.43</td>\n",
495
- " <td>10451128.0</td>\n",
496
- " <td>2.254199e+08</td>\n",
497
- " <td>厦门钨业</td>\n",
498
- " <td>XMWY</td>\n",
499
- " <td>有色金属I 稀有金属II 钨III 有色金属冶炼和压延加工业 钨钼 原材料</td>\n",
500
- " <td>原料与能源</td>\n",
501
- " </tr>\n",
502
- " <tr>\n",
503
- " <th>185162</th>\n",
504
- " <td>2022-01-10</td>\n",
505
- " <td>0.116</td>\n",
506
- " <td>山煤国际</td>\n",
507
- " <td>2021-12-31</td>\n",
508
- " <td>600546.XSHG</td>\n",
509
- " <td>6.74</td>\n",
510
- " <td>6.86</td>\n",
511
- " <td>6.86</td>\n",
512
- " <td>6.71</td>\n",
513
- " <td>66929559.0</td>\n",
514
- " <td>4.539690e+08</td>\n",
515
- " <td>山煤国际</td>\n",
516
- " <td>SMGJ</td>\n",
517
- " <td>煤炭I 煤炭开采II 动力煤III 批发业 煤炭 能源</td>\n",
518
- " <td>原料与能源</td>\n",
519
- " </tr>\n",
520
- " <tr>\n",
521
- " <th>185161</th>\n",
522
- " <td>2022-01-10</td>\n",
523
- " <td>0.211</td>\n",
524
- " <td>中国软件</td>\n",
525
- " <td>2021-12-31</td>\n",
526
- " <td>600536.XSHG</td>\n",
527
- " <td>29.01</td>\n",
528
- " <td>30.90</td>\n",
529
- " <td>31.45</td>\n",
530
- " <td>28.98</td>\n",
531
- " <td>35489167.0</td>\n",
532
- " <td>1.087404e+09</td>\n",
533
- " <td>中国软件</td>\n",
534
- " <td>ZGRJ</td>\n",
535
- " <td>计算机I IT服务II IT服务III 软件和信息技术服务业 行业应用软件 信息技术</td>\n",
536
- " <td>信息与通信</td>\n",
537
- " </tr>\n",
538
- " <tr>\n",
539
- " <th>185160</th>\n",
540
- " <td>2022-01-10</td>\n",
541
- " <td>0.205</td>\n",
542
- " <td>天士力</td>\n",
543
- " <td>2021-12-31</td>\n",
544
- " <td>600535.XSHG</td>\n",
545
- " <td>15.04</td>\n",
546
- " <td>15.52</td>\n",
547
- " <td>15.75</td>\n",
548
- " <td>14.95</td>\n",
549
- " <td>46823950.0</td>\n",
550
- " <td>7.247465e+08</td>\n",
551
- " <td>天士力</td>\n",
552
- " <td>TSL</td>\n",
553
- " <td>医药生物I 中药II 中药III 医药制造业 中成药 医药卫生</td>\n",
554
- " <td>医药卫生</td>\n",
555
- " </tr>\n",
556
- " <tr>\n",
557
- " <th>185159</th>\n",
558
- " <td>2022-01-10</td>\n",
559
- " <td>0.297</td>\n",
560
- " <td>山东药玻</td>\n",
561
- " <td>2021-12-31</td>\n",
562
- " <td>600529.XSHG</td>\n",
563
- " <td>42.39</td>\n",
564
- " <td>40.14</td>\n",
565
- " <td>42.39</td>\n",
566
- " <td>39.47</td>\n",
567
- " <td>12543641.0</td>\n",
568
- " <td>5.049473e+08</td>\n",
569
- " <td>山东药玻</td>\n",
570
- " <td>SDYB</td>\n",
571
- " <td>医药生物I 医疗器械II 医疗耗材III 非金属矿物制品业 医疗耗材 医药卫生</td>\n",
572
- " <td>医药卫生</td>\n",
573
- " </tr>\n",
574
- " <tr>\n",
575
- " <th>185158</th>\n",
576
- " <td>2022-01-10</td>\n",
577
- " <td>0.156</td>\n",
578
- " <td>中铁工业</td>\n",
579
- " <td>2021-12-31</td>\n",
580
- " <td>600528.XSHG</td>\n",
581
- " <td>8.69</td>\n",
582
- " <td>9.08</td>\n",
583
- " <td>9.26</td>\n",
584
- " <td>8.68</td>\n",
585
- " <td>98213530.0</td>\n",
586
- " <td>8.961637e+08</td>\n",
587
- " <td>中铁工业</td>\n",
588
- " <td>ZTGY</td>\n",
589
- " <td>机械设备I 运输设备II 铁路设备III 专用设备制造业 城轨铁路 工业</td>\n",
590
- " <td>工业</td>\n",
591
- " </tr>\n",
592
- " <tr>\n",
593
- " <th>185157</th>\n",
594
- " <td>2022-01-10</td>\n",
595
- " <td>0.642</td>\n",
596
- " <td>中天科技</td>\n",
597
- " <td>2021-12-31</td>\n",
598
- " <td>600522.XSHG</td>\n",
599
- " <td>15.21</td>\n",
600
- " <td>14.76</td>\n",
601
- " <td>15.26</td>\n",
602
- " <td>14.53</td>\n",
603
- " <td>112744173.0</td>\n",
604
- " <td>1.670952e+09</td>\n",
605
- " <td>中天科技</td>\n",
606
- " <td>ZTKJ</td>\n",
607
- " <td>通信I 通信设备II 通信线缆及配套III 电气机械和器材制造业 通信系统设备及组件 通信服务</td>\n",
608
- " <td>信息与通信</td>\n",
609
- " </tr>\n",
610
- " <tr>\n",
611
- " <th>185156</th>\n",
612
- " <td>2022-01-10</td>\n",
613
- " <td>0.276</td>\n",
614
- " <td>华海药业</td>\n",
615
- " <td>2021-12-31</td>\n",
616
- " <td>600521.XSHG</td>\n",
617
- " <td>22.32</td>\n",
618
- " <td>23.32</td>\n",
619
- " <td>23.43</td>\n",
620
- " <td>21.90</td>\n",
621
- " <td>29810065.0</td>\n",
622
- " <td>6.827298e+08</td>\n",
623
- " <td>华海药业</td>\n",
624
- " <td>HHYY</td>\n",
625
- " <td>医药生物I 化学制药II 化学制剂III 医药制造业 药品制剂 医药卫生</td>\n",
626
- " <td>医药卫生</td>\n",
627
- " </tr>\n",
628
- " <tr>\n",
629
- " <th>185169</th>\n",
630
- " <td>2022-01-10</td>\n",
631
- " <td>0.240</td>\n",
632
- " <td>卧龙电驱</td>\n",
633
- " <td>2021-12-31</td>\n",
634
- " <td>600580.XSHG</td>\n",
635
- " <td>16.66</td>\n",
636
- " <td>16.51</td>\n",
637
- " <td>16.68</td>\n",
638
- " <td>16.23</td>\n",
639
- " <td>19294606.0</td>\n",
640
- " <td>3.175398e+08</td>\n",
641
- " <td>卧龙电驱</td>\n",
642
- " <td>WLDQ</td>\n",
643
- " <td>电气设备I 电机II 电机III 电气机械和器材制造业 电动机与工控自动化 工业</td>\n",
644
- " <td>工业</td>\n",
645
- " </tr>\n",
646
- " <tr>\n",
647
- " <th>185499</th>\n",
648
- " <td>2022-01-10</td>\n",
649
- " <td>0.350</td>\n",
650
- " <td>思瑞浦</td>\n",
651
- " <td>2021-12-31</td>\n",
652
- " <td>688536.XSHG</td>\n",
653
- " <td>476.70</td>\n",
654
- " <td>463.10</td>\n",
655
- " <td>476.70</td>\n",
656
- " <td>446.03</td>\n",
657
- " <td>924992.0</td>\n",
658
- " <td>4.254053e+08</td>\n",
659
- " <td>思瑞浦</td>\n",
660
- " <td>SRP</td>\n",
661
- " <td>电子I 半导体II 模拟芯片设计III 软件和信息技术服务业 集成电路设计 信息技术</td>\n",
662
- " <td>信息与通信</td>\n",
663
- " </tr>\n",
664
- " </tbody>\n",
665
- "</table>\n",
666
- "</div>"
667
- ],
668
- "text/plain": [
669
- " date weight display_name_x actual_data ticker open \\\n",
670
- "185163 2022-01-10 0.274 厦门钨业 2021-12-31 600549.XSHG 21.50 \n",
671
- "185162 2022-01-10 0.116 山煤国际 2021-12-31 600546.XSHG 6.74 \n",
672
- "185161 2022-01-10 0.211 中国软件 2021-12-31 600536.XSHG 29.01 \n",
673
- "185160 2022-01-10 0.205 天士力 2021-12-31 600535.XSHG 15.04 \n",
674
- "185159 2022-01-10 0.297 山东药玻 2021-12-31 600529.XSHG 42.39 \n",
675
- "185158 2022-01-10 0.156 中铁工业 2021-12-31 600528.XSHG 8.69 \n",
676
- "185157 2022-01-10 0.642 中天科技 2021-12-31 600522.XSHG 15.21 \n",
677
- "185156 2022-01-10 0.276 华海药业 2021-12-31 600521.XSHG 22.32 \n",
678
- "185169 2022-01-10 0.240 卧龙电驱 2021-12-31 600580.XSHG 16.66 \n",
679
- "185499 2022-01-10 0.350 思瑞浦 2021-12-31 688536.XSHG 476.70 \n",
680
- "\n",
681
- " close high low volume money display_name_y \\\n",
682
- "185163 21.59 21.75 21.43 10451128.0 2.254199e+08 厦门钨业 \n",
683
- "185162 6.86 6.86 6.71 66929559.0 4.539690e+08 山煤国际 \n",
684
- "185161 30.90 31.45 28.98 35489167.0 1.087404e+09 中国软件 \n",
685
- "185160 15.52 15.75 14.95 46823950.0 7.247465e+08 天士力 \n",
686
- "185159 40.14 42.39 39.47 12543641.0 5.049473e+08 山东药玻 \n",
687
- "185158 9.08 9.26 8.68 98213530.0 8.961637e+08 中铁工业 \n",
688
- "185157 14.76 15.26 14.53 112744173.0 1.670952e+09 中天科技 \n",
689
- "185156 23.32 23.43 21.90 29810065.0 6.827298e+08 华海药业 \n",
690
- "185169 16.51 16.68 16.23 19294606.0 3.175398e+08 卧龙电驱 \n",
691
- "185499 463.10 476.70 446.03 924992.0 4.254053e+08 思瑞浦 \n",
692
- "\n",
693
- " name sector aggregate_sector \n",
694
- "185163 XMWY 有色金属I 稀有金属II 钨III 有色金属冶炼和压延加工业 钨钼 原材料 原料与能源 \n",
695
- "185162 SMGJ 煤炭I 煤炭开采II 动力煤III 批发业 煤炭 能源 原料与能源 \n",
696
- "185161 ZGRJ 计算机I IT服务II IT服务III 软件和信息技术服务业 行业应用软件 信息技术 信息与通信 \n",
697
- "185160 TSL 医药生物I 中药II 中药III 医药制造业 中成药 医药卫生 医药卫生 \n",
698
- "185159 SDYB 医药生物I 医疗器械II 医疗耗材III 非金属矿物制品业 医疗耗材 医药卫生 医药卫生 \n",
699
- "185158 ZTGY 机械设备I 运输设备II 铁路设备III 专用设备制造业 城轨铁路 工业 工业 \n",
700
- "185157 ZTKJ 通信I 通信设备II 通信线缆及配套III 电气机械和器材制造业 通信系统设备及组件 通信服务 信息与通信 \n",
701
- "185156 HHYY 医药生物I 化学制药II 化学制剂III 医药制造业 药品制剂 医药卫生 医药卫生 \n",
702
- "185169 WLDQ 电气设备I 电机II 电机III 电气机械和器材制造业 电动机与工控自动化 工业 工业 \n",
703
- "185499 SRP 电子I 半导体II 模拟芯片设计III 软件和信息技术服务业 集成电路设计 信息技术 信息与通信 "
704
- ]
705
- },
706
- "execution_count": 28,
707
- "metadata": {},
708
- "output_type": "execute_result"
709
- }
710
- ],
711
- "source": [
712
- "print(error)\n",
713
- "print(benchmark_portfolio.shape)\n",
714
- "benchmark_portfolio.sort_values(by=['date'], inplace=True)\n",
715
- "benchmark_portfolio.tail(10)\n"
716
- ]
717
- },
718
- {
719
- "cell_type": "code",
720
- "execution_count": 29,
721
- "metadata": {},
722
- "outputs": [],
723
- "source": [
724
- "# save\n",
725
- "benchmark_portfolio.to_pickle('../data/benchmark_portfolio.pkl')"
726
- ]
727
- }
728
- ],
729
- "metadata": {
730
- "kernelspec": {
731
- "display_name": "portfolio_risk_assesment",
732
- "language": "python",
733
- "name": "python3"
734
- },
735
- "language_info": {
736
- "codemirror_mode": {
737
- "name": "ipython",
738
- "version": 3
739
- },
740
- "file_extension": ".py",
741
- "mimetype": "text/x-python",
742
- "name": "python",
743
- "nbconvert_exporter": "python",
744
- "pygments_lexer": "ipython3",
745
- "version": "3.11.4"
746
- },
747
- "orig_nbformat": 4
748
- },
749
- "nbformat": 4,
750
- "nbformat_minor": 2
751
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/downloadData.py DELETED
@@ -1,10 +0,0 @@
1
- import pandas as pd
2
- from api import update_portfolio_profile, get_stocks_price, get_benchmark_portfolio
3
-
4
- portfolio_profile_data = [
5
-
6
- ]
7
-
8
-
9
- def main():
10
- # create a portfolio
 
 
 
 
 
 
 
 
 
 
 
script/pipeline.ipynb DELETED
@@ -1,521 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 36,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "import pandas as pd\n",
10
- "import math\n",
11
- "from datetime import datetime\n",
12
- "import hvplot.pandas\n",
13
- "import math\n",
14
- "import numpy as np\n",
15
- "# load data\n",
16
- "profile_df = pd.read_pickle('../data/portfolio_portfile.pkl')\n",
17
- "benchmark_df = pd.read_pickle('../data/benchmark_portfolio.pkl')\n",
18
- "portfolio_df = pd.read_pickle('../data/portfolio_data.pkl')"
19
- ]
20
- },
21
- {
22
- "attachments": {},
23
- "cell_type": "markdown",
24
- "metadata": {},
25
- "source": [
26
- "## This section transfrom benchmark_df and creat an benchmark profile to accomadate current pipeline"
27
- ]
28
- },
29
- {
30
- "cell_type": "code",
31
- "execution_count": 37,
32
- "metadata": {},
33
- "outputs": [],
34
- "source": [
35
- "# drop weight\n",
36
- "# benchmark_df = benchmark_df.drop(columns=['weight'])\n",
37
- "\n",
38
- "## simulate update potfolio weigth at 2021-01-10\n",
39
- "update_profile_df = profile_df.copy()\n",
40
- "update_profile_df['date'] = datetime(2021,1,10)\n",
41
- "update_profile_df['weight'] = [50,100,200,300,400,500]\n",
42
- "profile_df = pd.concat([profile_df, update_profile_df])\n"
43
- ]
44
- },
45
- {
46
- "cell_type": "code",
47
- "execution_count": 38,
48
- "metadata": {},
49
- "outputs": [],
50
- "source": [
51
- "## create a profile for benchmark\n",
52
- "b_profile = benchmark_df.drop_duplicates(subset=['ticker', 'actual_data'])\n",
53
- "# df_unique[df_unique.ticker == \"000008.XSHE\"]\n",
54
- "# only keep ticker\tdate\tweight\tdisplay_name\tname\tsector\taggregate_sector column\n",
55
- "b_profile = b_profile[['ticker','date','weight','name','sector','aggregate_sector','display_name_x']]\n",
56
- "b_profile.rename(columns={'display_name_x': 'display_name'}, inplace=True)"
57
- ]
58
- },
59
- {
60
- "cell_type": "code",
61
- "execution_count": 39,
62
- "metadata": {},
63
- "outputs": [
64
- {
65
- "data": {
66
- "text/html": [
67
- "<div>\n",
68
- "<style scoped>\n",
69
- " .dataframe tbody tr th:only-of-type {\n",
70
- " vertical-align: middle;\n",
71
- " }\n",
72
- "\n",
73
- " .dataframe tbody tr th {\n",
74
- " vertical-align: top;\n",
75
- " }\n",
76
- "\n",
77
- " .dataframe thead th {\n",
78
- " text-align: right;\n",
79
- " }\n",
80
- "</style>\n",
81
- "<table border=\"1\" class=\"dataframe\">\n",
82
- " <thead>\n",
83
- " <tr style=\"text-align: right;\">\n",
84
- " <th></th>\n",
85
- " <th>date</th>\n",
86
- " <th>ticker</th>\n",
87
- " <th>open</th>\n",
88
- " <th>close</th>\n",
89
- " <th>high</th>\n",
90
- " <th>low</th>\n",
91
- " <th>volume</th>\n",
92
- " <th>money</th>\n",
93
- " </tr>\n",
94
- " </thead>\n",
95
- " <tbody>\n",
96
- " <tr>\n",
97
- " <th>0</th>\n",
98
- " <td>2021-01-05</td>\n",
99
- " <td>000008.XSHE</td>\n",
100
- " <td>2.52</td>\n",
101
- " <td>2.57</td>\n",
102
- " <td>2.67</td>\n",
103
- " <td>2.49</td>\n",
104
- " <td>33215803.0</td>\n",
105
- " <td>85358605.99</td>\n",
106
- " </tr>\n",
107
- " </tbody>\n",
108
- "</table>\n",
109
- "</div>"
110
- ],
111
- "text/plain": [
112
- " date ticker open close high low volume money\n",
113
- "0 2021-01-05 000008.XSHE 2.52 2.57 2.67 2.49 33215803.0 85358605.99"
114
- ]
115
- },
116
- "execution_count": 39,
117
- "metadata": {},
118
- "output_type": "execute_result"
119
- }
120
- ],
121
- "source": [
122
- "# drop weight in benchmark\n",
123
- "benchmark_df = benchmark_df.drop(columns=['weight'])\n",
124
- "benchmark_df = benchmark_df.drop(columns=['display_name_x'])\n",
125
- "# drop display_name_y\n",
126
- "benchmark_df = benchmark_df.drop(columns=['display_name_y'])\n",
127
- "# drop actual_data\n",
128
- "benchmark_df = benchmark_df.drop(columns=['actual_data'])\n",
129
- "# drop name\n",
130
- "benchmark_df = benchmark_df.drop(columns=['name'])\n",
131
- "# drop aggregate_sector\n",
132
- "benchmark_df = benchmark_df.drop(columns=['aggregate_sector'])\n",
133
- "# drop sector\n",
134
- "benchmark_df = benchmark_df.drop(columns=['sector'])\n",
135
- "benchmark_df.head(1)"
136
- ]
137
- },
138
- {
139
- "cell_type": "code",
140
- "execution_count": 40,
141
- "metadata": {},
142
- "outputs": [],
143
- "source": [
144
- "for col_name in benchmark_df.columns:\n",
145
- " if (col_name not in portfolio_df.columns):\n",
146
- " print(f'portfolio does not have {col_name}')\n",
147
- " \n",
148
- "\n",
149
- "for col_name in portfolio_df.columns:\n",
150
- " if (col_name not in benchmark_df.columns):\n",
151
- " print(f'benchmark does not have {col_name}')"
152
- ]
153
- },
154
- {
155
- "cell_type": "code",
156
- "execution_count": 41,
157
- "metadata": {},
158
- "outputs": [
159
- {
160
- "name": "stdout",
161
- "output_type": "stream",
162
- "text": [
163
- "True\n",
164
- "True\n",
165
- "True\n",
166
- "True\n",
167
- "True\n",
168
- "True\n",
169
- "True\n",
170
- "True\n",
171
- "True\n",
172
- "True\n",
173
- "True\n",
174
- "True\n",
175
- "True\n",
176
- "True\n"
177
- ]
178
- }
179
- ],
180
- "source": [
181
- "for col_name in b_profile.columns:\n",
182
- " print(col_name in profile_df.columns)\n",
183
- "\n",
184
- "for col_name in profile_df.columns:\n",
185
- " print(col_name in b_profile.columns)"
186
- ]
187
- },
188
- {
189
- "attachments": {},
190
- "cell_type": "markdown",
191
- "metadata": {},
192
- "source": [
193
- "## calculate result for each individual stock this part should return a table"
194
- ]
195
- },
196
- {
197
- "cell_type": "code",
198
- "execution_count": 42,
199
- "metadata": {},
200
- "outputs": [],
201
- "source": [
202
- "def get_processing_result_of_stocks_df(stock_df, profile_df):\n",
203
- " ## add sector_name display_name name\n",
204
- " ticker_sector_map = dict(zip(profile_df['ticker'], profile_df['aggregate_sector']))\n",
205
- " ticker_display_name_map = dict(zip(profile_df['ticker'], profile_df['display_name']))\n",
206
- " ticker_name_map = dict(zip(profile_df['ticker'], profile_df['name']))\n",
207
- "\n",
208
- " stock_df['display_name'] = stock_df['ticker'].map(ticker_display_name_map)\n",
209
- " stock_df['name'] = stock_df['ticker'].map(ticker_name_map)\n",
210
- " stock_df['aggregate_sector'] = stock_df['ticker'].map(ticker_sector_map)\n",
211
- "\n",
212
- " ## calculate pct using closing price\n",
213
- " stock_df.sort_values(by=['date'], inplace=True)\n",
214
- " stock_df['pct'] = stock_df.groupby('ticker')['close'].pct_change()\n",
215
- "\n",
216
- " ## calculate weight TODO: think about how to optimize this\n",
217
- " stock_df = stock_df.merge(profile_df[['weight', 'date', 'ticker']], on=['ticker', 'date'], how='outer')\n",
218
- " stock_df.rename(columns={'weight': 'initial_weight'}, inplace=True)\n",
219
- " stock_df['current_weight'] = float('nan')\n",
220
- " stock_df['previous_weight'] = float('nan')\n",
221
- " df_grouped = stock_df.groupby('ticker')\n",
222
- " for _, group in df_grouped:\n",
223
- " pre_w = float('nan')\n",
224
- " ini_w = float('nan')\n",
225
- " for index, row in group.iterrows():\n",
226
- " cur_w = float('nan')\n",
227
- "\n",
228
- " # if has initial weight, the following row all use this initial weight\n",
229
- " if not pd.isna(row['initial_weight']):\n",
230
- " ini_w = row['initial_weight']\n",
231
- " cur_w = ini_w\n",
232
- "\n",
233
- " # just calculate current weight based on previous weight\n",
234
- " else:\n",
235
- " cur_w = pre_w * (1 + row['pct'])\n",
236
- "\n",
237
- " stock_df.loc[index, 'current_weight'] = cur_w \n",
238
- " stock_df.loc[index, 'previous_weight'] = pre_w\n",
239
- " stock_df.loc[index, 'initial_weight'] = ini_w\n",
240
- " pre_w = cur_w\n",
241
- "\n",
242
- " stock_df.rename(columns={'weight': 'initial_weight'}, inplace=True)\n",
243
- " stock_df.dropna(subset=['close'], inplace=True)\n",
244
- "\n",
245
- " ## normalize weight\n",
246
- " stock_df['prev_w_in_p'] = stock_df['previous_weight'] / \\\n",
247
- " stock_df.groupby('date')['previous_weight'].transform('sum')\n",
248
- "\n",
249
- " stock_df['ini_w_in_p'] = stock_df['initial_weight'] / \\\n",
250
- " stock_df.groupby('date')['initial_weight'].transform('sum')\n",
251
- "\n",
252
- " ## calculate weighted pct in portfolio\n",
253
- " stock_df['portfolio_pct'] = stock_df['pct'] * stock_df['prev_w_in_p']\n",
254
- "\n",
255
- " ## calculate weight in sector TODO: remove\n",
256
- " stock_df['prev_w_in_sectore'] = stock_df['previous_weight'] / \\\n",
257
- " stock_df.groupby(['date', 'aggregate_sector'])['previous_weight'].transform('sum')\n",
258
- " stock_df['ini_w_in_sector'] = stock_df['initial_weight'] / \\\n",
259
- " stock_df.groupby(['date', 'aggregate_sector'])['initial_weight'].transform('sum')\n",
260
- " ## weighted pct in sector TODO: remove\n",
261
- " stock_df['sector_pct'] = stock_df['pct'] * stock_df['prev_w_in_sectore']\n",
262
- "\n",
263
- " ## portfolio return\n",
264
- " stock_df['cum_p_pct'] = stock_df.groupby('ticker')['portfolio_pct'].cumsum()\n",
265
- " stock_df['portfolio_return'] = np.exp(stock_df['cum_p_pct']) -1 \n",
266
- " # drop intermediate columns\n",
267
- " stock_df = stock_df.drop(columns=['cum_p_pct'])\n",
268
- "\n",
269
- "\n",
270
- " ## sector return TODO:remove \n",
271
- " # stock_df['sector_return'] = stock_df['ini_w_in_sector'] * stock_df['return']\n",
272
- "\n",
273
- " return stock_df\n"
274
- ]
275
- },
276
- {
277
- "cell_type": "code",
278
- "execution_count": 43,
279
- "metadata": {},
280
- "outputs": [],
281
- "source": [
282
- "# portfolio_stock = get_processing_result_of_stocks_df(portfolio_df, profile_df)\n",
283
- "# portfolio_stock[portfolio_stock.ticker == '002709.XSHE'][['date','portfolio_pct','prev_w_in_p','portfolio_return']]\n",
284
- "# # benchmark_stock = get_processing_result_of_stocks_df(benchmark_df, b_profile)"
285
- ]
286
- },
287
- {
288
- "cell_type": "code",
289
- "execution_count": 44,
290
- "metadata": {},
291
- "outputs": [],
292
- "source": [
293
- "# profile_df.groupby('date')['weight'].sum()"
294
- ]
295
- },
296
- {
297
- "cell_type": "code",
298
- "execution_count": 45,
299
- "metadata": {},
300
- "outputs": [],
301
- "source": [
302
- "## total return by date\n",
303
- "def get_portfolio_evaluation(portfolio_stock, benchmark_stock, profile_df):\n",
304
- " # add pct of benchmark \n",
305
- " merged_df = portfolio_stock.merge(benchmark_stock[['ticker','date','portfolio_pct','portfolio_return']], \n",
306
- " on=['ticker','date'],how='left',suffixes=('_p','_b'))\n",
307
- "\n",
308
- " # sum up pct and return from portfolio and benchmark\n",
309
- " merged_df = merged_df.groupby('date',as_index=False).agg({'portfolio_return_p':'sum',\n",
310
- " 'portfolio_return_b':'sum',\n",
311
- " 'portfolio_pct_p':'sum',\n",
312
- " 'portfolio_pct_b':'sum'})\n",
313
- "\n",
314
- " # portfolio mkt cap\n",
315
- " mkt_adjustment = pd.DataFrame(profile_df.groupby('date')['weight'].sum())\n",
316
- " mkt_adjustment.rename(columns={'weight':'mkt_cap'}, inplace=True)\n",
317
- " merged_df = merged_df.merge(mkt_adjustment, on=['date'], how='outer')\n",
318
- "\n",
319
- " for i in range(len(merged_df)):\n",
320
- " if pd.isna(merged_df.loc[i, 'mkt_cap']):\n",
321
- " merged_df.loc[i, 'mkt_cap'] = merged_df.loc[i-1, 'mkt_cap'] * (1 + merged_df.loc[i, 'portfolio_pct_p'])\n",
322
- " # drop where portfolio_return_p is nan\n",
323
- " merged_df.dropna(subset=['portfolio_return_p'], inplace=True)\n",
324
- " # portfolio pnl TODO seem I can just use current wegith to do this\n",
325
- " merged_df['prev_mkt_cap'] = merged_df['mkt_cap'].shift(1)\n",
326
- " merged_df['pnl'] = merged_df['prev_mkt_cap'] * merged_df['portfolio_pct_p']\n",
327
- "\n",
328
- " # risk std(pct)\n",
329
- " merged_df['risk'] = merged_df['portfolio_pct_p'].rolling(len(merged_df), min_periods=1).std() * math.sqrt(252)\n",
330
- "\n",
331
- " # active return\n",
332
- " merged_df['active_return'] = merged_df['portfolio_pct_p'] - merged_df['portfolio_pct_b']\n",
333
- "\n",
334
- " # tracking errro std(active return)\n",
335
- " merged_df['tracking_error'] = merged_df['active_return'].rolling(len(merged_df), min_periods=1).std() * math.sqrt(252)\n",
336
- "\n",
337
- " # cum pnl\n",
338
- " merged_df['cum_pnl'] = merged_df['pnl'].cumsum()\n",
339
- "\n",
340
- " return merged_df\n"
341
- ]
342
- },
343
- {
344
- "cell_type": "code",
345
- "execution_count": 46,
346
- "metadata": {},
347
- "outputs": [],
348
- "source": [
349
- "# portfolio_eval_df = get_portfolio_evaluation(portfolio_stock, benchmark_stock, profile_df)"
350
- ]
351
- },
352
- {
353
- "cell_type": "code",
354
- "execution_count": 47,
355
- "metadata": {},
356
- "outputs": [],
357
- "source": [
358
- "# portfolio_stock.columns"
359
- ]
360
- },
361
- {
362
- "cell_type": "code",
363
- "execution_count": 48,
364
- "metadata": {},
365
- "outputs": [],
366
- "source": [
367
- "## TODO convert below to funciton\n",
368
- "\n",
369
- "def get_portfolio_sector_evaluation(portfolio_stock,benchmark_df):\n",
370
- "# aggregate on sector and day\n",
371
- " p_sector_df = portfolio_stock.groupby(['date','aggregate_sector'], as_index=False)\\\n",
372
- " .agg({'prev_w_in_p': 'sum','ini_w_in_p':\"sum\",\"current_weight\":'sum',\\\n",
373
- " \"portfolio_pct\":\"sum\", \"portfolio_return\":\"sum\"})\n",
374
- " # TODO shrink it down before aggregate\n",
375
- " b_sector_df = benchmark_df.groupby(['date','aggregate_sector'], as_index=False)\\\n",
376
- " .agg({'prev_w_in_p': 'sum','ini_w_in_p':\"sum\",\"current_weight\":'sum',\\\n",
377
- " \"portfolio_pct\":\"sum\", \"portfolio_return\":\"sum\"})\n",
378
- " \n",
379
- " # merge portfolio and benchmark\n",
380
- " merge_df = p_sector_df.merge(b_sector_df, on=['date','aggregate_sector'], how='left', suffixes=('_p','_b'))\n",
381
- "\n",
382
- " return merge_df"
383
- ]
384
- },
385
- {
386
- "cell_type": "code",
387
- "execution_count": 49,
388
- "metadata": {},
389
- "outputs": [],
390
- "source": [
391
- "# sector_eval_df = get_portfolio_sector_evaluation(portfolio_stock, benchmark_stock)\n",
392
- "# sector_eval_df[sector_eval_df.date == datetime(2021, 10,13)].hvplot.bar(x='aggregate_sector', y=['portfolio_pct_p','portfolio_pct_b'], stacked=True, rot=90, title='sector pct')"
393
- ]
394
- },
395
- {
396
- "cell_type": "code",
397
- "execution_count": 50,
398
- "metadata": {},
399
- "outputs": [],
400
- "source": [
401
- "def merge_on_date(portfolio_stock, benchmark_df):\n",
402
- " p_selected = portfolio_stock.reset_index()[['ini_w_in_p', 'portfolio_return', 'date', 'ticker', 'display_name']]\n",
403
- " b_selected = benchmark_df.reset_index()[['ini_w_in_p', 'portfolio_return', 'date', 'ticker']]\n",
404
- " merged_stock_df = pd.merge(p_selected, b_selected, on=['date', 'ticker'], how='outer', suffixes=('_p', '_b'))\n",
405
- " return merged_stock_df"
406
- ]
407
- },
408
- {
409
- "cell_type": "code",
410
- "execution_count": 51,
411
- "metadata": {},
412
- "outputs": [],
413
- "source": [
414
- "# merged_df = merge_on_date(portfolio_stock, benchmark_stock)"
415
- ]
416
- },
417
- {
418
- "cell_type": "code",
419
- "execution_count": 52,
420
- "metadata": {},
421
- "outputs": [],
422
- "source": [
423
- "def get_bhb_result(merged_stock_df):\n",
424
- " # merged_stock_df['ini_w_in_p_p'].fillna(0, inplace=True)\n",
425
- " # merged_stock_df['ini_w_in_p_b'].fillna(0, inplace=True)\n",
426
- " # merged_stock_df['portfolio_return_b'].fillna(0, inplace=True)\n",
427
- " # merged_stock_df['portfolio_return_p'].fillna(0, inplace=True)\n",
428
- " # allocation\n",
429
- " merged_stock_df['allocation'] = (merged_stock_df['ini_w_in_p_p'] - merged_stock_df['ini_w_in_p_b']) \\\n",
430
- " * merged_stock_df['portfolio_return_b']\n",
431
- "\n",
432
- " # selection\n",
433
- " merged_stock_df['selection'] = merged_stock_df['ini_w_in_p_b'] * \\\n",
434
- " (merged_stock_df['portfolio_return_p'] - merged_stock_df['portfolio_return_b'])\n",
435
- "\n",
436
- " # interaction\n",
437
- " merged_stock_df['interaction'] = (merged_stock_df['ini_w_in_p_p'] - merged_stock_df['ini_w_in_p_b']) * \\\n",
438
- " (merged_stock_df['portfolio_return_p'] - merged_stock_df['portfolio_return_b'])\n",
439
- "\n",
440
- " # excess\n",
441
- " merged_stock_df['excess'] = merged_stock_df['portfolio_return_p'] - merged_stock_df['portfolio_return_b']\n",
442
- "\n",
443
- " # replace inf with nan\n",
444
- " merged_stock_df.replace([np.inf, -np.inf], np.nan, inplace=True)\n",
445
- " return merged_stock_df"
446
- ]
447
- },
448
- {
449
- "cell_type": "code",
450
- "execution_count": 53,
451
- "metadata": {},
452
- "outputs": [],
453
- "source": [
454
- "# test ing pipeline here "
455
- ]
456
- },
457
- {
458
- "cell_type": "code",
459
- "execution_count": 54,
460
- "metadata": {},
461
- "outputs": [],
462
- "source": [
463
- "portfolio_stock = get_processing_result_of_stocks_df(portfolio_df, profile_df)\n",
464
- "benchmark_stock = get_processing_result_of_stocks_df(benchmark_df, b_profile)\n",
465
- "\n",
466
- "portfolio_eval_df = get_portfolio_evaluation(portfolio_stock, benchmark_stock, profile_df)\n",
467
- "sector_eval_df = get_portfolio_sector_evaluation(portfolio_stock, benchmark_stock)\n",
468
- "merged_df = merge_on_date(portfolio_stock, benchmark_stock)\n",
469
- "bnb_sector_result = get_bhb_result(sector_eval_df)\n",
470
- "bnb_stock_result = get_bhb_result(merged_df)\n"
471
- ]
472
- },
473
- {
474
- "cell_type": "code",
475
- "execution_count": null,
476
- "metadata": {},
477
- "outputs": [],
478
- "source": [
479
- "# save result \n",
480
- "portfolio_eval_df.to_pickle('../data/portfolio_eval_df.pkl')\n",
481
- "sector_eval_df.to_pickle('../data/sector_eval_df.pkl')\n",
482
- "# merged_df.to_csv('merged_df.csv')\n",
483
- "bnb_sector_result.to_pickle('../data/bnb_sector_result.pkl')\n",
484
- "bnb_stock_result.to_pickle('../data/bnb_stock_result.pkl')\n",
485
- "profile_df.to_pickle('../data/protfolio_profile.pkl')\n",
486
- "b_profile.to_pickle('../data/benchmark_profile.pkl')"
487
- ]
488
- },
489
- {
490
- "cell_type": "code",
491
- "execution_count": null,
492
- "metadata": {},
493
- "outputs": [],
494
- "source": [
495
- "# bnb_sector_result[bnb_sector_result.date == datetime(2021, 10,13)].hvplot.bar(x='aggregate_sector', y=['allocation','selection','interaction'], stacked=True, rot=90, title='sector allocation')"
496
- ]
497
- }
498
- ],
499
- "metadata": {
500
- "kernelspec": {
501
- "display_name": "portfolio_risk_assesment",
502
- "language": "python",
503
- "name": "python3"
504
- },
505
- "language_info": {
506
- "codemirror_mode": {
507
- "name": "ipython",
508
- "version": 3
509
- },
510
- "file_extension": ".py",
511
- "mimetype": "text/x-python",
512
- "name": "python",
513
- "nbconvert_exporter": "python",
514
- "pygments_lexer": "ipython3",
515
- "version": "3.11.4"
516
- },
517
- "orig_nbformat": 4
518
- },
519
- "nbformat": 4,
520
- "nbformat_minor": 2
521
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/portfolio_eval_df.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:b8b82727132680652cd1ca9c9a10d8014a22c77a7fa901983f97db99367ed0e6
3
- size 25105
 
 
 
 
script/processing.ipynb DELETED
@@ -1,501 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
11
- "application/vnd.holoviews_load.v0+json": ""
12
- },
13
- "metadata": {},
14
- "output_type": "display_data"
15
- },
16
- {
17
- "data": {
18
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
19
- "application/vnd.holoviews_load.v0+json": ""
20
- },
21
- "metadata": {},
22
- "output_type": "display_data"
23
- },
24
- {
25
- "data": {
26
- "text/html": [
27
- "<style>*[data-root-id],\n",
28
- "*[data-root-id] > * {\n",
29
- " box-sizing: border-box;\n",
30
- " font-family: var(--jp-ui-font-family);\n",
31
- " font-size: var(--jp-ui-font-size1);\n",
32
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
33
- "}\n",
34
- "\n",
35
- "/* Override VSCode background color */\n",
36
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
37
- " > .lm-Widget\n",
38
- " > *[data-root-id]),\n",
39
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
40
- " background-color: transparent !important;\n",
41
- "}\n",
42
- "</style>"
43
- ]
44
- },
45
- "metadata": {},
46
- "output_type": "display_data"
47
- }
48
- ],
49
- "source": [
50
- "import pandas as pd\n",
51
- "import math\n",
52
- "from datetime import datetime\n",
53
- "import hvplot.pandas\n",
54
- "# load data\n",
55
- "profile_df = pd.read_pickle('../data/portfolio_portfile.pkl')\n",
56
- "benchmark_df = pd.read_pickle('../data/benchmark_portfolio.pkl')\n",
57
- "portfolio_df = pd.read_pickle('../data/portfolio_data.pkl')"
58
- ]
59
- },
60
- {
61
- "cell_type": "code",
62
- "execution_count": 2,
63
- "metadata": {},
64
- "outputs": [],
65
- "source": [
66
- "## calculate pct using closing price for each date\n",
67
- "portfolio_df.sort_values(by=['date'], inplace=True)\n",
68
- "portfolio_df['pct'] = portfolio_df.groupby(['ticker'])['close'].pct_change()\n",
69
- "\n",
70
- "benchmark_df.sort_values(by=['date'], inplace=True)\n",
71
- "benchmark_df['pct'] = benchmark_df.groupby(['ticker'])['close'].pct_change()\n"
72
- ]
73
- },
74
- {
75
- "cell_type": "code",
76
- "execution_count": 3,
77
- "metadata": {},
78
- "outputs": [],
79
- "source": [
80
- "## return and weight\n",
81
- "merge_df = portfolio_df.merge(profile_df[['ticker','weight','date']], on=['ticker','date'], how='left')\n",
82
- "merge_df.sort_values(by=['date'], inplace=True)\n",
83
- "benchmark_df.sort_values(by=['date'], inplace=True)\n",
84
- "\n",
85
- "# return for each stock\n",
86
- "# portfolio_df['return'] = portfolio_df['close'] / portfolio_df.groupby(['ticker'])['close'].transform('first') - 1\n",
87
- "# benchmark_df['return'] = benchmark_df['close'] / benchmark_df.groupby(['ticker'])['close'].transform('first') - 1\n",
88
- "\n",
89
- "# stock return in portfolio\n",
90
- "first_close_per_ticker = merge_df.groupby('ticker')['close'].transform('first')\n",
91
- "merge_df['return'] = merge_df['close'] / first_close_per_ticker - 1\n",
92
- "\n",
93
- "# stock return in benchmark\n",
94
- "first_close_per_ticker = benchmark_df.groupby('ticker')['close'].transform('first')\n",
95
- "benchmark_df['return'] = benchmark_df['close'] / first_close_per_ticker - 1\n",
96
- "\n",
97
- "# weight\n",
98
- "initial_weight = merge_df.groupby('ticker')['weight'].transform('first') \n",
99
- "merge_df['weight'] = initial_weight + (merge_df['return'] * initial_weight)\n",
100
- "\n",
101
- "# initial_weight\n",
102
- "# merge_df[merge_df.ticker==\"002709.XSHE\"]\n",
103
- "# merge_df\n",
104
- "# benchmark_df"
105
- ]
106
- },
107
- {
108
- "cell_type": "code",
109
- "execution_count": 4,
110
- "metadata": {},
111
- "outputs": [],
112
- "source": [
113
- "portfolio_df = merge_df"
114
- ]
115
- },
116
- {
117
- "cell_type": "code",
118
- "execution_count": 5,
119
- "metadata": {},
120
- "outputs": [],
121
- "source": [
122
- "## normalize weight\n",
123
- "benchmark_df['norm_weight'] = benchmark_df['weight'] / benchmark_df.groupby(['date'])['weight'].transform('sum')\n",
124
- "portfolio_df['norm_weight'] = portfolio_df['weight'] / portfolio_df.groupby(['date'])['weight'].transform('sum')"
125
- ]
126
- },
127
- {
128
- "cell_type": "code",
129
- "execution_count": 6,
130
- "metadata": {},
131
- "outputs": [],
132
- "source": [
133
- "## calculate weighted return\n",
134
- "portfolio_df['weighted_pct'] = portfolio_df['pct'] * portfolio_df['norm_weight']\n",
135
- "benchmark_df['weighted_pct'] = benchmark_df['pct'] * benchmark_df['norm_weight']\n"
136
- ]
137
- },
138
- {
139
- "cell_type": "code",
140
- "execution_count": 7,
141
- "metadata": {},
142
- "outputs": [],
143
- "source": [
144
- "## Calculate portfolio pct of return by summing the 'weighted_return' for each date\n",
145
- "\n",
146
- "# reset index becaue its a new table\n",
147
- "portfolio_pct = portfolio_df.groupby('date')['weighted_pct'].sum().reset_index()\n",
148
- "portfolio_pct.columns = ['date', 'pct']\n",
149
- "\n",
150
- "# benchmark pct summing the 'weighted_return' for each date\n",
151
- "#TODO chagne to use new weight in order to perform simulation\n",
152
- "benchmark_pct = benchmark_df.groupby('date')['weighted_pct'].sum().reset_index()\n",
153
- "benchmark_pct.columns = ['date', 'pct']\n",
154
- "\n",
155
- "# 'date', 'portfolio_return', and 'benchmark_return' columns\n",
156
- "return_result = pd.merge(portfolio_pct, benchmark_pct, on='date', suffixes=('_portfolio', '_benchmark'))"
157
- ]
158
- },
159
- {
160
- "cell_type": "code",
161
- "execution_count": 8,
162
- "metadata": {},
163
- "outputs": [],
164
- "source": [
165
- "## add total return\n",
166
- "portfolio_df['weighted_return'] = portfolio_df['return'] * portfolio_df['norm_weight']\n",
167
- "portfolio_return = portfolio_df.groupby('date')['weighted_return'].sum().reset_index()\n",
168
- "portfolio_return.columns = ['date', 'return']\n",
169
- "return_result = return_result.merge(portfolio_return, on='date')"
170
- ]
171
- },
172
- {
173
- "cell_type": "code",
174
- "execution_count": 9,
175
- "metadata": {},
176
- "outputs": [],
177
- "source": [
178
- "# daily_active_return\n",
179
- "return_result['daily_active_return'] = return_result['pct_portfolio'] - return_result['pct_benchmark']"
180
- ]
181
- },
182
- {
183
- "cell_type": "code",
184
- "execution_count": 10,
185
- "metadata": {},
186
- "outputs": [],
187
- "source": [
188
- "# daily pnl\n",
189
- "return_result['mkt_cap'] = None\n",
190
- "\n",
191
- "# assign initial market cap\n",
192
- "# sum weight because it is the money invested in the stock\n",
193
- "# TODO chagne here to add simulation functionality\n",
194
- "return_result.loc[return_result['date'] == profile_df['date'].values[0],'mkt_cap'] = profile_df['weight'].sum()\n",
195
- "return_result.sort_values(by=['date'], inplace=True)\n",
196
- "\n",
197
- "# calculate daily mkt_cap\n",
198
- "for i in range(1, len(return_result)):\n",
199
- " return_result.loc[i, 'mkt_cap'] = return_result.loc[i-1, 'mkt_cap'] * (1 + return_result.loc[i, 'pct_portfolio'])\n",
200
- "\n",
201
- "# calculate daily pnl\n",
202
- "return_result['daily_pnl'] = return_result['mkt_cap'].diff()\n",
203
- "\n",
204
- "\n"
205
- ]
206
- },
207
- {
208
- "cell_type": "code",
209
- "execution_count": 11,
210
- "metadata": {},
211
- "outputs": [],
212
- "source": [
213
- "## return volatilty mean return tracking erro cumulative pnl\n",
214
- "# volatitly\n",
215
- "return_result['pct_volitity_p'] = return_result['pct_portfolio'].expanding().std() * math.sqrt(252)\n",
216
- "return_result['pct_volitity_b'] = return_result['pct_benchmark'].expanding().std() * math.sqrt(252)\n",
217
- "# mean return\n",
218
- "return_result['mean_return'] = return_result['return'].mean()\n",
219
- "# tracking error \n",
220
- "return_result['tracking_error'] = return_result['daily_active_return'].expanding().std() * math.sqrt(252)\n",
221
- "# cumulative pnl\n",
222
- "return_result['cum_pnl'] = return_result['daily_pnl'].cumsum()\n",
223
- "# drawdown \n",
224
- "return_result['drawdown'] = (return_result['cum_pnl'] - return_result['cum_pnl'].cummax()) / return_result['cum_pnl'].cummax()"
225
- ]
226
- },
227
- {
228
- "cell_type": "code",
229
- "execution_count": 12,
230
- "metadata": {},
231
- "outputs": [],
232
- "source": [
233
- "## save\n",
234
- "return_result.to_pickle('../data/risk_return_result.pkl')"
235
- ]
236
- },
237
- {
238
- "cell_type": "code",
239
- "execution_count": 13,
240
- "metadata": {},
241
- "outputs": [],
242
- "source": [
243
- "# add sector info to portfolio_df\n",
244
- "portfolio_df = pd.merge(portfolio_df, profile_df[['ticker','aggregate_sector']], on='ticker', how='left')"
245
- ]
246
- },
247
- {
248
- "cell_type": "code",
249
- "execution_count": 14,
250
- "metadata": {},
251
- "outputs": [
252
- {
253
- "name": "stderr",
254
- "output_type": "stream",
255
- "text": [
256
- "/var/folders/v5/2108rh5964q9j741wg_s8r1w0000gn/T/ipykernel_1263/1040563745.py:2: SettingWithCopyWarning: \n",
257
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
258
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
259
- "\n",
260
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
261
- " benchmark_df[benchmark_df.aggregate_sector.isna()].aggregate_sector = '其他'\n"
262
- ]
263
- }
264
- ],
265
- "source": [
266
- "# hanlde sector is nan\n",
267
- "benchmark_df[benchmark_df.aggregate_sector.isna()].aggregate_sector = '其他'\n",
268
- "portfolio_df[portfolio_df.aggregate_sector.isna()].aggregate_sector = '其他'"
269
- ]
270
- },
271
- {
272
- "cell_type": "code",
273
- "execution_count": 15,
274
- "metadata": {},
275
- "outputs": [
276
- {
277
- "data": {
278
- "text/html": [
279
- "<div>\n",
280
- "<style scoped>\n",
281
- " .dataframe tbody tr th:only-of-type {\n",
282
- " vertical-align: middle;\n",
283
- " }\n",
284
- "\n",
285
- " .dataframe tbody tr th {\n",
286
- " vertical-align: top;\n",
287
- " }\n",
288
- "\n",
289
- " .dataframe thead th {\n",
290
- " text-align: right;\n",
291
- " }\n",
292
- "</style>\n",
293
- "<table border=\"1\" class=\"dataframe\">\n",
294
- " <thead>\n",
295
- " <tr style=\"text-align: right;\">\n",
296
- " <th></th>\n",
297
- " <th>date</th>\n",
298
- " <th>weight</th>\n",
299
- " <th>display_name_x</th>\n",
300
- " <th>actual_data</th>\n",
301
- " <th>ticker</th>\n",
302
- " <th>open</th>\n",
303
- " <th>close</th>\n",
304
- " <th>high</th>\n",
305
- " <th>low</th>\n",
306
- " <th>volume</th>\n",
307
- " <th>money</th>\n",
308
- " <th>display_name_y</th>\n",
309
- " <th>name</th>\n",
310
- " <th>sector</th>\n",
311
- " <th>aggregate_sector</th>\n",
312
- " <th>pct</th>\n",
313
- " <th>return</th>\n",
314
- " <th>norm_weight</th>\n",
315
- " <th>weighted_pct</th>\n",
316
- " </tr>\n",
317
- " </thead>\n",
318
- " <tbody>\n",
319
- " <tr>\n",
320
- " <th>0</th>\n",
321
- " <td>2021-01-05</td>\n",
322
- " <td>0.088</td>\n",
323
- " <td>神州高铁</td>\n",
324
- " <td>2020-12-31</td>\n",
325
- " <td>000008.XSHE</td>\n",
326
- " <td>2.52</td>\n",
327
- " <td>2.57</td>\n",
328
- " <td>2.67</td>\n",
329
- " <td>2.49</td>\n",
330
- " <td>33215803.0</td>\n",
331
- " <td>85358605.99</td>\n",
332
- " <td>神州高铁</td>\n",
333
- " <td>SZGT</td>\n",
334
- " <td>机械设备I 运输设备II 铁路设备III 铁路、船舶、航空航天和其他运输设备制造业 城轨铁路 工业</td>\n",
335
- " <td>工业</td>\n",
336
- " <td>NaN</td>\n",
337
- " <td>0.0</td>\n",
338
- " <td>0.00088</td>\n",
339
- " <td>NaN</td>\n",
340
- " </tr>\n",
341
- " </tbody>\n",
342
- "</table>\n",
343
- "</div>"
344
- ],
345
- "text/plain": [
346
- " date weight display_name_x actual_data ticker open close \\\n",
347
- "0 2021-01-05 0.088 神州高铁 2020-12-31 000008.XSHE 2.52 2.57 \n",
348
- "\n",
349
- " high low volume money display_name_y name \\\n",
350
- "0 2.67 2.49 33215803.0 85358605.99 神州高铁 SZGT \n",
351
- "\n",
352
- " sector aggregate_sector pct \\\n",
353
- "0 机械设备I 运输设备II 铁路设备III 铁路、船舶、航空航天和其他运输设备制造业 城轨铁路 工业 工业 NaN \n",
354
- "\n",
355
- " return norm_weight weighted_pct \n",
356
- "0 0.0 0.00088 NaN "
357
- ]
358
- },
359
- "execution_count": 15,
360
- "metadata": {},
361
- "output_type": "execute_result"
362
- }
363
- ],
364
- "source": [
365
- "benchmark_df.head(1)"
366
- ]
367
- },
368
- {
369
- "cell_type": "code",
370
- "execution_count": 16,
371
- "metadata": {},
372
- "outputs": [],
373
- "source": [
374
- "## aggregate as sector \n",
375
- "\n",
376
- "# weighted return in a sector, weight in a sector\n",
377
- "portfolio_df['weight_in_sector'] = portfolio_df['norm_weight']/ portfolio_df.groupby(['aggregate_sector','date'])['weight'].transform('sum')\n",
378
- "portfolio_df['weighted_s_return'] = portfolio_df['return'] * portfolio_df['weight_in_sector']\n",
379
- "\n",
380
- "# return and weight by sector\n",
381
- "return_by_sector = portfolio_df.groupby(['aggregate_sector','date'])['weighted_s_return'].sum().reset_index()\n",
382
- "normed_sector_weight = portfolio_df.groupby(['aggregate_sector','date'])['norm_weight'].sum().reset_index()\n",
383
- "p_sector_result = pd.merge(return_by_sector, normed_sector_weight, on=['aggregate_sector','date'], how='left')\n",
384
- "p_sector_result.rename(columns={'weighted_s_return':'return'}, inplace=True)\n",
385
- "\n",
386
- "# same thing for benchmark\n",
387
- "benchmark_df['weight_in_sector'] = benchmark_df['norm_weight']/ benchmark_df.groupby(['aggregate_sector','date'])['norm_weight'].transform('sum')\n",
388
- "benchmark_df['weighted_s_return'] = benchmark_df['return'] * benchmark_df['weight_in_sector']\n",
389
- "return_by_sector = benchmark_df.groupby(['aggregate_sector','date'])['weighted_s_return'].sum().reset_index()\n",
390
- "normed_sector_weight = benchmark_df.groupby(['aggregate_sector','date'])['norm_weight'].sum().reset_index()\n",
391
- "b_sector_result = pd.merge(return_by_sector, normed_sector_weight, on=['aggregate_sector','date'], how='left')\n",
392
- "b_sector_result.rename(columns={'weighted_s_return':'return'}, inplace=True)\n"
393
- ]
394
- },
395
- {
396
- "cell_type": "code",
397
- "execution_count": 17,
398
- "metadata": {},
399
- "outputs": [],
400
- "source": [
401
- "## selection, allocation, interaction for sector\n",
402
- "\n",
403
- "\n",
404
- "bnb_result_sector = pd.merge(\n",
405
- " p_sector_result, b_sector_result,\n",
406
- " on=['date','aggregate_sector',], how='outer', suffixes=('_p', '_b'))\n",
407
- "\n",
408
- "# replace nan norm_weight_b with 0\n",
409
- "bnb_result_sector['norm_weight_b'] = bnb_result_sector['norm_weight_b'].fillna(0)\n",
410
- "bnb_result_sector['norm_weight_p'] = bnb_result_sector['norm_weight_p'].fillna(0)\n",
411
- "\n",
412
- "# active weight\n",
413
- "bnb_result_sector['active_weight'] = bnb_result_sector['norm_weight_p'] - bnb_result_sector['norm_weight_b']\n",
414
- "\n",
415
- "# allocation \n",
416
- "bnb_result_sector['allocation'] = bnb_result_sector['active_weight'] * bnb_result_sector['return_b']\n",
417
- "\n",
418
- "#selection\n",
419
- "bnb_result_sector['selection'] = bnb_result_sector['norm_weight_p'] * (bnb_result_sector['return_p'] - bnb_result_sector['return_b'])\n",
420
- "\n",
421
- "#inetration\n",
422
- "bnb_result_sector['interaction'] = (bnb_result_sector['norm_weight_p'] - bnb_result_sector['norm_weight_b']) *\\\n",
423
- " (bnb_result_sector['return_p'] - bnb_result_sector['return_b'])"
424
- ]
425
- },
426
- {
427
- "cell_type": "code",
428
- "execution_count": 18,
429
- "metadata": {},
430
- "outputs": [],
431
- "source": [
432
- "## save result \n",
433
- "bnb_result_sector.to_pickle('../data/bnb_result_sector.pkl')"
434
- ]
435
- },
436
- {
437
- "cell_type": "code",
438
- "execution_count": 19,
439
- "metadata": {},
440
- "outputs": [],
441
- "source": [
442
- "## selection, allocation, interaction for stocks\n",
443
- "\n",
444
- "# I keep weight to exame the stock not in benchmark but in portfolio and vice versa\n",
445
- "bnb_result = pd.merge(\n",
446
- " portfolio_df[['date','ticker','norm_weight','weight','return','aggregate_sector']],\n",
447
- " benchmark_df[['date','ticker','norm_weight','weight','return']], on=['date','ticker',], how='outer', suffixes=('_p', '_b'))\n",
448
- "\n",
449
- "# replace nan norm_weight_b with 0\n",
450
- "bnb_result['norm_weight_b'] = bnb_result['norm_weight_b'].fillna(0)\n",
451
- "bnb_result['norm_weight_p'] = bnb_result['norm_weight_p'].fillna(0)\n",
452
- "\n",
453
- "# active weight\n",
454
- "bnb_result['active_weight'] = bnb_result['norm_weight_p'] - bnb_result['norm_weight_b']\n",
455
- "\n",
456
- "# allocation \n",
457
- "bnb_result['allocation'] = bnb_result['active_weight'] * bnb_result['return_b']\n",
458
- "\n",
459
- "#selection\n",
460
- "bnb_result['selection'] = bnb_result['norm_weight_p'] * (bnb_result['return_p'] - bnb_result['return_b'])\n",
461
- "\n",
462
- "#inetration\n",
463
- "bnb_result['interaction'] = (bnb_result['norm_weight_p'] - bnb_result['norm_weight_b']) *\\\n",
464
- " (bnb_result['return_p'] - bnb_result['return_b'])\n",
465
- "\n"
466
- ]
467
- },
468
- {
469
- "cell_type": "code",
470
- "execution_count": 20,
471
- "metadata": {},
472
- "outputs": [],
473
- "source": [
474
- "## svae\n",
475
- "bnb_result.to_pickle('../data/bnb_result.pkl')"
476
- ]
477
- }
478
- ],
479
- "metadata": {
480
- "kernelspec": {
481
- "display_name": "portfolio_risk_assesment",
482
- "language": "python",
483
- "name": "python3"
484
- },
485
- "language_info": {
486
- "codemirror_mode": {
487
- "name": "ipython",
488
- "version": 3
489
- },
490
- "file_extension": ".py",
491
- "mimetype": "text/x-python",
492
- "name": "python",
493
- "nbconvert_exporter": "python",
494
- "pygments_lexer": "ipython3",
495
- "version": "3.11.4"
496
- },
497
- "orig_nbformat": 4
498
- },
499
- "nbformat": 4,
500
- "nbformat_minor": 2
501
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/processing2.ipynb DELETED
@@ -1,1836 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 142,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "import pandas as pd\n",
10
- "import math\n",
11
- "from datetime import datetime\n",
12
- "import hvplot.pandas\n",
13
- "import math\n",
14
- "# load data\n",
15
- "profile_df = pd.read_pickle('../data/portfolio_portfile.pkl')\n",
16
- "benchmark_df = pd.read_pickle('../data/benchmark_portfolio.pkl')\n",
17
- "portfolio_df = pd.read_pickle('../data/portfolio_data.pkl')"
18
- ]
19
- },
20
- {
21
- "cell_type": "code",
22
- "execution_count": 143,
23
- "metadata": {},
24
- "outputs": [],
25
- "source": [
26
- "# to acoomodate the current pipe line\n",
27
- "min_dates = benchmark_df.groupby('ticker')['date'].min()\n",
28
- "\n",
29
- "for ticker, min_date in min_dates.items():\n",
30
- " benchmark_df.loc[(benchmark_df['ticker'] == ticker) & (benchmark_df['date'] != min_date), 'weight'] = float('nan')\n",
31
- "\n",
32
- "benchmark_df['initial_weight'] = benchmark_df['weight']\n",
33
- "# drop weight\n",
34
- "benchmark_df = benchmark_df.drop(columns=['weight'])"
35
- ]
36
- },
37
- {
38
- "cell_type": "code",
39
- "execution_count": 144,
40
- "metadata": {},
41
- "outputs": [
42
- {
43
- "data": {
44
- "text/plain": [
45
- "Series([], Name: initial_weight, dtype: int64)"
46
- ]
47
- },
48
- "execution_count": 144,
49
- "metadata": {},
50
- "output_type": "execute_result"
51
- }
52
- ],
53
- "source": [
54
- "# check if all unique ticker has an weight\n",
55
- "count_list = benchmark_df.groupby('ticker')['initial_weight'].count().sort_values(ascending=False)\n",
56
- "count_list[count_list != 1]\n"
57
- ]
58
- },
59
- {
60
- "cell_type": "code",
61
- "execution_count": 145,
62
- "metadata": {},
63
- "outputs": [],
64
- "source": [
65
- "update_profile_df = profile_df.copy()\n",
66
- "update_profile_df['date'] = datetime(2021,1,10)\n",
67
- "update_profile_df['weight'] = [50,100,200,300,400,500]\n",
68
- "profile_df = pd.concat([profile_df, update_profile_df])\n"
69
- ]
70
- },
71
- {
72
- "cell_type": "code",
73
- "execution_count": 146,
74
- "metadata": {},
75
- "outputs": [],
76
- "source": [
77
- "def calculate_pct(stock_df):\n",
78
- " stock_df['pct'] = stock_df.groupby(['ticker'])['close'].pct_change()\n"
79
- ]
80
- },
81
- {
82
- "cell_type": "code",
83
- "execution_count": 147,
84
- "metadata": {},
85
- "outputs": [],
86
- "source": [
87
- "# step 1 pct\n",
88
- "calculate_pct(portfolio_df)\n",
89
- "calculate_pct(benchmark_df)"
90
- ]
91
- },
92
- {
93
- "cell_type": "code",
94
- "execution_count": 148,
95
- "metadata": {},
96
- "outputs": [],
97
- "source": [
98
- "def return_weighted_stock_df(stock_price_df, profile_df=None):\n",
99
- " # TODO change later this a temporary solution\n",
100
- " # initialize weight if profile_df is not none\n",
101
- " merged_df = pd.DataFrame()\n",
102
- " if profile_df is not None:\n",
103
- " merged_df = stock_price_df.merge(profile_df[['weight', 'date', 'ticker']], on=['ticker', 'date'], how='outer')\n",
104
- " merged_df.sort_values(by=['date'], inplace=True)\n",
105
- " merged_df.rename(columns={'weight': 'initial_weight'}, inplace=True)\n",
106
- " else:\n",
107
- " merged_df = stock_price_df.copy()\n",
108
- " merged_df['current_weight'] = float('nan')\n",
109
- " merged_df['previous_weight'] = float('nan')\n",
110
- " df_grouped = merged_df.groupby('ticker')\n",
111
- " for _, group in df_grouped:\n",
112
- " pre_w = float('nan')\n",
113
- " ini_w = float('nan')\n",
114
- " for index, row in group.iterrows():\n",
115
- " cur_w = float('nan')\n",
116
- " # if has initial weight, the following row all use this initial weight\n",
117
- " if not pd.isna(row['initial_weight']):\n",
118
- " ini_w = row['initial_weight']\n",
119
- " cur_w = ini_w\n",
120
- " # just calculate current weight based on previous weight\n",
121
- " else:\n",
122
- " cur_w = pre_w * (1 + row['pct'])\n",
123
- "\n",
124
- " merged_df.loc[index, 'current_weight'] = cur_w \n",
125
- " merged_df.loc[index, 'previous_weight'] = pre_w\n",
126
- " merged_df.loc[index, 'initial_weight'] = ini_w\n",
127
- " pre_w = cur_w\n",
128
- " \n",
129
- " # drop row where closing price is none\n",
130
- " merged_df = merged_df[~pd.isna(merged_df['close'])]\n",
131
- " # drop index\n",
132
- " return merged_df"
133
- ]
134
- },
135
- {
136
- "cell_type": "code",
137
- "execution_count": 149,
138
- "metadata": {},
139
- "outputs": [],
140
- "source": [
141
- "# TODO consider save the weight calculation\n",
142
- "portfolio_df = return_weighted_stock_df(portfolio_df, profile_df)\n",
143
- "benchmark_df = return_weighted_stock_df(benchmark_df)"
144
- ]
145
- },
146
- {
147
- "cell_type": "code",
148
- "execution_count": 150,
149
- "metadata": {},
150
- "outputs": [],
151
- "source": [
152
- "# benchmark_df[benchmark_df.ticker =='000008.XSHE']"
153
- ]
154
- },
155
- {
156
- "cell_type": "code",
157
- "execution_count": 151,
158
- "metadata": {},
159
- "outputs": [],
160
- "source": [
161
- "## normalize all weight\n",
162
- "def normalize_weight(stock_df):\n",
163
- " stock_df['current_weight'] = stock_df['current_weight'] / \\\n",
164
- " stock_df.groupby('date')['current_weight'].transform('sum')\n",
165
- "\n",
166
- " stock_df['previous_weight'] = stock_df['previous_weight'] / \\\n",
167
- " stock_df.groupby('date')['previous_weight'].transform('sum')\n",
168
- "\n",
169
- " stock_df['initial_weight'] = stock_df['initial_weight'] / \\\n",
170
- " stock_df.groupby('date')['initial_weight'].transform('sum')\n"
171
- ]
172
- },
173
- {
174
- "cell_type": "code",
175
- "execution_count": 152,
176
- "metadata": {},
177
- "outputs": [],
178
- "source": [
179
- "normalize_weight(portfolio_df)\n",
180
- "normalize_weight(benchmark_df)"
181
- ]
182
- },
183
- {
184
- "cell_type": "code",
185
- "execution_count": 153,
186
- "metadata": {},
187
- "outputs": [
188
- {
189
- "data": {
190
- "text/plain": [
191
- "260 0.032258\n",
192
- "258 0.064516\n",
193
- "262 0.129032\n",
194
- "263 0.258065\n",
195
- "259 0.322581\n",
196
- "261 0.193548\n",
197
- "Name: initial_weight, dtype: float64"
198
- ]
199
- },
200
- "execution_count": 153,
201
- "metadata": {},
202
- "output_type": "execute_result"
203
- }
204
- ],
205
- "source": [
206
- "portfolio_df[portfolio_df.date == datetime(2021, 3, 12)]['initial_weight']"
207
- ]
208
- },
209
- {
210
- "cell_type": "code",
211
- "execution_count": 154,
212
- "metadata": {},
213
- "outputs": [
214
- {
215
- "name": "stdout",
216
- "output_type": "stream",
217
- "text": [
218
- "1.0\n",
219
- "1.0\n",
220
- "1.0\n"
221
- ]
222
- }
223
- ],
224
- "source": [
225
- "print(benchmark_df[benchmark_df.date == datetime(2021, 3, 12)]['initial_weight'].sum())\n",
226
- "print(benchmark_df[benchmark_df.date == datetime(2021, 3, 12)]['current_weight'].sum())\n",
227
- "print(benchmark_df[benchmark_df.date == datetime(2021, 3, 12)]['previous_weight'].sum())"
228
- ]
229
- },
230
- {
231
- "cell_type": "code",
232
- "execution_count": 155,
233
- "metadata": {},
234
- "outputs": [],
235
- "source": [
236
- "# step 3 sector wegiht\n",
237
- "\n",
238
- "# add sector information first\n",
239
- "def create_sector_weight(stock_df, profile_df=None):\n",
240
- " # if profile_df is none assume the aggregate_sector stock info already in stock_df\n",
241
- " merged_df = None\n",
242
- " if profile_df is not None:\n",
243
- " merged_df = stock_df.merge(profile_df[['ticker', 'aggregate_sector']], on='ticker', how='left')\n",
244
- " else:\n",
245
- " merged_df = stock_df.copy()\n",
246
- " # set null to others\n",
247
- " merged_df['aggregate_sector'] = merged_df['aggregate_sector'].fillna('其他')\n",
248
- " # calculate previous_sector_weight\n",
249
- " merged_df['previous_sector_weight'] = merged_df['previous_weight'] / \\\n",
250
- " merged_df.groupby(['date', 'aggregate_sector'])['previous_weight'].transform('sum')\n",
251
- " # calculate initial sectore weight\n",
252
- " merged_df['initial_sector_weight'] = merged_df['initial_weight'] / \\\n",
253
- " merged_df.groupby(['date', 'aggregate_sector'])['initial_weight'].transform('sum')\n",
254
- " \n",
255
- " return merged_df"
256
- ]
257
- },
258
- {
259
- "cell_type": "code",
260
- "execution_count": 156,
261
- "metadata": {},
262
- "outputs": [],
263
- "source": [
264
- "portfolio_df = create_sector_weight(stock_df = portfolio_df, profile_df = profile_df)\n",
265
- "benchmark_df = create_sector_weight(benchmark_df)\n"
266
- ]
267
- },
268
- {
269
- "cell_type": "code",
270
- "execution_count": 157,
271
- "metadata": {},
272
- "outputs": [
273
- {
274
- "name": "stdout",
275
- "output_type": "stream",
276
- "text": [
277
- "aggregate_sector\n",
278
- "信息与通信 1.0\n",
279
- "公用事业 1.0\n",
280
- "其他 1.0\n",
281
- "医药卫生 1.0\n",
282
- "原料与能源 1.0\n",
283
- "工业 1.0\n",
284
- "消费 1.0\n",
285
- "金融与地产 1.0\n",
286
- "Name: previous_sector_weight, dtype: float64\n",
287
- "aggregate_sector\n",
288
- "信息与通信 1.0\n",
289
- "公用事业 1.0\n",
290
- "其他 1.0\n",
291
- "医药卫生 1.0\n",
292
- "原料与能源 1.0\n",
293
- "工业 1.0\n",
294
- "消费 1.0\n",
295
- "金融与地产 1.0\n",
296
- "Name: initial_sector_weight, dtype: float64\n"
297
- ]
298
- }
299
- ],
300
- "source": [
301
- "# check result \n",
302
- "print(benchmark_df[benchmark_df.date == datetime(2021, 3, 12)].groupby('aggregate_sector')['previous_sector_weight'].sum())\n",
303
- "print(benchmark_df[benchmark_df.date == datetime(2021, 3, 12)].groupby('aggregate_sector')['initial_sector_weight'].sum())\n"
304
- ]
305
- },
306
- {
307
- "cell_type": "code",
308
- "execution_count": 158,
309
- "metadata": {},
310
- "outputs": [
311
- {
312
- "name": "stdout",
313
- "output_type": "stream",
314
- "text": [
315
- "aggregate_sector\n",
316
- "信息与通信 1.0\n",
317
- "医药卫生 1.0\n",
318
- "原料与能源 1.0\n",
319
- "工业 1.0\n",
320
- "消费 1.0\n",
321
- "Name: previous_sector_weight, dtype: float64\n",
322
- "aggregate_sector\n",
323
- "信息与通信 1.0\n",
324
- "医药卫生 1.0\n",
325
- "原料与能源 1.0\n",
326
- "工业 1.0\n",
327
- "消费 1.0\n",
328
- "Name: initial_sector_weight, dtype: float64\n"
329
- ]
330
- }
331
- ],
332
- "source": [
333
- "# check result \n",
334
- "print(portfolio_df[portfolio_df.date == datetime(2021, 3, 12)].groupby('aggregate_sector')['previous_sector_weight'].sum())\n",
335
- "print(portfolio_df[portfolio_df.date == datetime(2021, 3, 12)].groupby('aggregate_sector')['initial_sector_weight'].sum())\n"
336
- ]
337
- },
338
- {
339
- "cell_type": "code",
340
- "execution_count": 159,
341
- "metadata": {},
342
- "outputs": [],
343
- "source": [
344
- "## return define as the total return since the portfolio created\n",
345
- "def calcualte_return(stock_df):\n",
346
- " stock_df['return'] = stock_df['close'] / stock_df.groupby(['ticker'])['close'].transform('first') - 1"
347
- ]
348
- },
349
- {
350
- "cell_type": "code",
351
- "execution_count": 160,
352
- "metadata": {},
353
- "outputs": [],
354
- "source": [
355
- "calcualte_return(portfolio_df)\n",
356
- "calcualte_return(benchmark_df)"
357
- ]
358
- },
359
- {
360
- "cell_type": "code",
361
- "execution_count": 161,
362
- "metadata": {},
363
- "outputs": [],
364
- "source": [
365
- "def calculate_weighted_sector_return(stock_df):\n",
366
- " stock_df['weighted_sectore_return'] = stock_df['return'] * stock_df['initial_sector_weight']"
367
- ]
368
- },
369
- {
370
- "cell_type": "code",
371
- "execution_count": 162,
372
- "metadata": {},
373
- "outputs": [],
374
- "source": [
375
- "calculate_weighted_sector_return(portfolio_df)\n",
376
- "calculate_weighted_sector_return(benchmark_df)"
377
- ]
378
- },
379
- {
380
- "cell_type": "code",
381
- "execution_count": 163,
382
- "metadata": {},
383
- "outputs": [],
384
- "source": [
385
- "## weighted return and sector weighred return \n",
386
- "def calculate_weighted_return(stock_df):\n",
387
- " stock_df['weighted_return'] = stock_df['return'] * stock_df['initial_weight']"
388
- ]
389
- },
390
- {
391
- "cell_type": "code",
392
- "execution_count": 164,
393
- "metadata": {},
394
- "outputs": [],
395
- "source": [
396
- "# step\n",
397
- "calculate_weighted_return(portfolio_df)\n",
398
- "calculate_weighted_return(benchmark_df)"
399
- ]
400
- },
401
- {
402
- "cell_type": "code",
403
- "execution_count": 165,
404
- "metadata": {},
405
- "outputs": [],
406
- "source": [
407
- "def calculate_weighted_sector_return(stock_df):\n",
408
- " stock_df['weighted_sector_return'] = stock_df['return'] * stock_df['initial_sector_weight']"
409
- ]
410
- },
411
- {
412
- "cell_type": "code",
413
- "execution_count": 166,
414
- "metadata": {},
415
- "outputs": [],
416
- "source": [
417
- "calculate_weighted_sector_return(portfolio_df)\n",
418
- "calculate_weighted_sector_return(benchmark_df)"
419
- ]
420
- },
421
- {
422
- "cell_type": "code",
423
- "execution_count": 167,
424
- "metadata": {},
425
- "outputs": [],
426
- "source": [
427
- "## calcualte weighted pc\n",
428
- "def calculate_weighted_pct(stock_df):\n",
429
- " stock_df['weighted_pct'] = stock_df['pct'] * stock_df['previous_weight']\n",
430
- "\n"
431
- ]
432
- },
433
- {
434
- "cell_type": "code",
435
- "execution_count": 168,
436
- "metadata": {},
437
- "outputs": [],
438
- "source": [
439
- "def calculate_weighted_sector_pct(stock_df):\n",
440
- " stock_df['weighted_sector_pct'] = stock_df['pct'] * stock_df['previous_sector_weight']\n",
441
- " "
442
- ]
443
- },
444
- {
445
- "cell_type": "code",
446
- "execution_count": 169,
447
- "metadata": {},
448
- "outputs": [],
449
- "source": [
450
- "calculate_weighted_sector_pct(portfolio_df)\n",
451
- "calculate_weighted_sector_pct(benchmark_df)"
452
- ]
453
- },
454
- {
455
- "cell_type": "code",
456
- "execution_count": 170,
457
- "metadata": {},
458
- "outputs": [],
459
- "source": [
460
- "calculate_weighted_pct(portfolio_df)\n",
461
- "calculate_weighted_pct(benchmark_df)"
462
- ]
463
- },
464
- {
465
- "cell_type": "code",
466
- "execution_count": 171,
467
- "metadata": {},
468
- "outputs": [],
469
- "source": [
470
- "calculate_weighted_sector_return(portfolio_df)\n",
471
- "calculate_weighted_sector_return(benchmark_df)"
472
- ]
473
- },
474
- {
475
- "cell_type": "code",
476
- "execution_count": 172,
477
- "metadata": {},
478
- "outputs": [],
479
- "source": [
480
- "## aggregate by date\n",
481
- "\n",
482
- "# pct and weighted_return\n",
483
- "# def agg_by_date(stock_df)\n",
484
- "def agg_by_date(stock_df):\n",
485
- " agg_on_date_df = pd.DataFrame(stock_df.groupby('date')[['weighted_return','weighted_pct']].sum())\n",
486
- " agg_on_date_df.rename(columns={'weighted_return': 'return', 'weighted_pct': 'pct'}, inplace=True)\n",
487
- " return agg_on_date_df\n",
488
- "\n",
489
- "\n"
490
- ]
491
- },
492
- {
493
- "cell_type": "code",
494
- "execution_count": 173,
495
- "metadata": {},
496
- "outputs": [],
497
- "source": [
498
- "p_total_view = agg_by_date(portfolio_df)\n",
499
- "b_total_view = agg_by_date(benchmark_df)"
500
- ]
501
- },
502
- {
503
- "cell_type": "code",
504
- "execution_count": 174,
505
- "metadata": {},
506
- "outputs": [],
507
- "source": [
508
- "## aggregate by sector\n",
509
- "def agg_by_sector(stock_df):\n",
510
- " agg_on_sector_df = pd.DataFrame(stock_df.groupby(['aggregate_sector','date'])[['weighted_sector_return','weighted_sector_pct']].sum())\n",
511
- " agg_on_sector_df.rename(columns={'weighted_sector_return': 'return', 'weighted_sector_pct': 'pct'}, inplace=True)\n",
512
- " return agg_on_sector_df"
513
- ]
514
- },
515
- {
516
- "cell_type": "code",
517
- "execution_count": 175,
518
- "metadata": {},
519
- "outputs": [],
520
- "source": [
521
- "p_sector_view = agg_by_sector(portfolio_df)\n",
522
- "b_sector_view = agg_by_sector(benchmark_df)"
523
- ]
524
- },
525
- {
526
- "cell_type": "code",
527
- "execution_count": 200,
528
- "metadata": {},
529
- "outputs": [],
530
- "source": [
531
- "def create_risk_table(portfolio_summary, benchmark_summary):\n",
532
- " # total risk tracking error \n",
533
- " merged_df = pd.merge(portfolio_summary, benchmark_summary, on='date', how='outer', suffixes=('_p', '_b'))\n",
534
- " merged_df['risk_p'] = merged_df['return_p'].expanding().std() * math.sqrt(252)\n",
535
- " merged_df['risk_b'] = merged_df['return_b'].expanding().std() * math.sqrt(252)\n",
536
- " merged_df['active_return'] = merged_df['return_p'] - merged_df['return_b']\n",
537
- " merged_df['tracking_error'] = merged_df['active_return'].expanding().std() * math.sqrt(252)\n",
538
- " merged_df['date'] = merged_df.index\n",
539
- " # drop index\n",
540
- " merged_df.reset_index(drop=True, inplace=True)\n",
541
- " return merged_df"
542
- ]
543
- },
544
- {
545
- "cell_type": "code",
546
- "execution_count": 201,
547
- "metadata": {},
548
- "outputs": [],
549
- "source": [
550
- "portfolio_risk_by_date_df = create_risk_table(p_total_view, b_total_view)"
551
- ]
552
- },
553
- {
554
- "cell_type": "code",
555
- "execution_count": 202,
556
- "metadata": {},
557
- "outputs": [
558
- {
559
- "data": {
560
- "text/html": [
561
- "<div>\n",
562
- "<style scoped>\n",
563
- " .dataframe tbody tr th:only-of-type {\n",
564
- " vertical-align: middle;\n",
565
- " }\n",
566
- "\n",
567
- " .dataframe tbody tr th {\n",
568
- " vertical-align: top;\n",
569
- " }\n",
570
- "\n",
571
- " .dataframe thead th {\n",
572
- " text-align: right;\n",
573
- " }\n",
574
- "</style>\n",
575
- "<table border=\"1\" class=\"dataframe\">\n",
576
- " <thead>\n",
577
- " <tr style=\"text-align: right;\">\n",
578
- " <th></th>\n",
579
- " <th>return_p</th>\n",
580
- " <th>pct_p</th>\n",
581
- " <th>return_b</th>\n",
582
- " <th>pct_b</th>\n",
583
- " <th>risk_p</th>\n",
584
- " <th>risk_b</th>\n",
585
- " <th>active_return</th>\n",
586
- " <th>tracking_error</th>\n",
587
- " <th>date</th>\n",
588
- " </tr>\n",
589
- " </thead>\n",
590
- " <tbody>\n",
591
- " <tr>\n",
592
- " <th>0</th>\n",
593
- " <td>0.000000</td>\n",
594
- " <td>0.000000</td>\n",
595
- " <td>0.000000</td>\n",
596
- " <td>0.000000</td>\n",
597
- " <td>NaN</td>\n",
598
- " <td>NaN</td>\n",
599
- " <td>0.000000</td>\n",
600
- " <td>NaN</td>\n",
601
- " <td>2021-01-05</td>\n",
602
- " </tr>\n",
603
- " <tr>\n",
604
- " <th>1</th>\n",
605
- " <td>0.012146</td>\n",
606
- " <td>0.012146</td>\n",
607
- " <td>-0.001934</td>\n",
608
- " <td>-0.001934</td>\n",
609
- " <td>0.136341</td>\n",
610
- " <td>0.021705</td>\n",
611
- " <td>0.014080</td>\n",
612
- " <td>0.158046</td>\n",
613
- " <td>2021-01-06</td>\n",
614
- " </tr>\n",
615
- " <tr>\n",
616
- " <th>2</th>\n",
617
- " <td>0.086830</td>\n",
618
- " <td>0.074233</td>\n",
619
- " <td>-0.000811</td>\n",
620
- " <td>0.001125</td>\n",
621
- " <td>0.746402</td>\n",
622
- " <td>0.015414</td>\n",
623
- " <td>0.087641</td>\n",
624
- " <td>0.747127</td>\n",
625
- " <td>2021-01-07</td>\n",
626
- " </tr>\n",
627
- " <tr>\n",
628
- " <th>3</th>\n",
629
- " <td>0.089435</td>\n",
630
- " <td>0.002496</td>\n",
631
- " <td>0.002535</td>\n",
632
- " <td>0.003349</td>\n",
633
- " <td>0.756382</td>\n",
634
- " <td>0.030137</td>\n",
635
- " <td>0.086900</td>\n",
636
- " <td>0.740979</td>\n",
637
- " <td>2021-01-08</td>\n",
638
- " </tr>\n",
639
- " <tr>\n",
640
- " <th>4</th>\n",
641
- " <td>0.148063</td>\n",
642
- " <td>0.029363</td>\n",
643
- " <td>-0.013015</td>\n",
644
- " <td>-0.015511</td>\n",
645
- " <td>0.970984</td>\n",
646
- " <td>0.095654</td>\n",
647
- " <td>0.161078</td>\n",
648
- " <td>1.032423</td>\n",
649
- " <td>2021-01-11</td>\n",
650
- " </tr>\n",
651
- " <tr>\n",
652
- " <th>...</th>\n",
653
- " <td>...</td>\n",
654
- " <td>...</td>\n",
655
- " <td>...</td>\n",
656
- " <td>...</td>\n",
657
- " <td>...</td>\n",
658
- " <td>...</td>\n",
659
- " <td>...</td>\n",
660
- " <td>...</td>\n",
661
- " <td>...</td>\n",
662
- " </tr>\n",
663
- " <tr>\n",
664
- " <th>242</th>\n",
665
- " <td>0.028005</td>\n",
666
- " <td>-0.071081</td>\n",
667
- " <td>0.086827</td>\n",
668
- " <td>0.000156</td>\n",
669
- " <td>2.097631</td>\n",
670
- " <td>0.886298</td>\n",
671
- " <td>-0.058822</td>\n",
672
- " <td>1.856213</td>\n",
673
- " <td>2022-01-04</td>\n",
674
- " </tr>\n",
675
- " <tr>\n",
676
- " <th>243</th>\n",
677
- " <td>-0.033053</td>\n",
678
- " <td>-0.059582</td>\n",
679
- " <td>0.067931</td>\n",
680
- " <td>-0.017386</td>\n",
681
- " <td>2.099052</td>\n",
682
- " <td>0.884891</td>\n",
683
- " <td>-0.100984</td>\n",
684
- " <td>1.861347</td>\n",
685
- " <td>2022-01-05</td>\n",
686
- " </tr>\n",
687
- " <tr>\n",
688
- " <th>244</th>\n",
689
- " <td>-0.042238</td>\n",
690
- " <td>-0.008112</td>\n",
691
- " <td>0.069522</td>\n",
692
- " <td>0.001490</td>\n",
693
- " <td>2.101118</td>\n",
694
- " <td>0.883542</td>\n",
695
- " <td>-0.111761</td>\n",
696
- " <td>1.867445</td>\n",
697
- " <td>2022-01-06</td>\n",
698
- " </tr>\n",
699
- " <tr>\n",
700
- " <th>245</th>\n",
701
- " <td>-0.073118</td>\n",
702
- " <td>-0.031015</td>\n",
703
- " <td>0.062056</td>\n",
704
- " <td>-0.006981</td>\n",
705
- " <td>2.105760</td>\n",
706
- " <td>0.881986</td>\n",
707
- " <td>-0.135174</td>\n",
708
- " <td>1.875959</td>\n",
709
- " <td>2022-01-07</td>\n",
710
- " </tr>\n",
711
- " <tr>\n",
712
- " <th>246</th>\n",
713
- " <td>-0.029944</td>\n",
714
- " <td>0.044300</td>\n",
715
- " <td>0.064588</td>\n",
716
- " <td>0.002384</td>\n",
717
- " <td>2.106749</td>\n",
718
- " <td>0.880502</td>\n",
719
- " <td>-0.094532</td>\n",
720
- " <td>1.880060</td>\n",
721
- " <td>2022-01-10</td>\n",
722
- " </tr>\n",
723
- " </tbody>\n",
724
- "</table>\n",
725
- "<p>247 rows × 9 columns</p>\n",
726
- "</div>"
727
- ],
728
- "text/plain": [
729
- " return_p pct_p return_b pct_b risk_p risk_b \\\n",
730
- "0 0.000000 0.000000 0.000000 0.000000 NaN NaN \n",
731
- "1 0.012146 0.012146 -0.001934 -0.001934 0.136341 0.021705 \n",
732
- "2 0.086830 0.074233 -0.000811 0.001125 0.746402 0.015414 \n",
733
- "3 0.089435 0.002496 0.002535 0.003349 0.756382 0.030137 \n",
734
- "4 0.148063 0.029363 -0.013015 -0.015511 0.970984 0.095654 \n",
735
- ".. ... ... ... ... ... ... \n",
736
- "242 0.028005 -0.071081 0.086827 0.000156 2.097631 0.886298 \n",
737
- "243 -0.033053 -0.059582 0.067931 -0.017386 2.099052 0.884891 \n",
738
- "244 -0.042238 -0.008112 0.069522 0.001490 2.101118 0.883542 \n",
739
- "245 -0.073118 -0.031015 0.062056 -0.006981 2.105760 0.881986 \n",
740
- "246 -0.029944 0.044300 0.064588 0.002384 2.106749 0.880502 \n",
741
- "\n",
742
- " active_return tracking_error date \n",
743
- "0 0.000000 NaN 2021-01-05 \n",
744
- "1 0.014080 0.158046 2021-01-06 \n",
745
- "2 0.087641 0.747127 2021-01-07 \n",
746
- "3 0.086900 0.740979 2021-01-08 \n",
747
- "4 0.161078 1.032423 2021-01-11 \n",
748
- ".. ... ... ... \n",
749
- "242 -0.058822 1.856213 2022-01-04 \n",
750
- "243 -0.100984 1.861347 2022-01-05 \n",
751
- "244 -0.111761 1.867445 2022-01-06 \n",
752
- "245 -0.135174 1.875959 2022-01-07 \n",
753
- "246 -0.094532 1.880060 2022-01-10 \n",
754
- "\n",
755
- "[247 rows x 9 columns]"
756
- ]
757
- },
758
- "execution_count": 202,
759
- "metadata": {},
760
- "output_type": "execute_result"
761
- }
762
- ],
763
- "source": [
764
- "# add mkt cap\n",
765
- "portfolio_risk_by_date_df"
766
- ]
767
- },
768
- {
769
- "cell_type": "code",
770
- "execution_count": 217,
771
- "metadata": {},
772
- "outputs": [
773
- {
774
- "data": {
775
- "text/plain": [
776
- "date\n",
777
- "2021-01-05 600\n",
778
- "2021-01-10 1550\n",
779
- "Name: weight, dtype: int64"
780
- ]
781
- },
782
- "execution_count": 217,
783
- "metadata": {},
784
- "output_type": "execute_result"
785
- }
786
- ],
787
- "source": [
788
- "profile_df.groupby('date')['weight'].sum()\n",
789
- "\n",
790
- "# for i in range(1, len(portfolio_risk_by_date_df)):\n",
791
- "# cur_mkt = portfolio_risk_by_date_df.loc[i, 'mkt_cap']\n",
792
- "# if pd.isna(cur_mkt):\n",
793
- "# portfolio_risk_by_date_df.loc[i, 'mkt_cap'] = portfolio_risk_by_date_df.loc[i-1, 'mkt_cap'] * (1 + portfolio_risk_by_date_df.loc[i, 'pct_p'])\n",
794
- " "
795
- ]
796
- },
797
- {
798
- "cell_type": "code",
799
- "execution_count": 216,
800
- "metadata": {},
801
- "outputs": [
802
- {
803
- "data": {
804
- "text/html": [
805
- "<div>\n",
806
- "<style scoped>\n",
807
- " .dataframe tbody tr th:only-of-type {\n",
808
- " vertical-align: middle;\n",
809
- " }\n",
810
- "\n",
811
- " .dataframe tbody tr th {\n",
812
- " vertical-align: top;\n",
813
- " }\n",
814
- "\n",
815
- " .dataframe thead th {\n",
816
- " text-align: right;\n",
817
- " }\n",
818
- "</style>\n",
819
- "<table border=\"1\" class=\"dataframe\">\n",
820
- " <thead>\n",
821
- " <tr style=\"text-align: right;\">\n",
822
- " <th></th>\n",
823
- " <th>return_p</th>\n",
824
- " <th>pct_p</th>\n",
825
- " <th>return_b</th>\n",
826
- " <th>pct_b</th>\n",
827
- " <th>risk_p</th>\n",
828
- " <th>risk_b</th>\n",
829
- " <th>active_return</th>\n",
830
- " <th>tracking_error</th>\n",
831
- " <th>date</th>\n",
832
- " <th>mkt_cap</th>\n",
833
- " </tr>\n",
834
- " </thead>\n",
835
- " <tbody>\n",
836
- " <tr>\n",
837
- " <th>0</th>\n",
838
- " <td>0.0</td>\n",
839
- " <td>0.0</td>\n",
840
- " <td>0.0</td>\n",
841
- " <td>0.0</td>\n",
842
- " <td>NaN</td>\n",
843
- " <td>NaN</td>\n",
844
- " <td>0.0</td>\n",
845
- " <td>NaN</td>\n",
846
- " <td>2021-01-05</td>\n",
847
- " <td>600.0</td>\n",
848
- " </tr>\n",
849
- " </tbody>\n",
850
- "</table>\n",
851
- "</div>"
852
- ],
853
- "text/plain": [
854
- " return_p pct_p return_b pct_b risk_p risk_b active_return \\\n",
855
- "0 0.0 0.0 0.0 0.0 NaN NaN 0.0 \n",
856
- "\n",
857
- " tracking_error date mkt_cap \n",
858
- "0 NaN 2021-01-05 600.0 "
859
- ]
860
- },
861
- "execution_count": 216,
862
- "metadata": {},
863
- "output_type": "execute_result"
864
- }
865
- ],
866
- "source": [
867
- "# display row where mkt_cap is not nana\n",
868
- "portfolio_risk_by_date_df[portfolio_risk_by_date_df['mkt_cap'].notna()]"
869
- ]
870
- },
871
- {
872
- "cell_type": "code",
873
- "execution_count": null,
874
- "metadata": {},
875
- "outputs": [
876
- {
877
- "name": "stderr",
878
- "output_type": "stream",
879
- "text": [
880
- "/var/folders/v5/2108rh5964q9j741wg_s8r1w0000gn/T/ipykernel_23255/2871737262.py:10: SettingWithCopyWarning: \n",
881
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
882
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
883
- "\n",
884
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
885
- " pct['weighted_pct'] = pct['pct'] * pct['norm_weight']\n"
886
- ]
887
- },
888
- {
889
- "data": {
890
- "text/html": [
891
- "<div>\n",
892
- "<style scoped>\n",
893
- " .dataframe tbody tr th:only-of-type {\n",
894
- " vertical-align: middle;\n",
895
- " }\n",
896
- "\n",
897
- " .dataframe tbody tr th {\n",
898
- " vertical-align: top;\n",
899
- " }\n",
900
- "\n",
901
- " .dataframe thead th {\n",
902
- " text-align: right;\n",
903
- " }\n",
904
- "</style>\n",
905
- "<table border=\"1\" class=\"dataframe\">\n",
906
- " <thead>\n",
907
- " <tr style=\"text-align: right;\">\n",
908
- " <th></th>\n",
909
- " <th>date</th>\n",
910
- " <th>return</th>\n",
911
- " <th>pct</th>\n",
912
- " </tr>\n",
913
- " </thead>\n",
914
- " <tbody>\n",
915
- " <tr>\n",
916
- " <th>0</th>\n",
917
- " <td>2021-01-05</td>\n",
918
- " <td>0.000000</td>\n",
919
- " <td>0.000000</td>\n",
920
- " </tr>\n",
921
- " <tr>\n",
922
- " <th>1</th>\n",
923
- " <td>2021-01-06</td>\n",
924
- " <td>0.007011</td>\n",
925
- " <td>0.036439</td>\n",
926
- " </tr>\n",
927
- " <tr>\n",
928
- " <th>2</th>\n",
929
- " <td>2021-01-07</td>\n",
930
- " <td>0.047531</td>\n",
931
- " <td>0.218707</td>\n",
932
- " </tr>\n",
933
- " <tr>\n",
934
- " <th>3</th>\n",
935
- " <td>2021-01-08</td>\n",
936
- " <td>0.047111</td>\n",
937
- " <td>0.013639</td>\n",
938
- " </tr>\n",
939
- " <tr>\n",
940
- " <th>4</th>\n",
941
- " <td>2021-01-11</td>\n",
942
- " <td>0.052768</td>\n",
943
- " <td>0.014559</td>\n",
944
- " </tr>\n",
945
- " <tr>\n",
946
- " <th>...</th>\n",
947
- " <td>...</td>\n",
948
- " <td>...</td>\n",
949
- " <td>...</td>\n",
950
- " </tr>\n",
951
- " <tr>\n",
952
- " <th>242</th>\n",
953
- " <td>2022-01-04</td>\n",
954
- " <td>0.363845</td>\n",
955
- " <td>-0.199827</td>\n",
956
- " </tr>\n",
957
- " <tr>\n",
958
- " <th>243</th>\n",
959
- " <td>2022-01-05</td>\n",
960
- " <td>0.306697</td>\n",
961
- " <td>-0.193598</td>\n",
962
- " </tr>\n",
963
- " <tr>\n",
964
- " <th>244</th>\n",
965
- " <td>2022-01-06</td>\n",
966
- " <td>0.331291</td>\n",
967
- " <td>0.023418</td>\n",
968
- " </tr>\n",
969
- " <tr>\n",
970
- " <th>245</th>\n",
971
- " <td>2022-01-07</td>\n",
972
- " <td>0.313726</td>\n",
973
- " <td>-0.080728</td>\n",
974
- " </tr>\n",
975
- " <tr>\n",
976
- " <th>246</th>\n",
977
- " <td>2022-01-10</td>\n",
978
- " <td>0.313262</td>\n",
979
- " <td>0.110254</td>\n",
980
- " </tr>\n",
981
- " </tbody>\n",
982
- "</table>\n",
983
- "<p>247 rows × 3 columns</p>\n",
984
- "</div>"
985
- ],
986
- "text/plain": [
987
- " date return pct\n",
988
- "0 2021-01-05 0.000000 0.000000\n",
989
- "1 2021-01-06 0.007011 0.036439\n",
990
- "2 2021-01-07 0.047531 0.218707\n",
991
- "3 2021-01-08 0.047111 0.013639\n",
992
- "4 2021-01-11 0.052768 0.014559\n",
993
- ".. ... ... ...\n",
994
- "242 2022-01-04 0.363845 -0.199827\n",
995
- "243 2022-01-05 0.306697 -0.193598\n",
996
- "244 2022-01-06 0.331291 0.023418\n",
997
- "245 2022-01-07 0.313726 -0.080728\n",
998
- "246 2022-01-10 0.313262 0.110254\n",
999
- "\n",
1000
- "[247 rows x 3 columns]"
1001
- ]
1002
- },
1003
- "execution_count": 191,
1004
- "metadata": {},
1005
- "output_type": "execute_result"
1006
- }
1007
- ],
1008
- "source": [
1009
- "## aggregate by date\n",
1010
- "# step 7 aggregate (get portfolio return and pct(change of daily return))by date\n",
1011
- "def create_agg_by_date(stock_df):\n",
1012
- " # sum up weighted return to get return \n",
1013
- " agg_return = stock_df.groupby(['date'])['weighted_return'].sum().reset_index()\n",
1014
- " agg_return.rename(columns={'weighted_return':'return'}, inplace=True)\n",
1015
- "\n",
1016
- " # sum up weighted pct to get pct\n",
1017
- " pct = stock_df[['date','pct','norm_weight','ticker']]\n",
1018
- " pct['weighted_pct'] = pct['pct'] * pct['norm_weight']\n",
1019
- " agg_pct = pct.groupby(['date'])['pct'].sum().reset_index()\n",
1020
- "\n",
1021
- " agg_df = pd.merge(agg_return, agg_pct, on='date', how='outer')\n",
1022
- " return agg_df\n",
1023
- "\n",
1024
- "\n",
1025
- "\n",
1026
- "p_perform_result = create_agg_by_date(p_stock_df)\n",
1027
- "p_perform_result"
1028
- ]
1029
- },
1030
- {
1031
- "cell_type": "code",
1032
- "execution_count": null,
1033
- "metadata": {},
1034
- "outputs": [
1035
- {
1036
- "data": {
1037
- "text/html": [
1038
- "<div>\n",
1039
- "<style scoped>\n",
1040
- " .dataframe tbody tr th:only-of-type {\n",
1041
- " vertical-align: middle;\n",
1042
- " }\n",
1043
- "\n",
1044
- " .dataframe tbody tr th {\n",
1045
- " vertical-align: top;\n",
1046
- " }\n",
1047
- "\n",
1048
- " .dataframe thead th {\n",
1049
- " text-align: right;\n",
1050
- " }\n",
1051
- "</style>\n",
1052
- "<table border=\"1\" class=\"dataframe\">\n",
1053
- " <thead>\n",
1054
- " <tr style=\"text-align: right;\">\n",
1055
- " <th></th>\n",
1056
- " <th>ticker</th>\n",
1057
- " <th>date</th>\n",
1058
- " <th>open</th>\n",
1059
- " <th>close</th>\n",
1060
- " <th>high</th>\n",
1061
- " <th>low</th>\n",
1062
- " <th>volume</th>\n",
1063
- " <th>money</th>\n",
1064
- " <th>pct</th>\n",
1065
- " <th>weight</th>\n",
1066
- " <th>return</th>\n",
1067
- " <th>norm_weight</th>\n",
1068
- " <th>weighted_return</th>\n",
1069
- " <th>aggregate_sector</th>\n",
1070
- " <th>display_name</th>\n",
1071
- " </tr>\n",
1072
- " </thead>\n",
1073
- " <tbody>\n",
1074
- " <tr>\n",
1075
- " <th>1452</th>\n",
1076
- " <td>603882.XSHG</td>\n",
1077
- " <td>2022-01-04</td>\n",
1078
- " <td>106.89</td>\n",
1079
- " <td>98.84</td>\n",
1080
- " <td>106.89</td>\n",
1081
- " <td>98.67</td>\n",
1082
- " <td>5140406.0</td>\n",
1083
- " <td>5.181929e+08</td>\n",
1084
- " <td>-0.076262</td>\n",
1085
- " <td>79.300385</td>\n",
1086
- " <td>-0.206996</td>\n",
1087
- " <td>0.107586</td>\n",
1088
- " <td>-0.022270</td>\n",
1089
- " <td>医药卫生</td>\n",
1090
- " <td>金域医学</td>\n",
1091
- " </tr>\n",
1092
- " <tr>\n",
1093
- " <th>1453</th>\n",
1094
- " <td>002709.XSHE</td>\n",
1095
- " <td>2022-01-04</td>\n",
1096
- " <td>57.64</td>\n",
1097
- " <td>54.64</td>\n",
1098
- " <td>57.87</td>\n",
1099
- " <td>54.29</td>\n",
1100
- " <td>42150916.0</td>\n",
1101
- " <td>2.333429e+09</td>\n",
1102
- " <td>-0.028277</td>\n",
1103
- " <td>161.227501</td>\n",
1104
- " <td>0.612275</td>\n",
1105
- " <td>0.218735</td>\n",
1106
- " <td>0.133926</td>\n",
1107
- " <td>工业</td>\n",
1108
- " <td>天赐材料</td>\n",
1109
- " </tr>\n",
1110
- " <tr>\n",
1111
- " <th>1454</th>\n",
1112
- " <td>600409.XSHG</td>\n",
1113
- " <td>2022-01-04</td>\n",
1114
- " <td>8.16</td>\n",
1115
- " <td>8.21</td>\n",
1116
- " <td>8.25</td>\n",
1117
- " <td>8.15</td>\n",
1118
- " <td>27288613.0</td>\n",
1119
- " <td>2.237925e+08</td>\n",
1120
- " <td>0.007362</td>\n",
1121
- " <td>85.788924</td>\n",
1122
- " <td>-0.142111</td>\n",
1123
- " <td>0.116389</td>\n",
1124
- " <td>-0.016540</td>\n",
1125
- " <td>原料与能源</td>\n",
1126
- " <td>三友化工</td>\n",
1127
- " </tr>\n",
1128
- " <tr>\n",
1129
- " <th>1455</th>\n",
1130
- " <td>002920.XSHE</td>\n",
1131
- " <td>2022-01-04</td>\n",
1132
- " <td>139.71</td>\n",
1133
- " <td>131.69</td>\n",
1134
- " <td>140.91</td>\n",
1135
- " <td>131.45</td>\n",
1136
- " <td>5410083.0</td>\n",
1137
- " <td>7.233361e+08</td>\n",
1138
- " <td>-0.060833</td>\n",
1139
- " <td>150.934097</td>\n",
1140
- " <td>0.509341</td>\n",
1141
- " <td>0.204770</td>\n",
1142
- " <td>0.104298</td>\n",
1143
- " <td>信息与通信</td>\n",
1144
- " <td>德赛西威</td>\n",
1145
- " </tr>\n",
1146
- " <tr>\n",
1147
- " <th>1456</th>\n",
1148
- " <td>300274.XSHE</td>\n",
1149
- " <td>2022-01-04</td>\n",
1150
- " <td>146.52</td>\n",
1151
- " <td>134.96</td>\n",
1152
- " <td>148.46</td>\n",
1153
- " <td>134.61</td>\n",
1154
- " <td>24205007.0</td>\n",
1155
- " <td>3.333125e+09</td>\n",
1156
- " <td>-0.071291</td>\n",
1157
- " <td>176.533682</td>\n",
1158
- " <td>0.765337</td>\n",
1159
- " <td>0.239501</td>\n",
1160
- " <td>0.183299</td>\n",
1161
- " <td>工业</td>\n",
1162
- " <td>阳光电源</td>\n",
1163
- " </tr>\n",
1164
- " <tr>\n",
1165
- " <th>1457</th>\n",
1166
- " <td>600415.XSHG</td>\n",
1167
- " <td>2022-01-04</td>\n",
1168
- " <td>4.80</td>\n",
1169
- " <td>4.89</td>\n",
1170
- " <td>4.90</td>\n",
1171
- " <td>4.78</td>\n",
1172
- " <td>58291943.0</td>\n",
1173
- " <td>2.832956e+08</td>\n",
1174
- " <td>0.029474</td>\n",
1175
- " <td>83.304940</td>\n",
1176
- " <td>-0.166951</td>\n",
1177
- " <td>0.113019</td>\n",
1178
- " <td>-0.018869</td>\n",
1179
- " <td>消费</td>\n",
1180
- " <td>小商品城</td>\n",
1181
- " </tr>\n",
1182
- " </tbody>\n",
1183
- "</table>\n",
1184
- "</div>"
1185
- ],
1186
- "text/plain": [
1187
- " ticker date open close high low volume \\\n",
1188
- "1452 603882.XSHG 2022-01-04 106.89 98.84 106.89 98.67 5140406.0 \n",
1189
- "1453 002709.XSHE 2022-01-04 57.64 54.64 57.87 54.29 42150916.0 \n",
1190
- "1454 600409.XSHG 2022-01-04 8.16 8.21 8.25 8.15 27288613.0 \n",
1191
- "1455 002920.XSHE 2022-01-04 139.71 131.69 140.91 131.45 5410083.0 \n",
1192
- "1456 300274.XSHE 2022-01-04 146.52 134.96 148.46 134.61 24205007.0 \n",
1193
- "1457 600415.XSHG 2022-01-04 4.80 4.89 4.90 4.78 58291943.0 \n",
1194
- "\n",
1195
- " money pct weight return norm_weight \\\n",
1196
- "1452 5.181929e+08 -0.076262 79.300385 -0.206996 0.107586 \n",
1197
- "1453 2.333429e+09 -0.028277 161.227501 0.612275 0.218735 \n",
1198
- "1454 2.237925e+08 0.007362 85.788924 -0.142111 0.116389 \n",
1199
- "1455 7.233361e+08 -0.060833 150.934097 0.509341 0.204770 \n",
1200
- "1456 3.333125e+09 -0.071291 176.533682 0.765337 0.239501 \n",
1201
- "1457 2.832956e+08 0.029474 83.304940 -0.166951 0.113019 \n",
1202
- "\n",
1203
- " weighted_return aggregate_sector display_name \n",
1204
- "1452 -0.022270 医药卫生 金域医学 \n",
1205
- "1453 0.133926 工业 天赐材料 \n",
1206
- "1454 -0.016540 原料与能源 三友化工 \n",
1207
- "1455 0.104298 信息与通信 德赛西威 \n",
1208
- "1456 0.183299 工业 阳光电源 \n",
1209
- "1457 -0.018869 消费 小商品城 "
1210
- ]
1211
- },
1212
- "execution_count": 194,
1213
- "metadata": {},
1214
- "output_type": "execute_result"
1215
- }
1216
- ],
1217
- "source": [
1218
- "p_stock_df[p_stock_df.date==datetime(2022,1,4)]"
1219
- ]
1220
- },
1221
- {
1222
- "cell_type": "code",
1223
- "execution_count": null,
1224
- "metadata": {},
1225
- "outputs": [
1226
- {
1227
- "data": {
1228
- "text/html": [
1229
- "<div>\n",
1230
- "<style scoped>\n",
1231
- " .dataframe tbody tr th:only-of-type {\n",
1232
- " vertical-align: middle;\n",
1233
- " }\n",
1234
- "\n",
1235
- " .dataframe tbody tr th {\n",
1236
- " vertical-align: top;\n",
1237
- " }\n",
1238
- "\n",
1239
- " .dataframe thead th {\n",
1240
- " text-align: right;\n",
1241
- " }\n",
1242
- "</style>\n",
1243
- "<table border=\"1\" class=\"dataframe\">\n",
1244
- " <thead>\n",
1245
- " <tr style=\"text-align: right;\">\n",
1246
- " <th></th>\n",
1247
- " <th>date</th>\n",
1248
- " <th>mkt_cap</th>\n",
1249
- " </tr>\n",
1250
- " </thead>\n",
1251
- " <tbody>\n",
1252
- " <tr>\n",
1253
- " <th>0</th>\n",
1254
- " <td>2021-01-05</td>\n",
1255
- " <td>600</td>\n",
1256
- " </tr>\n",
1257
- " <tr>\n",
1258
- " <th>1</th>\n",
1259
- " <td>2021-01-10</td>\n",
1260
- " <td>1550</td>\n",
1261
- " </tr>\n",
1262
- " </tbody>\n",
1263
- "</table>\n",
1264
- "</div>"
1265
- ],
1266
- "text/plain": [
1267
- " date mkt_cap\n",
1268
- "0 2021-01-05 600\n",
1269
- "1 2021-01-10 1550"
1270
- ]
1271
- },
1272
- "execution_count": 102,
1273
- "metadata": {},
1274
- "output_type": "execute_result"
1275
- }
1276
- ],
1277
- "source": [
1278
- "mkt_cap_df = pd.DataFrame(profile_df.groupby(['date'])['weight'].sum()).reset_index()\n",
1279
- "mkt_cap_df.rename(columns={'weight':'mkt_cap'}, inplace=True)\n",
1280
- "mkt_cap_df"
1281
- ]
1282
- },
1283
- {
1284
- "cell_type": "code",
1285
- "execution_count": null,
1286
- "metadata": {},
1287
- "outputs": [
1288
- {
1289
- "data": {
1290
- "text/html": [
1291
- "<div>\n",
1292
- "<style scoped>\n",
1293
- " .dataframe tbody tr th:only-of-type {\n",
1294
- " vertical-align: middle;\n",
1295
- " }\n",
1296
- "\n",
1297
- " .dataframe tbody tr th {\n",
1298
- " vertical-align: top;\n",
1299
- " }\n",
1300
- "\n",
1301
- " .dataframe thead th {\n",
1302
- " text-align: right;\n",
1303
- " }\n",
1304
- "</style>\n",
1305
- "<table border=\"1\" class=\"dataframe\">\n",
1306
- " <thead>\n",
1307
- " <tr style=\"text-align: right;\">\n",
1308
- " <th></th>\n",
1309
- " <th>date</th>\n",
1310
- " <th>return</th>\n",
1311
- " <th>pct</th>\n",
1312
- " <th>mkt_cap</th>\n",
1313
- " </tr>\n",
1314
- " </thead>\n",
1315
- " <tbody>\n",
1316
- " <tr>\n",
1317
- " <th>0</th>\n",
1318
- " <td>2021-01-05</td>\n",
1319
- " <td>0.000000</td>\n",
1320
- " <td>0.000000</td>\n",
1321
- " <td>600.000000</td>\n",
1322
- " </tr>\n",
1323
- " <tr>\n",
1324
- " <th>1</th>\n",
1325
- " <td>2021-01-06</td>\n",
1326
- " <td>0.007011</td>\n",
1327
- " <td>0.036439</td>\n",
1328
- " <td>621.863161</td>\n",
1329
- " </tr>\n",
1330
- " <tr>\n",
1331
- " <th>2</th>\n",
1332
- " <td>2021-01-07</td>\n",
1333
- " <td>0.047531</td>\n",
1334
- " <td>0.218707</td>\n",
1335
- " <td>757.869005</td>\n",
1336
- " </tr>\n",
1337
- " <tr>\n",
1338
- " <th>3</th>\n",
1339
- " <td>2021-01-08</td>\n",
1340
- " <td>0.047111</td>\n",
1341
- " <td>0.013639</td>\n",
1342
- " <td>768.205269</td>\n",
1343
- " </tr>\n",
1344
- " </tbody>\n",
1345
- "</table>\n",
1346
- "</div>"
1347
- ],
1348
- "text/plain": [
1349
- " date return pct mkt_cap\n",
1350
- "0 2021-01-05 0.000000 0.000000 600.000000\n",
1351
- "1 2021-01-06 0.007011 0.036439 621.863161\n",
1352
- "2 2021-01-07 0.047531 0.218707 757.869005\n",
1353
- "3 2021-01-08 0.047111 0.013639 768.205269"
1354
- ]
1355
- },
1356
- "execution_count": 103,
1357
- "metadata": {},
1358
- "output_type": "execute_result"
1359
- }
1360
- ],
1361
- "source": [
1362
- "# get mkt adjustment (weight is the fund in a stock)\n",
1363
- "mkt_adjustment = pd.DataFrame(profile_df.groupby(['date'])['weight'].sum()).reset_index()\n",
1364
- "mkt_adjustment.rename(columns={'weight':'mkt_cap'}, inplace=True)\n",
1365
- "merge_df = p_perform_result.merge(mkt_adjustment, on='date', how='outer')\n",
1366
- "\n",
1367
- "\n",
1368
- "for i in range(1, len(merge_df)):\n",
1369
- " merge_df.loc[i, 'mkt_cap'] = merge_df.loc[i-1, 'mkt_cap'] * (1 + merge_df.loc[i, 'pct'])\n",
1370
- "\n",
1371
- "# # calculate daily mkt_cap\n",
1372
- "# # initial_mkt_cap = merge_df.loc[0, 'mkt_cap']\n",
1373
- "# for i in range(1, len(merge_df)):\n",
1374
- "# row = merge_df.loc[i]\n",
1375
- "# if pd.isna(row['mkt_cap']):\n",
1376
- "# merge_df.loc[i, 'mkt_cap'] = merge_df.loc[i-1, 'mkt_cap'] * (1 + merge_df.loc[i, 'pct_portfolio'])\n",
1377
- " \n",
1378
- "# # step 8 calculate daily mkt cap\n",
1379
- "\n",
1380
- "merge_df[merge_df.date < datetime(2021,1,10)]"
1381
- ]
1382
- },
1383
- {
1384
- "cell_type": "code",
1385
- "execution_count": null,
1386
- "metadata": {},
1387
- "outputs": [
1388
- {
1389
- "data": {
1390
- "text/html": [
1391
- "<div>\n",
1392
- "<style scoped>\n",
1393
- " .dataframe tbody tr th:only-of-type {\n",
1394
- " vertical-align: middle;\n",
1395
- " }\n",
1396
- "\n",
1397
- " .dataframe tbody tr th {\n",
1398
- " vertical-align: top;\n",
1399
- " }\n",
1400
- "\n",
1401
- " .dataframe thead th {\n",
1402
- " text-align: right;\n",
1403
- " }\n",
1404
- "</style>\n",
1405
- "<table border=\"1\" class=\"dataframe\">\n",
1406
- " <thead>\n",
1407
- " <tr style=\"text-align: right;\">\n",
1408
- " <th></th>\n",
1409
- " <th>ticker</th>\n",
1410
- " <th>date</th>\n",
1411
- " <th>open</th>\n",
1412
- " <th>close</th>\n",
1413
- " <th>high</th>\n",
1414
- " <th>low</th>\n",
1415
- " <th>volume</th>\n",
1416
- " <th>money</th>\n",
1417
- " <th>pct</th>\n",
1418
- " <th>weight</th>\n",
1419
- " <th>return</th>\n",
1420
- " <th>norm_weight</th>\n",
1421
- " <th>weighted_return</th>\n",
1422
- " <th>aggregate_sector</th>\n",
1423
- " <th>display_name</th>\n",
1424
- " </tr>\n",
1425
- " </thead>\n",
1426
- " <tbody>\n",
1427
- " <tr>\n",
1428
- " <th>0</th>\n",
1429
- " <td>002709.XSHE</td>\n",
1430
- " <td>2021-01-05</td>\n",
1431
- " <td>32.54</td>\n",
1432
- " <td>33.89</td>\n",
1433
- " <td>34.22</td>\n",
1434
- " <td>31.39</td>\n",
1435
- " <td>59152352.0</td>\n",
1436
- " <td>1.942406e+09</td>\n",
1437
- " <td>NaN</td>\n",
1438
- " <td>100.000000</td>\n",
1439
- " <td>0.000000</td>\n",
1440
- " <td>0.166667</td>\n",
1441
- " <td>0.000000</td>\n",
1442
- " <td>工业</td>\n",
1443
- " <td>天赐材料</td>\n",
1444
- " </tr>\n",
1445
- " <tr>\n",
1446
- " <th>1</th>\n",
1447
- " <td>600415.XSHG</td>\n",
1448
- " <td>2021-01-05</td>\n",
1449
- " <td>5.33</td>\n",
1450
- " <td>5.87</td>\n",
1451
- " <td>5.87</td>\n",
1452
- " <td>5.22</td>\n",
1453
- " <td>180936477.0</td>\n",
1454
- " <td>1.010225e+09</td>\n",
1455
- " <td>NaN</td>\n",
1456
- " <td>100.000000</td>\n",
1457
- " <td>0.000000</td>\n",
1458
- " <td>0.166667</td>\n",
1459
- " <td>0.000000</td>\n",
1460
- " <td>消费</td>\n",
1461
- " <td>小商品城</td>\n",
1462
- " </tr>\n",
1463
- " <tr>\n",
1464
- " <th>2</th>\n",
1465
- " <td>600409.XSHG</td>\n",
1466
- " <td>2021-01-05</td>\n",
1467
- " <td>9.23</td>\n",
1468
- " <td>9.57</td>\n",
1469
- " <td>9.66</td>\n",
1470
- " <td>9.08</td>\n",
1471
- " <td>82669289.0</td>\n",
1472
- " <td>7.803391e+08</td>\n",
1473
- " <td>NaN</td>\n",
1474
- " <td>100.000000</td>\n",
1475
- " <td>0.000000</td>\n",
1476
- " <td>0.166667</td>\n",
1477
- " <td>0.000000</td>\n",
1478
- " <td>原料与能源</td>\n",
1479
- " <td>三友化工</td>\n",
1480
- " </tr>\n",
1481
- " <tr>\n",
1482
- " <th>3</th>\n",
1483
- " <td>300274.XSHE</td>\n",
1484
- " <td>2021-01-05</td>\n",
1485
- " <td>76.03</td>\n",
1486
- " <td>76.45</td>\n",
1487
- " <td>80.20</td>\n",
1488
- " <td>75.27</td>\n",
1489
- " <td>51384827.0</td>\n",
1490
- " <td>3.961995e+09</td>\n",
1491
- " <td>NaN</td>\n",
1492
- " <td>100.000000</td>\n",
1493
- " <td>0.000000</td>\n",
1494
- " <td>0.166667</td>\n",
1495
- " <td>0.000000</td>\n",
1496
- " <td>工业</td>\n",
1497
- " <td>阳光电源</td>\n",
1498
- " </tr>\n",
1499
- " <tr>\n",
1500
- " <th>4</th>\n",
1501
- " <td>002920.XSHE</td>\n",
1502
- " <td>2021-01-05</td>\n",
1503
- " <td>85.44</td>\n",
1504
- " <td>87.25</td>\n",
1505
- " <td>87.95</td>\n",
1506
- " <td>84.07</td>\n",
1507
- " <td>3852674.0</td>\n",
1508
- " <td>3.322598e+08</td>\n",
1509
- " <td>NaN</td>\n",
1510
- " <td>100.000000</td>\n",
1511
- " <td>0.000000</td>\n",
1512
- " <td>0.166667</td>\n",
1513
- " <td>0.000000</td>\n",
1514
- " <td>信息与通信</td>\n",
1515
- " <td>德赛西威</td>\n",
1516
- " </tr>\n",
1517
- " <tr>\n",
1518
- " <th>...</th>\n",
1519
- " <td>...</td>\n",
1520
- " <td>...</td>\n",
1521
- " <td>...</td>\n",
1522
- " <td>...</td>\n",
1523
- " <td>...</td>\n",
1524
- " <td>...</td>\n",
1525
- " <td>...</td>\n",
1526
- " <td>...</td>\n",
1527
- " <td>...</td>\n",
1528
- " <td>...</td>\n",
1529
- " <td>...</td>\n",
1530
- " <td>...</td>\n",
1531
- " <td>...</td>\n",
1532
- " <td>...</td>\n",
1533
- " <td>...</td>\n",
1534
- " </tr>\n",
1535
- " <tr>\n",
1536
- " <th>1477</th>\n",
1537
- " <td>600409.XSHG</td>\n",
1538
- " <td>2022-01-10</td>\n",
1539
- " <td>8.24</td>\n",
1540
- " <td>8.35</td>\n",
1541
- " <td>8.39</td>\n",
1542
- " <td>8.21</td>\n",
1543
- " <td>32516017.0</td>\n",
1544
- " <td>2.699300e+08</td>\n",
1545
- " <td>0.015815</td>\n",
1546
- " <td>87.251829</td>\n",
1547
- " <td>-0.127482</td>\n",
1548
- " <td>0.121949</td>\n",
1549
- " <td>-0.015546</td>\n",
1550
- " <td>原料与能源</td>\n",
1551
- " <td>三友化工</td>\n",
1552
- " </tr>\n",
1553
- " <tr>\n",
1554
- " <th>1478</th>\n",
1555
- " <td>002920.XSHE</td>\n",
1556
- " <td>2022-01-10</td>\n",
1557
- " <td>130.36</td>\n",
1558
- " <td>138.43</td>\n",
1559
- " <td>141.96</td>\n",
1560
- " <td>130.11</td>\n",
1561
- " <td>5005400.0</td>\n",
1562
- " <td>6.901614e+08</td>\n",
1563
- " <td>0.046888</td>\n",
1564
- " <td>158.659026</td>\n",
1565
- " <td>0.586590</td>\n",
1566
- " <td>0.221752</td>\n",
1567
- " <td>0.130077</td>\n",
1568
- " <td>信息与通信</td>\n",
1569
- " <td>德赛西威</td>\n",
1570
- " </tr>\n",
1571
- " <tr>\n",
1572
- " <th>1479</th>\n",
1573
- " <td>002709.XSHE</td>\n",
1574
- " <td>2022-01-10</td>\n",
1575
- " <td>51.63</td>\n",
1576
- " <td>50.73</td>\n",
1577
- " <td>51.93</td>\n",
1578
- " <td>50.03</td>\n",
1579
- " <td>29821246.0</td>\n",
1580
- " <td>1.518902e+09</td>\n",
1581
- " <td>-0.019142</td>\n",
1582
- " <td>149.690174</td>\n",
1583
- " <td>0.496902</td>\n",
1584
- " <td>0.209216</td>\n",
1585
- " <td>0.103960</td>\n",
1586
- " <td>工业</td>\n",
1587
- " <td>天赐材料</td>\n",
1588
- " </tr>\n",
1589
- " <tr>\n",
1590
- " <th>1480</th>\n",
1591
- " <td>600415.XSHG</td>\n",
1592
- " <td>2022-01-10</td>\n",
1593
- " <td>4.70</td>\n",
1594
- " <td>4.75</td>\n",
1595
- " <td>4.85</td>\n",
1596
- " <td>4.67</td>\n",
1597
- " <td>39278041.0</td>\n",
1598
- " <td>1.859827e+08</td>\n",
1599
- " <td>0.010638</td>\n",
1600
- " <td>80.919932</td>\n",
1601
- " <td>-0.190801</td>\n",
1602
- " <td>0.113099</td>\n",
1603
- " <td>-0.021579</td>\n",
1604
- " <td>消费</td>\n",
1605
- " <td>小商品城</td>\n",
1606
- " </tr>\n",
1607
- " <tr>\n",
1608
- " <th>1481</th>\n",
1609
- " <td>603882.XSHG</td>\n",
1610
- " <td>2022-01-10</td>\n",
1611
- " <td>88.45</td>\n",
1612
- " <td>95.53</td>\n",
1613
- " <td>95.59</td>\n",
1614
- " <td>88.39</td>\n",
1615
- " <td>6991445.0</td>\n",
1616
- " <td>6.468392e+08</td>\n",
1617
- " <td>0.085692</td>\n",
1618
- " <td>76.644737</td>\n",
1619
- " <td>-0.233553</td>\n",
1620
- " <td>0.107123</td>\n",
1621
- " <td>-0.025019</td>\n",
1622
- " <td>医药卫生</td>\n",
1623
- " <td>金域医学</td>\n",
1624
- " </tr>\n",
1625
- " </tbody>\n",
1626
- "</table>\n",
1627
- "<p>1482 rows × 15 columns</p>\n",
1628
- "</div>"
1629
- ],
1630
- "text/plain": [
1631
- " ticker date open close high low volume \\\n",
1632
- "0 002709.XSHE 2021-01-05 32.54 33.89 34.22 31.39 59152352.0 \n",
1633
- "1 600415.XSHG 2021-01-05 5.33 5.87 5.87 5.22 180936477.0 \n",
1634
- "2 600409.XSHG 2021-01-05 9.23 9.57 9.66 9.08 82669289.0 \n",
1635
- "3 300274.XSHE 2021-01-05 76.03 76.45 80.20 75.27 51384827.0 \n",
1636
- "4 002920.XSHE 2021-01-05 85.44 87.25 87.95 84.07 3852674.0 \n",
1637
- "... ... ... ... ... ... ... ... \n",
1638
- "1477 600409.XSHG 2022-01-10 8.24 8.35 8.39 8.21 32516017.0 \n",
1639
- "1478 002920.XSHE 2022-01-10 130.36 138.43 141.96 130.11 5005400.0 \n",
1640
- "1479 002709.XSHE 2022-01-10 51.63 50.73 51.93 50.03 29821246.0 \n",
1641
- "1480 600415.XSHG 2022-01-10 4.70 4.75 4.85 4.67 39278041.0 \n",
1642
- "1481 603882.XSHG 2022-01-10 88.45 95.53 95.59 88.39 6991445.0 \n",
1643
- "\n",
1644
- " money pct weight return norm_weight \\\n",
1645
- "0 1.942406e+09 NaN 100.000000 0.000000 0.166667 \n",
1646
- "1 1.010225e+09 NaN 100.000000 0.000000 0.166667 \n",
1647
- "2 7.803391e+08 NaN 100.000000 0.000000 0.166667 \n",
1648
- "3 3.961995e+09 NaN 100.000000 0.000000 0.166667 \n",
1649
- "4 3.322598e+08 NaN 100.000000 0.000000 0.166667 \n",
1650
- "... ... ... ... ... ... \n",
1651
- "1477 2.699300e+08 0.015815 87.251829 -0.127482 0.121949 \n",
1652
- "1478 6.901614e+08 0.046888 158.659026 0.586590 0.221752 \n",
1653
- "1479 1.518902e+09 -0.019142 149.690174 0.496902 0.209216 \n",
1654
- "1480 1.859827e+08 0.010638 80.919932 -0.190801 0.113099 \n",
1655
- "1481 6.468392e+08 0.085692 76.644737 -0.233553 0.107123 \n",
1656
- "\n",
1657
- " weighted_return aggregate_sector display_name \n",
1658
- "0 0.000000 工业 天赐材料 \n",
1659
- "1 0.000000 消费 小商品城 \n",
1660
- "2 0.000000 原料与能源 三友化工 \n",
1661
- "3 0.000000 工业 阳光电源 \n",
1662
- "4 0.000000 信息与通信 德赛西威 \n",
1663
- "... ... ... ... \n",
1664
- "1477 -0.015546 原料与能源 三友化工 \n",
1665
- "1478 0.130077 信息与通信 德赛西威 \n",
1666
- "1479 0.103960 工业 天赐材料 \n",
1667
- "1480 -0.021579 消费 小商品城 \n",
1668
- "1481 -0.025019 医药卫生 金域医学 \n",
1669
- "\n",
1670
- "[1482 rows x 15 columns]"
1671
- ]
1672
- },
1673
- "execution_count": 127,
1674
- "metadata": {},
1675
- "output_type": "execute_result"
1676
- }
1677
- ],
1678
- "source": [
1679
- "## agg by sector and day\n",
1680
- "p_stock_df['weight_in_sector'] = p_stock_df.groupby"
1681
- ]
1682
- },
1683
- {
1684
- "cell_type": "code",
1685
- "execution_count": null,
1686
- "metadata": {},
1687
- "outputs": [],
1688
- "source": [
1689
- "def creaet_portfolio_return(stock_df):\n",
1690
- " portfolio_df = stock_df.groupby(['date'])['weighted_return'].sum().reset_index()\n",
1691
- " portfolio_df.rename(columns={'weighted_return':'portfolio_return'}, inplace=True)\n",
1692
- " return portfolio_df"
1693
- ]
1694
- },
1695
- {
1696
- "cell_type": "code",
1697
- "execution_count": null,
1698
- "metadata": {},
1699
- "outputs": [
1700
- {
1701
- "data": {
1702
- "text/html": [
1703
- "<div>\n",
1704
- "<style scoped>\n",
1705
- " .dataframe tbody tr th:only-of-type {\n",
1706
- " vertical-align: middle;\n",
1707
- " }\n",
1708
- "\n",
1709
- " .dataframe tbody tr th {\n",
1710
- " vertical-align: top;\n",
1711
- " }\n",
1712
- "\n",
1713
- " .dataframe thead th {\n",
1714
- " text-align: right;\n",
1715
- " }\n",
1716
- "</style>\n",
1717
- "<table border=\"1\" class=\"dataframe\">\n",
1718
- " <thead>\n",
1719
- " <tr style=\"text-align: right;\">\n",
1720
- " <th></th>\n",
1721
- " <th>date</th>\n",
1722
- " <th>portfolio_return</th>\n",
1723
- " </tr>\n",
1724
- " </thead>\n",
1725
- " <tbody>\n",
1726
- " <tr>\n",
1727
- " <th>0</th>\n",
1728
- " <td>2021-01-05</td>\n",
1729
- " <td>0.000000</td>\n",
1730
- " </tr>\n",
1731
- " <tr>\n",
1732
- " <th>1</th>\n",
1733
- " <td>2021-01-06</td>\n",
1734
- " <td>0.007011</td>\n",
1735
- " </tr>\n",
1736
- " <tr>\n",
1737
- " <th>2</th>\n",
1738
- " <td>2021-01-07</td>\n",
1739
- " <td>0.047531</td>\n",
1740
- " </tr>\n",
1741
- " <tr>\n",
1742
- " <th>3</th>\n",
1743
- " <td>2021-01-08</td>\n",
1744
- " <td>0.047111</td>\n",
1745
- " </tr>\n",
1746
- " <tr>\n",
1747
- " <th>4</th>\n",
1748
- " <td>2021-01-11</td>\n",
1749
- " <td>0.052768</td>\n",
1750
- " </tr>\n",
1751
- " <tr>\n",
1752
- " <th>...</th>\n",
1753
- " <td>...</td>\n",
1754
- " <td>...</td>\n",
1755
- " </tr>\n",
1756
- " <tr>\n",
1757
- " <th>242</th>\n",
1758
- " <td>2022-01-04</td>\n",
1759
- " <td>0.363845</td>\n",
1760
- " </tr>\n",
1761
- " <tr>\n",
1762
- " <th>243</th>\n",
1763
- " <td>2022-01-05</td>\n",
1764
- " <td>0.306697</td>\n",
1765
- " </tr>\n",
1766
- " <tr>\n",
1767
- " <th>244</th>\n",
1768
- " <td>2022-01-06</td>\n",
1769
- " <td>0.331291</td>\n",
1770
- " </tr>\n",
1771
- " <tr>\n",
1772
- " <th>245</th>\n",
1773
- " <td>2022-01-07</td>\n",
1774
- " <td>0.313726</td>\n",
1775
- " </tr>\n",
1776
- " <tr>\n",
1777
- " <th>246</th>\n",
1778
- " <td>2022-01-10</td>\n",
1779
- " <td>0.313262</td>\n",
1780
- " </tr>\n",
1781
- " </tbody>\n",
1782
- "</table>\n",
1783
- "<p>247 rows × 2 columns</p>\n",
1784
- "</div>"
1785
- ],
1786
- "text/plain": [
1787
- " date portfolio_return\n",
1788
- "0 2021-01-05 0.000000\n",
1789
- "1 2021-01-06 0.007011\n",
1790
- "2 2021-01-07 0.047531\n",
1791
- "3 2021-01-08 0.047111\n",
1792
- "4 2021-01-11 0.052768\n",
1793
- ".. ... ...\n",
1794
- "242 2022-01-04 0.363845\n",
1795
- "243 2022-01-05 0.306697\n",
1796
- "244 2022-01-06 0.331291\n",
1797
- "245 2022-01-07 0.313726\n",
1798
- "246 2022-01-10 0.313262\n",
1799
- "\n",
1800
- "[247 rows x 2 columns]"
1801
- ]
1802
- },
1803
- "execution_count": 58,
1804
- "metadata": {},
1805
- "output_type": "execute_result"
1806
- }
1807
- ],
1808
- "source": [
1809
- "portfolio_df = creaet_portfolio_return(p_stock_df)\n",
1810
- "portfolio_df"
1811
- ]
1812
- }
1813
- ],
1814
- "metadata": {
1815
- "kernelspec": {
1816
- "display_name": "portfolio_risk_assesment",
1817
- "language": "python",
1818
- "name": "python3"
1819
- },
1820
- "language_info": {
1821
- "codemirror_mode": {
1822
- "name": "ipython",
1823
- "version": 3
1824
- },
1825
- "file_extension": ".py",
1826
- "mimetype": "text/x-python",
1827
- "name": "python",
1828
- "nbconvert_exporter": "python",
1829
- "pygments_lexer": "ipython3",
1830
- "version": "3.11.4"
1831
- },
1832
- "orig_nbformat": 4
1833
- },
1834
- "nbformat": 4,
1835
- "nbformat_minor": 2
1836
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/sector_eval_df.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:dc104daae7afcd56a05f8aff9fa4d80d139a7db33d271fd69fbacb29db22283a
3
- size 152021
 
 
 
 
script/stream_pricessing.ipynb DELETED
@@ -1,617 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 2,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
11
- "application/vnd.holoviews_load.v0+json": ""
12
- },
13
- "metadata": {},
14
- "output_type": "display_data"
15
- },
16
- {
17
- "data": {
18
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
19
- "application/vnd.holoviews_load.v0+json": ""
20
- },
21
- "metadata": {},
22
- "output_type": "display_data"
23
- },
24
- {
25
- "data": {
26
- "text/html": [
27
- "<style>*[data-root-id],\n",
28
- "*[data-root-id] > * {\n",
29
- " box-sizing: border-box;\n",
30
- " font-family: var(--jp-ui-font-family);\n",
31
- " font-size: var(--jp-ui-font-size1);\n",
32
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
33
- "}\n",
34
- "\n",
35
- "/* Override VSCode background color */\n",
36
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
37
- " > .lm-Widget\n",
38
- " > *[data-root-id]),\n",
39
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
40
- " background-color: transparent !important;\n",
41
- "}\n",
42
- "</style>"
43
- ]
44
- },
45
- "metadata": {},
46
- "output_type": "display_data"
47
- }
48
- ],
49
- "source": [
50
- "import pandas as pd\n",
51
- "import math\n",
52
- "from datetime import datetime\n",
53
- "import hvplot.pandas\n",
54
- "import math\n",
55
- "import numpy as np\n",
56
- "from streamz import Stream"
57
- ]
58
- },
59
- {
60
- "cell_type": "code",
61
- "execution_count": 3,
62
- "metadata": {},
63
- "outputs": [],
64
- "source": [
65
- "b_stocks = pd.read_pickle('../data/b_stocks.pkl')\n",
66
- "p_stocks = pd.read_pickle('../data/p_stocks.pkl')\n",
67
- "p_profile = pd.read_pickle('../data/p_profile.pkl')\n",
68
- "b_profile = pd.read_pickle('../data/b_profile.pkl')"
69
- ]
70
- },
71
- {
72
- "cell_type": "code",
73
- "execution_count": 20,
74
- "metadata": {},
75
- "outputs": [
76
- {
77
- "data": {
78
- "text/html": [
79
- "<div>\n",
80
- "<style scoped>\n",
81
- " .dataframe tbody tr th:only-of-type {\n",
82
- " vertical-align: middle;\n",
83
- " }\n",
84
- "\n",
85
- " .dataframe tbody tr th {\n",
86
- " vertical-align: top;\n",
87
- " }\n",
88
- "\n",
89
- " .dataframe thead th {\n",
90
- " text-align: right;\n",
91
- " }\n",
92
- "</style>\n",
93
- "<table border=\"1\" class=\"dataframe\">\n",
94
- " <thead>\n",
95
- " <tr style=\"text-align: right;\">\n",
96
- " <th></th>\n",
97
- " <th>date</th>\n",
98
- " <th>ticker</th>\n",
99
- " <th>open</th>\n",
100
- " <th>close</th>\n",
101
- " <th>high</th>\n",
102
- " <th>low</th>\n",
103
- " <th>volume</th>\n",
104
- " <th>money</th>\n",
105
- " </tr>\n",
106
- " </thead>\n",
107
- " <tbody>\n",
108
- " <tr>\n",
109
- " <th>1</th>\n",
110
- " <td>2021-01-04</td>\n",
111
- " <td>002233.XSHE</td>\n",
112
- " <td>11.27</td>\n",
113
- " <td>11.28</td>\n",
114
- " <td>11.34</td>\n",
115
- " <td>11.17</td>\n",
116
- " <td>16262377.0</td>\n",
117
- " <td>1.829668e+08</td>\n",
118
- " </tr>\n",
119
- " <tr>\n",
120
- " <th>247</th>\n",
121
- " <td>2021-01-04</td>\n",
122
- " <td>601778.XSHG</td>\n",
123
- " <td>7.27</td>\n",
124
- " <td>7.65</td>\n",
125
- " <td>7.77</td>\n",
126
- " <td>7.25</td>\n",
127
- " <td>59723781.0</td>\n",
128
- " <td>4.523540e+08</td>\n",
129
- " </tr>\n",
130
- " <tr>\n",
131
- " <th>493</th>\n",
132
- " <td>2021-01-04</td>\n",
133
- " <td>002368.XSHE</td>\n",
134
- " <td>25.41</td>\n",
135
- " <td>28.18</td>\n",
136
- " <td>28.18</td>\n",
137
- " <td>25.27</td>\n",
138
- " <td>17448308.0</td>\n",
139
- " <td>4.729692e+08</td>\n",
140
- " </tr>\n",
141
- " <tr>\n",
142
- " <th>739</th>\n",
143
- " <td>2021-01-04</td>\n",
144
- " <td>001914.XSHE</td>\n",
145
- " <td>21.21</td>\n",
146
- " <td>20.39</td>\n",
147
- " <td>21.33</td>\n",
148
- " <td>20.26</td>\n",
149
- " <td>6619778.0</td>\n",
150
- " <td>1.366024e+08</td>\n",
151
- " </tr>\n",
152
- " <tr>\n",
153
- " <th>985</th>\n",
154
- " <td>2021-01-04</td>\n",
155
- " <td>002384.XSHE</td>\n",
156
- " <td>25.66</td>\n",
157
- " <td>25.98</td>\n",
158
- " <td>26.00</td>\n",
159
- " <td>25.17</td>\n",
160
- " <td>50695885.0</td>\n",
161
- " <td>1.296706e+09</td>\n",
162
- " </tr>\n",
163
- " <tr>\n",
164
- " <th>...</th>\n",
165
- " <td>...</td>\n",
166
- " <td>...</td>\n",
167
- " <td>...</td>\n",
168
- " <td>...</td>\n",
169
- " <td>...</td>\n",
170
- " <td>...</td>\n",
171
- " <td>...</td>\n",
172
- " <td>...</td>\n",
173
- " </tr>\n",
174
- " <tr>\n",
175
- " <th>147355</th>\n",
176
- " <td>2021-01-04</td>\n",
177
- " <td>600511.XSHG</td>\n",
178
- " <td>46.39</td>\n",
179
- " <td>45.10</td>\n",
180
- " <td>46.55</td>\n",
181
- " <td>44.32</td>\n",
182
- " <td>45375375.0</td>\n",
183
- " <td>2.043297e+09</td>\n",
184
- " </tr>\n",
185
- " <tr>\n",
186
- " <th>147601</th>\n",
187
- " <td>2021-01-04</td>\n",
188
- " <td>600236.XSHG</td>\n",
189
- " <td>4.05</td>\n",
190
- " <td>4.05</td>\n",
191
- " <td>4.05</td>\n",
192
- " <td>4.02</td>\n",
193
- " <td>5788783.0</td>\n",
194
- " <td>2.339606e+07</td>\n",
195
- " </tr>\n",
196
- " <tr>\n",
197
- " <th>147847</th>\n",
198
- " <td>2021-01-04</td>\n",
199
- " <td>000807.XSHE</td>\n",
200
- " <td>7.32</td>\n",
201
- " <td>7.58</td>\n",
202
- " <td>7.71</td>\n",
203
- " <td>7.13</td>\n",
204
- " <td>136647514.0</td>\n",
205
- " <td>1.027073e+09</td>\n",
206
- " </tr>\n",
207
- " <tr>\n",
208
- " <th>148093</th>\n",
209
- " <td>2021-01-04</td>\n",
210
- " <td>002815.XSHE</td>\n",
211
- " <td>13.41</td>\n",
212
- " <td>13.55</td>\n",
213
- " <td>13.67</td>\n",
214
- " <td>13.29</td>\n",
215
- " <td>5410989.0</td>\n",
216
- " <td>7.290842e+07</td>\n",
217
- " </tr>\n",
218
- " <tr>\n",
219
- " <th>148339</th>\n",
220
- " <td>2021-01-04</td>\n",
221
- " <td>002690.XSHE</td>\n",
222
- " <td>31.68</td>\n",
223
- " <td>31.68</td>\n",
224
- " <td>32.12</td>\n",
225
- " <td>31.26</td>\n",
226
- " <td>3641409.0</td>\n",
227
- " <td>1.153387e+08</td>\n",
228
- " </tr>\n",
229
- " </tbody>\n",
230
- "</table>\n",
231
- "<p>604 rows × 8 columns</p>\n",
232
- "</div>"
233
- ],
234
- "text/plain": [
235
- " date ticker open close high low volume \\\n",
236
- "1 2021-01-04 002233.XSHE 11.27 11.28 11.34 11.17 16262377.0 \n",
237
- "247 2021-01-04 601778.XSHG 7.27 7.65 7.77 7.25 59723781.0 \n",
238
- "493 2021-01-04 002368.XSHE 25.41 28.18 28.18 25.27 17448308.0 \n",
239
- "739 2021-01-04 001914.XSHE 21.21 20.39 21.33 20.26 6619778.0 \n",
240
- "985 2021-01-04 002384.XSHE 25.66 25.98 26.00 25.17 50695885.0 \n",
241
- "... ... ... ... ... ... ... ... \n",
242
- "147355 2021-01-04 600511.XSHG 46.39 45.10 46.55 44.32 45375375.0 \n",
243
- "147601 2021-01-04 600236.XSHG 4.05 4.05 4.05 4.02 5788783.0 \n",
244
- "147847 2021-01-04 000807.XSHE 7.32 7.58 7.71 7.13 136647514.0 \n",
245
- "148093 2021-01-04 002815.XSHE 13.41 13.55 13.67 13.29 5410989.0 \n",
246
- "148339 2021-01-04 002690.XSHE 31.68 31.68 32.12 31.26 3641409.0 \n",
247
- "\n",
248
- " money \n",
249
- "1 1.829668e+08 \n",
250
- "247 4.523540e+08 \n",
251
- "493 4.729692e+08 \n",
252
- "739 1.366024e+08 \n",
253
- "985 1.296706e+09 \n",
254
- "... ... \n",
255
- "147355 2.043297e+09 \n",
256
- "147601 2.339606e+07 \n",
257
- "147847 1.027073e+09 \n",
258
- "148093 7.290842e+07 \n",
259
- "148339 1.153387e+08 \n",
260
- "\n",
261
- "[604 rows x 8 columns]"
262
- ]
263
- },
264
- "execution_count": 20,
265
- "metadata": {},
266
- "output_type": "execute_result"
267
- }
268
- ],
269
- "source": [
270
- "# start stream here\n",
271
- "dates = b_stocks.date.unique()\n",
272
- "b_stocks[b_stocks.date == dates[1]]"
273
- ]
274
- },
275
- {
276
- "cell_type": "code",
277
- "execution_count": 32,
278
- "metadata": {},
279
- "outputs": [],
280
- "source": [
281
- "data1 = b_stocks[b_stocks.date == dates[0]]\n",
282
- "data2 = b_stocks[b_stocks.date == dates[1]]\n",
283
- "data3 = b_stocks[b_stocks.date == dates[2]]"
284
- ]
285
- },
286
- {
287
- "cell_type": "code",
288
- "execution_count": 34,
289
- "metadata": {},
290
- "outputs": [
291
- {
292
- "data": {
293
- "text/html": [
294
- "<div>\n",
295
- "<style scoped>\n",
296
- " .dataframe tbody tr th:only-of-type {\n",
297
- " vertical-align: middle;\n",
298
- " }\n",
299
- "\n",
300
- " .dataframe tbody tr th {\n",
301
- " vertical-align: top;\n",
302
- " }\n",
303
- "\n",
304
- " .dataframe thead th {\n",
305
- " text-align: right;\n",
306
- " }\n",
307
- "</style>\n",
308
- "<table border=\"1\" class=\"dataframe\">\n",
309
- " <thead>\n",
310
- " <tr style=\"text-align: right;\">\n",
311
- " <th></th>\n",
312
- " <th>date</th>\n",
313
- " <th>ticker</th>\n",
314
- " <th>open</th>\n",
315
- " <th>close</th>\n",
316
- " <th>high</th>\n",
317
- " <th>low</th>\n",
318
- " <th>volume</th>\n",
319
- " <th>money</th>\n",
320
- " </tr>\n",
321
- " </thead>\n",
322
- " <tbody>\n",
323
- " <tr>\n",
324
- " <th>0</th>\n",
325
- " <td>2020-12-31</td>\n",
326
- " <td>002233.XSHE</td>\n",
327
- " <td>11.23</td>\n",
328
- " <td>11.30</td>\n",
329
- " <td>11.38</td>\n",
330
- " <td>11.19</td>\n",
331
- " <td>9712496.0</td>\n",
332
- " <td>1.096390e+08</td>\n",
333
- " </tr>\n",
334
- " <tr>\n",
335
- " <th>246</th>\n",
336
- " <td>2020-12-31</td>\n",
337
- " <td>601778.XSHG</td>\n",
338
- " <td>7.28</td>\n",
339
- " <td>7.23</td>\n",
340
- " <td>7.39</td>\n",
341
- " <td>7.20</td>\n",
342
- " <td>29971398.0</td>\n",
343
- " <td>2.181267e+08</td>\n",
344
- " </tr>\n",
345
- " <tr>\n",
346
- " <th>492</th>\n",
347
- " <td>2020-12-31</td>\n",
348
- " <td>002368.XSHE</td>\n",
349
- " <td>24.96</td>\n",
350
- " <td>25.62</td>\n",
351
- " <td>25.92</td>\n",
352
- " <td>24.96</td>\n",
353
- " <td>7090839.0</td>\n",
354
- " <td>1.811902e+08</td>\n",
355
- " </tr>\n",
356
- " <tr>\n",
357
- " <th>738</th>\n",
358
- " <td>2020-12-31</td>\n",
359
- " <td>001914.XSHE</td>\n",
360
- " <td>20.52</td>\n",
361
- " <td>21.26</td>\n",
362
- " <td>21.36</td>\n",
363
- " <td>20.52</td>\n",
364
- " <td>5598757.0</td>\n",
365
- " <td>1.171876e+08</td>\n",
366
- " </tr>\n",
367
- " <tr>\n",
368
- " <th>984</th>\n",
369
- " <td>2020-12-31</td>\n",
370
- " <td>002384.XSHE</td>\n",
371
- " <td>25.67</td>\n",
372
- " <td>25.65</td>\n",
373
- " <td>25.90</td>\n",
374
- " <td>25.15</td>\n",
375
- " <td>49307624.0</td>\n",
376
- " <td>1.256593e+09</td>\n",
377
- " </tr>\n",
378
- " <tr>\n",
379
- " <th>...</th>\n",
380
- " <td>...</td>\n",
381
- " <td>...</td>\n",
382
- " <td>...</td>\n",
383
- " <td>...</td>\n",
384
- " <td>...</td>\n",
385
- " <td>...</td>\n",
386
- " <td>...</td>\n",
387
- " <td>...</td>\n",
388
- " </tr>\n",
389
- " <tr>\n",
390
- " <th>147355</th>\n",
391
- " <td>2021-01-04</td>\n",
392
- " <td>600511.XSHG</td>\n",
393
- " <td>46.39</td>\n",
394
- " <td>45.10</td>\n",
395
- " <td>46.55</td>\n",
396
- " <td>44.32</td>\n",
397
- " <td>45375375.0</td>\n",
398
- " <td>2.043297e+09</td>\n",
399
- " </tr>\n",
400
- " <tr>\n",
401
- " <th>147601</th>\n",
402
- " <td>2021-01-04</td>\n",
403
- " <td>600236.XSHG</td>\n",
404
- " <td>4.05</td>\n",
405
- " <td>4.05</td>\n",
406
- " <td>4.05</td>\n",
407
- " <td>4.02</td>\n",
408
- " <td>5788783.0</td>\n",
409
- " <td>2.339606e+07</td>\n",
410
- " </tr>\n",
411
- " <tr>\n",
412
- " <th>147847</th>\n",
413
- " <td>2021-01-04</td>\n",
414
- " <td>000807.XSHE</td>\n",
415
- " <td>7.32</td>\n",
416
- " <td>7.58</td>\n",
417
- " <td>7.71</td>\n",
418
- " <td>7.13</td>\n",
419
- " <td>136647514.0</td>\n",
420
- " <td>1.027073e+09</td>\n",
421
- " </tr>\n",
422
- " <tr>\n",
423
- " <th>148093</th>\n",
424
- " <td>2021-01-04</td>\n",
425
- " <td>002815.XSHE</td>\n",
426
- " <td>13.41</td>\n",
427
- " <td>13.55</td>\n",
428
- " <td>13.67</td>\n",
429
- " <td>13.29</td>\n",
430
- " <td>5410989.0</td>\n",
431
- " <td>7.290842e+07</td>\n",
432
- " </tr>\n",
433
- " <tr>\n",
434
- " <th>148339</th>\n",
435
- " <td>2021-01-04</td>\n",
436
- " <td>002690.XSHE</td>\n",
437
- " <td>31.68</td>\n",
438
- " <td>31.68</td>\n",
439
- " <td>32.12</td>\n",
440
- " <td>31.26</td>\n",
441
- " <td>3641409.0</td>\n",
442
- " <td>1.153387e+08</td>\n",
443
- " </tr>\n",
444
- " </tbody>\n",
445
- "</table>\n",
446
- "<p>1208 rows × 8 columns</p>\n",
447
- "</div>"
448
- ],
449
- "text/plain": [
450
- " date ticker open close high low volume \\\n",
451
- "0 2020-12-31 002233.XSHE 11.23 11.30 11.38 11.19 9712496.0 \n",
452
- "246 2020-12-31 601778.XSHG 7.28 7.23 7.39 7.20 29971398.0 \n",
453
- "492 2020-12-31 002368.XSHE 24.96 25.62 25.92 24.96 7090839.0 \n",
454
- "738 2020-12-31 001914.XSHE 20.52 21.26 21.36 20.52 5598757.0 \n",
455
- "984 2020-12-31 002384.XSHE 25.67 25.65 25.90 25.15 49307624.0 \n",
456
- "... ... ... ... ... ... ... ... \n",
457
- "147355 2021-01-04 600511.XSHG 46.39 45.10 46.55 44.32 45375375.0 \n",
458
- "147601 2021-01-04 600236.XSHG 4.05 4.05 4.05 4.02 5788783.0 \n",
459
- "147847 2021-01-04 000807.XSHE 7.32 7.58 7.71 7.13 136647514.0 \n",
460
- "148093 2021-01-04 002815.XSHE 13.41 13.55 13.67 13.29 5410989.0 \n",
461
- "148339 2021-01-04 002690.XSHE 31.68 31.68 32.12 31.26 3641409.0 \n",
462
- "\n",
463
- " money \n",
464
- "0 1.096390e+08 \n",
465
- "246 2.181267e+08 \n",
466
- "492 1.811902e+08 \n",
467
- "738 1.171876e+08 \n",
468
- "984 1.256593e+09 \n",
469
- "... ... \n",
470
- "147355 2.043297e+09 \n",
471
- "147601 2.339606e+07 \n",
472
- "147847 1.027073e+09 \n",
473
- "148093 7.290842e+07 \n",
474
- "148339 1.153387e+08 \n",
475
- "\n",
476
- "[1208 rows x 8 columns]"
477
- ]
478
- },
479
- "execution_count": 34,
480
- "metadata": {},
481
- "output_type": "execute_result"
482
- }
483
- ],
484
- "source": [
485
- "merged_df = pd.concat([data1, data2])\n",
486
- "merged_df"
487
- ]
488
- },
489
- {
490
- "cell_type": "code",
491
- "execution_count": 31,
492
- "metadata": {},
493
- "outputs": [
494
- {
495
- "name": "stdout",
496
- "output_type": "stream",
497
- "text": [
498
- " date ticker open close high low volume \\\n",
499
- "0 2020-12-31 002233.XSHE 11.23 11.30 11.38 11.19 9712496.0 \n",
500
- "246 2020-12-31 601778.XSHG 7.28 7.23 7.39 7.20 29971398.0 \n",
501
- "492 2020-12-31 002368.XSHE 24.96 25.62 25.92 24.96 7090839.0 \n",
502
- "738 2020-12-31 001914.XSHE 20.52 21.26 21.36 20.52 5598757.0 \n",
503
- "984 2020-12-31 002384.XSHE 25.67 25.65 25.90 25.15 49307624.0 \n",
504
- "... ... ... ... ... ... ... ... \n",
505
- "147354 2020-12-31 600511.XSHG 44.43 46.33 48.45 44.16 69779041.0 \n",
506
- "147600 2020-12-31 600236.XSHG 4.07 4.05 4.10 4.02 6542015.0 \n",
507
- "147846 2020-12-31 000807.XSHE 7.34 7.35 7.48 7.20 72260375.0 \n",
508
- "148092 2020-12-31 002815.XSHE 13.22 13.41 13.51 13.19 4198958.0 \n",
509
- "148338 2020-12-31 002690.XSHE 31.14 31.48 31.60 30.79 4010199.0 \n",
510
- "\n",
511
- " money \n",
512
- "0 1.096390e+08 \n",
513
- "246 2.181267e+08 \n",
514
- "492 1.811902e+08 \n",
515
- "738 1.171876e+08 \n",
516
- "984 1.256593e+09 \n",
517
- "... ... \n",
518
- "147354 3.258608e+09 \n",
519
- "147600 2.649244e+07 \n",
520
- "147846 5.305392e+08 \n",
521
- "148092 5.621386e+07 \n",
522
- "148338 1.257796e+08 \n",
523
- "\n",
524
- "[604 rows x 8 columns]\n",
525
- " date ticker open close high low volume \\\n",
526
- "0 2020-12-31 002233.XSHE 11.23 11.30 11.38 11.19 9712496.0 \n",
527
- "246 2020-12-31 601778.XSHG 7.28 7.23 7.39 7.20 29971398.0 \n",
528
- "492 2020-12-31 002368.XSHE 24.96 25.62 25.92 24.96 7090839.0 \n",
529
- "738 2020-12-31 001914.XSHE 20.52 21.26 21.36 20.52 5598757.0 \n",
530
- "984 2020-12-31 002384.XSHE 25.67 25.65 25.90 25.15 49307624.0 \n",
531
- "... ... ... ... ... ... ... ... \n",
532
- "147355 2021-01-04 600511.XSHG 46.39 45.10 46.55 44.32 45375375.0 \n",
533
- "147601 2021-01-04 600236.XSHG 4.05 4.05 4.05 4.02 5788783.0 \n",
534
- "147847 2021-01-04 000807.XSHE 7.32 7.58 7.71 7.13 136647514.0 \n",
535
- "148093 2021-01-04 002815.XSHE 13.41 13.55 13.67 13.29 5410989.0 \n",
536
- "148339 2021-01-04 002690.XSHE 31.68 31.68 32.12 31.26 3641409.0 \n",
537
- "\n",
538
- " money \n",
539
- "0 1.096390e+08 \n",
540
- "246 2.181267e+08 \n",
541
- "492 1.811902e+08 \n",
542
- "738 1.171876e+08 \n",
543
- "984 1.256593e+09 \n",
544
- "... ... \n",
545
- "147355 2.043297e+09 \n",
546
- "147601 2.339606e+07 \n",
547
- "147847 1.027073e+09 \n",
548
- "148093 7.290842e+07 \n",
549
- "148339 1.153387e+08 \n",
550
- "\n",
551
- "[1208 rows x 8 columns]\n",
552
- " date ticker open close high low volume \\\n",
553
- "0 2020-12-31 002233.XSHE 11.23 11.30 11.38 11.19 9712496.0 \n",
554
- "246 2020-12-31 601778.XSHG 7.28 7.23 7.39 7.20 29971398.0 \n",
555
- "492 2020-12-31 002368.XSHE 24.96 25.62 25.92 24.96 7090839.0 \n",
556
- "738 2020-12-31 001914.XSHE 20.52 21.26 21.36 20.52 5598757.0 \n",
557
- "984 2020-12-31 002384.XSHE 25.67 25.65 25.90 25.15 49307624.0 \n",
558
- "... ... ... ... ... ... ... ... \n",
559
- "147356 2021-01-05 600511.XSHG 45.00 45.58 46.79 43.58 45296155.0 \n",
560
- "147602 2021-01-05 600236.XSHG 4.04 4.01 4.05 4.00 4302703.0 \n",
561
- "147848 2021-01-05 000807.XSHE 7.61 7.99 8.21 7.48 177268867.0 \n",
562
- "148094 2021-01-05 002815.XSHE 13.52 13.63 13.65 13.44 5800866.0 \n",
563
- "148340 2021-01-05 002690.XSHE 31.68 31.85 32.14 31.42 5082815.0 \n",
564
- "\n",
565
- " money \n",
566
- "0 1.096390e+08 \n",
567
- "246 2.181267e+08 \n",
568
- "492 1.811902e+08 \n",
569
- "738 1.171876e+08 \n",
570
- "984 1.256593e+09 \n",
571
- "... ... \n",
572
- "147356 2.035299e+09 \n",
573
- "147602 1.726972e+07 \n",
574
- "147848 1.383377e+09 \n",
575
- "148094 7.856429e+07 \n",
576
- "148340 1.612986e+08 \n",
577
- "\n",
578
- "[1812 rows x 8 columns]\n"
579
- ]
580
- }
581
- ],
582
- "source": [
583
- "def add(prev_df, new_df):\n",
584
- " merged_df = pd.concat([prev_df, new_df])\n",
585
- " return merged_df\n",
586
- "\n",
587
- "source = Stream()\n",
588
- "source.accumulate(add).sink(print)\n",
589
- "source.emit(b_stocks[b_stocks.date == dates[0]])\n",
590
- "source.emit(b_stocks[b_stocks.date == dates[1]])\n",
591
- "source.emit(b_stocks[b_stocks.date == dates[2]])\n"
592
- ]
593
- }
594
- ],
595
- "metadata": {
596
- "kernelspec": {
597
- "display_name": "portfolio_risk_assesment",
598
- "language": "python",
599
- "name": "python3"
600
- },
601
- "language_info": {
602
- "codemirror_mode": {
603
- "name": "ipython",
604
- "version": 3
605
- },
606
- "file_extension": ".py",
607
- "mimetype": "text/x-python",
608
- "name": "python",
609
- "nbconvert_exporter": "python",
610
- "pygments_lexer": "ipython3",
611
- "version": "3.11.4"
612
- },
613
- "orig_nbformat": 4
614
- },
615
- "nbformat": 4,
616
- "nbformat_minor": 2
617
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/stream_processing.py DELETED
@@ -1,32 +0,0 @@
1
- import pandas as pd
2
- import math
3
- from datetime import datetime
4
- import hvplot.pandas
5
- import math
6
- import numpy as np
7
- import time
8
- from streamz import Stream
9
-
10
- b_stocks = pd.read_pickle('../data/b_stocks.pkl')
11
- p_stocks = pd.read_pickle('../data/p_stocks.pkl')
12
- p_profile = pd.read_pickle('../data/p_profile.pkl')
13
- b_profile = pd.read_pickle('../data/b_profile.pkl')
14
-
15
- # start stream here
16
- dates = b_stocks.date.unique()
17
- b_stocks[b_stocks.date == dates[1]]
18
-
19
- def add(prev_df, new_df):
20
- merged_df = pd.concat([prev_df, new_df])
21
- merged_df.sort_values(by=['date'], inplace=True)
22
- merged_df['pct'] = merged_df.groupby('ticker')['close'].pct_change()
23
-
24
- # remove prev_df
25
- merged_df = merged_df[~merged_df.isin(prev_df)].dropna()
26
- return merged_df
27
-
28
- source = Stream()
29
- source.accumulate(add).sink(print)
30
- source.emit(b_stocks[b_stocks.date == dates[0]])
31
- source.emit(b_stocks[b_stocks.date == dates[1]])
32
- source.emit(b_stocks[b_stocks.date == dates[2]])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script/styling.py DELETED
@@ -1,15 +0,0 @@
1
- plot_layout = dict(
2
- legend=dict(
3
- orientation="h",
4
- ),
5
- yaxis_title=None,
6
- xaxis_title=None,
7
- margin=dict(l=0, r=0, t=30, b=0),
8
- uniformtext_mode='hide',
9
-
10
- )
11
-
12
- barplot_trace = dict(
13
- marker_line_width=0,
14
- selector=dict(type="bar"),
15
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test.ipynb DELETED
@@ -1,47 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": null,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "import numpy as np\n",
10
- "import pandas as pd\n",
11
- "import panel as pn\n",
12
- "\n",
13
- "pn.extension('perspective', template='fast', sizing_mode='stretch_width')\n",
14
- "df = pd.DataFrame(np.random.randn(10, 4), columns=list('ABCD')).cumsum()\n",
15
- "\n",
16
- "rollover = pn.widgets.IntInput(name='Rollover', value=15)\n",
17
- "\n",
18
- "perspective = pn.pane.Perspective(df, height=400)\n",
19
- "\n",
20
- "def stream():\n",
21
- " data = df.iloc[-1] + np.random.randn(4)\n",
22
- " perspective.stream(data, rollover=rollover.value)\n",
23
- "\\\n",
24
- "cb = pn.state.add_periodic_callback(stream, 50)\n",
25
- "\n",
26
- "pn.Column(\n",
27
- " pn.Row(cb.param.period, rollover, perspective.param.theme),\n",
28
- " perspective\n",
29
- ").servable()"
30
- ]
31
- }
32
- ],
33
- "metadata": {
34
- "kernelspec": {
35
- "display_name": "portfolio_risk_assesment",
36
- "language": "python",
37
- "name": "python3"
38
- },
39
- "language_info": {
40
- "name": "python",
41
- "version": "3.11.4"
42
- },
43
- "orig_nbformat": 4
44
- },
45
- "nbformat": 4,
46
- "nbformat_minor": 2
47
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_background_task.py DELETED
@@ -1,26 +0,0 @@
1
- import pipeline
2
- import settings
3
-
4
- def test_need_to_update():
5
- table_list = settings.TABLE_NAME_AND_FREQ
6
- for table, freq in table_list:
7
- result = pipeline.need_to_update(table, freq)
8
- print(result)
9
-
10
- # test_need_to_update()
11
-
12
- def test_fetch_stock_price():
13
- df = pipeline.fetch_stock_price()
14
- return df
15
-
16
- def test_need_to_update_stocks_price():
17
- print(pipeline.need_to_update_stocks_price())
18
-
19
-
20
- def test_add_details_to_stock_df():
21
- stock_df = pipeline.update_stocks_price()
22
- stock_df = pipeline.add_details_to_stock_df(stock_df)
23
-
24
- return stock_df
25
-
26
- print(test_add_details_to_stock_df())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_responsive.py DELETED
@@ -1,14 +0,0 @@
1
- import random
2
- import panel.widgets as pnw
3
- import panel as pn
4
- pn.extension()
5
-
6
-
7
- def rcolor(): return "#%06x" % random.randint(0, 0xFFFFFF)
8
-
9
-
10
- box = pn.FlexBox(*[pn.pane.HTML(str(i), styles=dict(background=rcolor()),
11
- width=370, height=100, sizing_mode='fixed') for i in range(24)],
12
- align_conten='start', styles={'background': 'black'}
13
- )
14
- box.servable()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
testing_pipeline.ipynb DELETED
@@ -1,561 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
11
- "application/vnd.holoviews_load.v0+json": ""
12
- },
13
- "metadata": {},
14
- "output_type": "display_data"
15
- },
16
- {
17
- "data": {
18
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
19
- "application/vnd.holoviews_load.v0+json": ""
20
- },
21
- "metadata": {},
22
- "output_type": "display_data"
23
- },
24
- {
25
- "data": {
26
- "text/html": [
27
- "<style>*[data-root-id],\n",
28
- "*[data-root-id] > * {\n",
29
- " box-sizing: border-box;\n",
30
- " font-family: var(--jp-ui-font-family);\n",
31
- " font-size: var(--jp-ui-font-size1);\n",
32
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
33
- "}\n",
34
- "\n",
35
- "/* Override VSCode background color */\n",
36
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
37
- " > .lm-Widget\n",
38
- " > *[data-root-id]),\n",
39
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
40
- " background-color: transparent !important;\n",
41
- "}\n",
42
- "</style>"
43
- ]
44
- },
45
- "metadata": {},
46
- "output_type": "display_data"
47
- }
48
- ],
49
- "source": [
50
- "import pipeline\n",
51
- "import settings\n",
52
- "from sqlalchemy import create_engine\n",
53
- "import pandas as pd\n",
54
- "import processing\n",
55
- "import datetime as dt\n",
56
- "import api\n",
57
- "import table_schema as ts\n",
58
- "import db_operation as db\n",
59
- "import numpy as np\n",
60
- "import utils\n",
61
- "import hvplot.pandas # noqa\n",
62
- "pd.options.plotting.backend = 'holoviews'\n",
63
- "db_url = 'sqlite:///instance/local.db'"
64
- ]
65
- },
66
- {
67
- "cell_type": "code",
68
- "execution_count": 2,
69
- "metadata": {},
70
- "outputs": [],
71
- "source": [
72
- "%load_ext autoreload\n",
73
- "%autoreload 2"
74
- ]
75
- },
76
- {
77
- "cell_type": "code",
78
- "execution_count": 3,
79
- "metadata": {},
80
- "outputs": [],
81
- "source": [
82
- "# unique ticker list\n",
83
- "def get_stocks_in_profile(profile_df):\n",
84
- " ticker_list = profile_df['ticker'].unique().tolist()\n",
85
- " stocks_df = db.get_stocks_price(ticker_list)\n",
86
- " return stocks_df\n",
87
- "portfolio_p = db.get_all_portfolio_profile()\n",
88
- "benchmark_p = db.get_all_benchmark_profile()\n",
89
- "p_stocks_df = get_stocks_in_profile(portfolio_p)\n",
90
- "b_stocks_df = get_stocks_in_profile(benchmark_p)\n",
91
- "\n",
92
- "## temperaraly handle rename date to time\n",
93
- "portfolio_p.rename(columns={'date': 'time','weight':'ini_w'}, inplace=True)\n",
94
- "benchmark_p.rename(columns={'date': 'time'}, inplace=True)\n",
95
- "# normalize weight in benchmark\n",
96
- "grouped = benchmark_p.groupby('time')\n",
97
- "benchmark_p['ini_w'] = grouped['weight'].transform(lambda x: x / x.sum())"
98
- ]
99
- },
100
- {
101
- "cell_type": "code",
102
- "execution_count": 4,
103
- "metadata": {},
104
- "outputs": [],
105
- "source": [
106
- "analytic_b = processing.create_analytic_df(b_stocks_df, benchmark_p)\n",
107
- "analytic_p = processing.create_analytic_df(p_stocks_df, portfolio_p)"
108
- ]
109
- },
110
- {
111
- "cell_type": "code",
112
- "execution_count": 5,
113
- "metadata": {},
114
- "outputs": [],
115
- "source": [
116
- "# p stock weight\n",
117
- "processing.calculate_cash(analytic_p)\n",
118
- "processing.calculate_weight_using_cash(analytic_p)\n",
119
- "processing.calculate_pct(analytic_p)\n",
120
- "# b stock weight\n",
121
- "analytic_b.sort_values(by=['time'], inplace=True)\n",
122
- "grouped = analytic_b.groupby('ticker')\n",
123
- "analytic_b['pct'] = grouped['close'].pct_change()\n",
124
- "processing.calculate_weight_using_pct(analytic_b)\n",
125
- "\n",
126
- "# analytic_df.hvplot.line(x='time', y='cur_w', by='ticker', width=500, height=400)\n",
127
- "# analytic_d"
128
- ]
129
- },
130
- {
131
- "cell_type": "code",
132
- "execution_count": 6,
133
- "metadata": {},
134
- "outputs": [],
135
- "source": [
136
- "# crop before processing\n",
137
- "analytic_b = analytic_b[analytic_b.time >= analytic_p.time.min()].copy()\n",
138
- "processing.calculate_log_return(analytic_p)\n",
139
- "processing.calculate_log_return(analytic_b)\n"
140
- ]
141
- },
142
- {
143
- "cell_type": "code",
144
- "execution_count": 7,
145
- "metadata": {},
146
- "outputs": [
147
- {
148
- "data": {
149
- "text/plain": [
150
- "Index(['time', 'ticker', 'open', 'close', 'high', 'low', 'volume', 'money',\n",
151
- " 'shares', 'sector', 'aggregate_sector', 'display_name', 'name', 'cash',\n",
152
- " 'ini_w', 'ave_price', 'weight', 'pct', 'log_return',\n",
153
- " 'weighted_log_return'],\n",
154
- " dtype='object')"
155
- ]
156
- },
157
- "execution_count": 7,
158
- "metadata": {},
159
- "output_type": "execute_result"
160
- }
161
- ],
162
- "source": [
163
- "analytic_p.columns"
164
- ]
165
- },
166
- {
167
- "cell_type": "code",
168
- "execution_count": 20,
169
- "metadata": {},
170
- "outputs": [
171
- {
172
- "data": {},
173
- "metadata": {},
174
- "output_type": "display_data"
175
- },
176
- {
177
- "data": {
178
- "application/vnd.holoviews_exec.v0+json": "",
179
- "text/html": [
180
- "<div id='p1149'>\n",
181
- " <div id=\"ad7e920f-cf41-4c46-8ae3-2357eee49c67\" data-root-id=\"p1149\" style=\"display: contents;\"></div>\n",
182
- "</div>\n",
183
- "<script type=\"application/javascript\">(function(root) {\n",
184
- " var docs_json = {\"9024d76f-8d10-4a0a-8327-1e46e4bcf29d\":{\"version\":\"3.1.1\",\"title\":\"Bokeh Application\",\"defs\":[{\"type\":\"model\",\"name\":\"ReactiveHTML1\"},{\"type\":\"model\",\"name\":\"FlexBox1\",\"properties\":[{\"name\":\"align_content\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"align_items\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"flex_direction\",\"kind\":\"Any\",\"default\":\"row\"},{\"name\":\"flex_wrap\",\"kind\":\"Any\",\"default\":\"wrap\"},{\"name\":\"justify_content\",\"kind\":\"Any\",\"default\":\"flex-start\"}]},{\"type\":\"model\",\"name\":\"FloatPanel1\",\"properties\":[{\"name\":\"config\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"contained\",\"kind\":\"Any\",\"default\":true},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"right-top\"},{\"name\":\"offsetx\",\"kind\":\"Any\",\"default\":null},{\"name\":\"offsety\",\"kind\":\"Any\",\"default\":null},{\"name\":\"theme\",\"kind\":\"Any\",\"default\":\"primary\"},{\"name\":\"status\",\"kind\":\"Any\",\"default\":\"normalized\"}]},{\"type\":\"model\",\"name\":\"GridStack1\",\"properties\":[{\"name\":\"mode\",\"kind\":\"Any\",\"default\":\"warn\"},{\"name\":\"ncols\",\"kind\":\"Any\",\"default\":null},{\"name\":\"nrows\",\"kind\":\"Any\",\"default\":null},{\"name\":\"allow_resize\",\"kind\":\"Any\",\"default\":true},{\"name\":\"allow_drag\",\"kind\":\"Any\",\"default\":true},{\"name\":\"state\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"drag1\",\"properties\":[{\"name\":\"slider_width\",\"kind\":\"Any\",\"default\":5},{\"name\":\"slider_color\",\"kind\":\"Any\",\"default\":\"black\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":50}]},{\"type\":\"model\",\"name\":\"click1\",\"properties\":[{\"name\":\"terminal_output\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"debug_name\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"clears\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"FastWrapper1\",\"properties\":[{\"name\":\"object\",\"kind\":\"Any\",\"default\":null},{\"name\":\"style\",\"kind\":\"Any\",\"default\":null}]},{\"type\":\"model\",\"name\":\"NotificationAreaBase1\",\"properties\":[{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"NotificationArea1\",\"properties\":[{\"name\":\"notifications\",\"kind\":\"Any\",\"default\":[]},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0},{\"name\":\"types\",\"kind\":\"Any\",\"default\":[{\"type\":\"map\",\"entries\":[[\"type\",\"warning\"],[\"background\",\"#ffc107\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-exclamation-triangle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]},{\"type\":\"map\",\"entries\":[[\"type\",\"info\"],[\"background\",\"#007bff\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-info-circle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]}]}]},{\"type\":\"model\",\"name\":\"Notification\",\"properties\":[{\"name\":\"background\",\"kind\":\"Any\",\"default\":null},{\"name\":\"duration\",\"kind\":\"Any\",\"default\":3000},{\"name\":\"icon\",\"kind\":\"Any\",\"default\":null},{\"name\":\"message\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"notification_type\",\"kind\":\"Any\",\"default\":null},{\"name\":\"_destroyed\",\"kind\":\"Any\",\"default\":false}]},{\"type\":\"model\",\"name\":\"TemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"BootstrapTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"MaterialTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]}],\"roots\":[{\"type\":\"object\",\"name\":\"Row\",\"id\":\"p1149\",\"attributes\":{\"name\":\"Row01028\",\"tags\":[\"embedded\"],\"stylesheets\":[\"\\n:host(.pn-loading.pn-arc):before, .pn-loading.pn-arc:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46IGF1dG87IGJhY2tncm91bmQ6IG5vbmU7IGRpc3BsYXk6IGJsb2NrOyBzaGFwZS1yZW5kZXJpbmc6IGF1dG87IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjYzNjM2MzIiBzdHJva2Utd2lkdGg9IjEwIiByPSIzNSIgc3Ryb2tlLWRhc2hhcnJheT0iMTY0LjkzMzYxNDMxMzQ2NDE1IDU2Ljk3Nzg3MTQzNzgyMTM4Ij4gICAgPGFuaW1hdGVUcmFuc2Zvcm0gYXR0cmlidXRlTmFtZT0idHJhbnNmb3JtIiB0eXBlPSJyb3RhdGUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIj48L2FuaW1hdGVUcmFuc2Zvcm0+ICA8L2NpcmNsZT48L3N2Zz4=\\\");\\n background-size: auto calc(min(50%, 400px));\\n}\",{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1152\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.1.1/dist/css/loading.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1241\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.1.1/dist/css/listpanel.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1150\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.1.1/dist/bundled/theme/default.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1151\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.1.1/dist/bundled/theme/native.css\"}}],\"min_width\":700,\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\",\"children\":[{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1153\",\"attributes\":{\"name\":\"HSpacer01039\",\"stylesheets\":[\"\\n:host(.pn-loading.pn-arc):before, .pn-loading.pn-arc:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46IGF1dG87IGJhY2tncm91bmQ6IG5vbmU7IGRpc3BsYXk6IGJsb2NrOyBzaGFwZS1yZW5kZXJpbmc6IGF1dG87IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjYzNjM2MzIiBzdHJva2Utd2lkdGg9IjEwIiByPSIzNSIgc3Ryb2tlLWRhc2hhcnJheT0iMTY0LjkzMzYxNDMxMzQ2NDE1IDU2Ljk3Nzg3MTQzNzgyMTM4Ij4gICAgPGFuaW1hdGVUcmFuc2Zvcm0gYXR0cmlidXRlTmFtZT0idHJhbnNmb3JtIiB0eXBlPSJyb3RhdGUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIj48L2FuaW1hdGVUcmFuc2Zvcm0+ICA8L2NpcmNsZT48L3N2Zz4=\\\");\\n background-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1152\"},{\"id\":\"p1150\"},{\"id\":\"p1151\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}},{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1157\",\"attributes\":{\"width\":700,\"height\":300,\"margin\":[5,10],\"sizing_mode\":\"fixed\",\"align\":\"start\",\"x_range\":{\"type\":\"object\",\"name\":\"FactorRange\",\"id\":\"p1154\",\"attributes\":{\"tags\":[[[\"period\",\"period\",null],[\"Variable\",\"Variable\",null]]],\"factors\":[[\"2023-08-14\",\"notional_active_return\"],[\"2023-08-14\",\"selection\"],[\"2023-08-14\",\"interaction\"],[\"2023-08-14\",\"allocation\"],[\"2023-08-14\",\"active_return\"],[\"2023-08-15\",\"notional_active_return\"],[\"2023-08-15\",\"selection\"],[\"2023-08-15\",\"interaction\"],[\"2023-08-15\",\"allocation\"],[\"2023-08-15\",\"active_return\"],[\"2023-08-16\",\"notional_active_return\"],[\"2023-08-16\",\"selection\"],[\"2023-08-16\",\"interaction\"],[\"2023-08-16\",\"allocation\"],[\"2023-08-16\",\"active_return\"],[\"2023-08-17\",\"notional_active_return\"],[\"2023-08-17\",\"selection\"],[\"2023-08-17\",\"interaction\"],[\"2023-08-17\",\"allocation\"],[\"2023-08-17\",\"active_return\"],[\"2023-08-18\",\"notional_active_return\"],[\"2023-08-18\",\"selection\"],[\"2023-08-18\",\"interaction\"],[\"2023-08-18\",\"allocation\"],[\"2023-08-18\",\"active_return\"],[\"2023-08-21\",\"notional_active_return\"],[\"2023-08-21\",\"selection\"],[\"2023-08-21\",\"interaction\"],[\"2023-08-21\",\"allocation\"],[\"2023-08-21\",\"active_return\"],[\"2023-08-22\",\"notional_active_return\"],[\"2023-08-22\",\"selection\"],[\"2023-08-22\",\"interaction\"],[\"2023-08-22\",\"allocation\"],[\"2023-08-22\",\"active_return\"],[\"2023-08-23\",\"notional_active_return\"],[\"2023-08-23\",\"selection\"],[\"2023-08-23\",\"interaction\"],[\"2023-08-23\",\"allocation\"],[\"2023-08-23\",\"active_return\"],[\"2023-08-24\",\"notional_active_return\"],[\"2023-08-24\",\"selection\"],[\"2023-08-24\",\"interaction\"],[\"2023-08-24\",\"allocation\"],[\"2023-08-24\",\"active_return\"],[\"2023-08-25\",\"notional_active_return\"],[\"2023-08-25\",\"selection\"],[\"2023-08-25\",\"interaction\"],[\"2023-08-25\",\"allocation\"],[\"2023-08-25\",\"active_return\"],[\"2023-08-28\",\"notional_active_return\"],[\"2023-08-28\",\"selection\"],[\"2023-08-28\",\"interaction\"],[\"2023-08-28\",\"allocation\"],[\"2023-08-28\",\"active_return\"],[\"2023-08-29\",\"notional_active_return\"],[\"2023-08-29\",\"selection\"],[\"2023-08-29\",\"interaction\"],[\"2023-08-29\",\"allocation\"],[\"2023-08-29\",\"active_return\"]]}},\"y_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1155\",\"attributes\":{\"tags\":[[[\"value\",\"value\",null]]],\"start\":-0.038496781602345674,\"end\":0.03280656468119388,\"reset_start\":-0.038496781602345674,\"reset_end\":0.03280656468119388}},\"x_scale\":{\"type\":\"object\",\"name\":\"CategoricalScale\",\"id\":\"p1169\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1171\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1160\",\"attributes\":{\"text_color\":\"black\",\"text_font_size\":\"12pt\"}},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1211\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1201\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1202\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1203\"},\"data\":{\"type\":\"map\",\"entries\":[[\"xoffsets\",[[\"2023-08-14\",\"active_return\"],[\"2023-08-15\",\"active_return\"],[\"2023-08-16\",\"active_return\"],[\"2023-08-17\",\"active_return\"],[\"2023-08-18\",\"active_return\"],[\"2023-08-21\",\"active_return\"],[\"2023-08-22\",\"active_return\"],[\"2023-08-23\",\"active_return\"],[\"2023-08-24\",\"active_return\"],[\"2023-08-25\",\"active_return\"],[\"2023-08-28\",\"active_return\"],[\"2023-08-29\",\"active_return\"],[\"2023-08-14\",\"allocation\"],[\"2023-08-15\",\"allocation\"],[\"2023-08-16\",\"allocation\"],[\"2023-08-17\",\"allocation\"],[\"2023-08-18\",\"allocation\"],[\"2023-08-21\",\"allocation\"],[\"2023-08-22\",\"allocation\"],[\"2023-08-23\",\"allocation\"],[\"2023-08-24\",\"allocation\"],[\"2023-08-25\",\"allocation\"],[\"2023-08-28\",\"allocation\"],[\"2023-08-29\",\"allocation\"],[\"2023-08-14\",\"interaction\"],[\"2023-08-15\",\"interaction\"],[\"2023-08-16\",\"interaction\"],[\"2023-08-17\",\"interaction\"],[\"2023-08-18\",\"interaction\"],[\"2023-08-21\",\"interaction\"],[\"2023-08-22\",\"interaction\"],[\"2023-08-23\",\"interaction\"],[\"2023-08-24\",\"interaction\"],[\"2023-08-25\",\"interaction\"],[\"2023-08-28\",\"interaction\"],[\"2023-08-29\",\"interaction\"],[\"2023-08-14\",\"selection\"],[\"2023-08-15\",\"selection\"],[\"2023-08-16\",\"selection\"],[\"2023-08-17\",\"selection\"],[\"2023-08-18\",\"selection\"],[\"2023-08-21\",\"selection\"],[\"2023-08-22\",\"selection\"],[\"2023-08-23\",\"selection\"],[\"2023-08-24\",\"selection\"],[\"2023-08-25\",\"selection\"],[\"2023-08-28\",\"selection\"],[\"2023-08-29\",\"selection\"],[\"2023-08-14\",\"notional_active_return\"],[\"2023-08-15\",\"notional_active_return\"],[\"2023-08-16\",\"notional_active_return\"],[\"2023-08-17\",\"notional_active_return\"],[\"2023-08-18\",\"notional_active_return\"],[\"2023-08-21\",\"notional_active_return\"],[\"2023-08-22\",\"notional_active_return\"],[\"2023-08-23\",\"notional_active_return\"],[\"2023-08-24\",\"notional_active_return\"],[\"2023-08-25\",\"notional_active_return\"],[\"2023-08-28\",\"notional_active_return\"],[\"2023-08-29\",\"notional_active_return\"]]],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAAAACSdCUE2bmFP3iNNqu+pYE/OSn4FAn+gD/MxAlqBS5VP/EgqTPbb30/0vNefbyUbj+31cHIge+RP9S99ozbYn0/G5BXlT34fj8Vjs8HzTGSvyo0QxpwQJK/AAAAAAAAAABza22o1z+IP6dNJlePK4A/4UGVEQRyar81d4M+I+SRP0CLg/lztoE/HHfxBthpcT+oziSlOt2TPywP6a3443C/DWZJd1aniT+qHEItiBqHv+qiiBZr4Za/AAAAAAAAAACoKW1MOLt+v6obLAbAYn2/v/3qxyjtkj9lyJEIB6ugv0owVeBZk4q/AmEDeK10cj+Yx4eB88qVvxZuZHRmlY8/B4LzEUfpkb9VOsqV7KJzP6oRzhJmgps/AAAAAAAAAADkO90DO695P6dNJlePK4A/nAPx7I5/fL/itUApy8SQP4M1poDTlIc/NV5FQCeUdL+oziSlOt2TPywP6a3443C/DWZJd1aniT+qHEItiBqHv+qiiBZr4Za/AAAAAAAAAACSdCUE2bmFP3iNNqu+pYE/OSn4FAn+gD/MxAlqBS5VP/EgqTPbb30/0vNefbyUbj+31cHIge+RP9S99ozbYn0/G5BXlT34fj8Vjs8HzTGSvyo0QxpwQJK/\"},\"shape\":[60],\"dtype\":\"float64\",\"order\":\"little\"}],[\"period\",[\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\",\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\",\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\",\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\",\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\"]],[\"Variable\",[\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"active_return\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"allocation\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"interaction\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"selection\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\",\"notional_active_return\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1212\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1213\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"VBar\",\"id\":\"p1208\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"xoffsets\"},\"width\":{\"type\":\"value\",\"value\":0.8},\"top\":{\"type\":\"field\",\"field\":\"value\"},\"fill_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"type\":\"object\",\"name\":\"CategoricalColorMapper\",\"id\":\"p1200\",\"attributes\":{\"palette\":[\"#30a2da\",\"#fc4f30\",\"#e5ae38\",\"#6d904f\",\"#8b8b8b\"],\"factors\":[\"active_return\",\"allocation\",\"interaction\",\"selection\",\"notional_active_return\"]}}},\"hatch_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}}}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"VBar\",\"id\":\"p1214\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"xoffsets\"},\"width\":{\"type\":\"value\",\"value\":0.8},\"bottom\":{\"type\":\"value\",\"value\":0},\"top\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":{\"type\":\"value\",\"value\":\"black\"},\"line_alpha\":{\"type\":\"value\",\"value\":1.0},\"line_width\":{\"type\":\"value\",\"value\":1},\"line_join\":{\"type\":\"value\",\"value\":\"bevel\"},\"line_cap\":{\"type\":\"value\",\"value\":\"butt\"},\"line_dash\":{\"type\":\"value\",\"value\":[]},\"line_dash_offset\":{\"type\":\"value\",\"value\":0},\"fill_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"fill_alpha\":{\"type\":\"value\",\"value\":1.0},\"hatch_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"hatch_alpha\":{\"type\":\"value\",\"value\":1.0},\"hatch_scale\":{\"type\":\"value\",\"value\":12.0},\"hatch_pattern\":{\"type\":\"value\",\"value\":null},\"hatch_weight\":{\"type\":\"value\",\"value\":1.0}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"VBar\",\"id\":\"p1209\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"xoffsets\"},\"width\":{\"type\":\"value\",\"value\":0.8},\"top\":{\"type\":\"field\",\"field\":\"value\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"VBar\",\"id\":\"p1210\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"xoffsets\"},\"width\":{\"type\":\"value\",\"value\":0.8},\"top\":{\"type\":\"field\",\"field\":\"value\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_color\":{\"type\":\"field\",\"field\":\"Variable\",\"transform\":{\"id\":\"p1200\"}},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1162\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"HoverTool\",\"id\":\"p1156\",\"attributes\":{\"tags\":[\"hv_created\"],\"renderers\":[{\"id\":\"p1211\"}],\"tooltips\":[[\"period\",\"@{period}\"],[\"Variable\",\"@{Variable}\"],[\"value\",\"@{value}\"]]}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1186\"},{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1187\"},{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1188\"},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1189\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1190\",\"attributes\":{\"syncable\":false,\"level\":\"overlay\",\"visible\":false,\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"bottom_units\":\"canvas\",\"top_units\":\"canvas\",\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5}}}},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1191\"}],\"active_drag\":{\"id\":\"p1187\"},\"active_scroll\":{\"id\":\"p1188\"}}},\"left\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1179\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1182\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1181\"},\"axis_label\":\"\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1180\"}}}],\"below\":[{\"type\":\"object\",\"name\":\"CategoricalAxis\",\"id\":\"p1173\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"CategoricalTicker\",\"id\":\"p1176\"},\"formatter\":{\"type\":\"object\",\"name\":\"CategoricalTickFormatter\",\"id\":\"p1175\"},\"axis_label\":\"period, Variable\",\"major_label_orientation\":0.7853981633974483,\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1174\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1178\",\"attributes\":{\"axis\":{\"id\":\"p1173\"},\"grid_line_color\":null}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1185\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1179\"},\"grid_line_color\":null}}],\"min_border_top\":10,\"min_border_bottom\":10,\"min_border_left\":10,\"min_border_right\":10,\"output_backend\":\"webgl\"}},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1239\",\"attributes\":{\"name\":\"HSpacer01042\",\"stylesheets\":[\"\\n:host(.pn-loading.pn-arc):before, .pn-loading.pn-arc:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46IGF1dG87IGJhY2tncm91bmQ6IG5vbmU7IGRpc3BsYXk6IGJsb2NrOyBzaGFwZS1yZW5kZXJpbmc6IGF1dG87IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjYzNjM2MzIiBzdHJva2Utd2lkdGg9IjEwIiByPSIzNSIgc3Ryb2tlLWRhc2hhcnJheT0iMTY0LjkzMzYxNDMxMzQ2NDE1IDU2Ljk3Nzg3MTQzNzgyMTM4Ij4gICAgPGFuaW1hdGVUcmFuc2Zvcm0gYXR0cmlidXRlTmFtZT0idHJhbnNmb3JtIiB0eXBlPSJyb3RhdGUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIj48L2FuaW1hdGVUcmFuc2Zvcm0+ICA8L2NpcmNsZT48L3N2Zz4=\\\");\\n background-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1152\"},{\"id\":\"p1150\"},{\"id\":\"p1151\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}}]}}],\"callbacks\":{\"type\":\"map\"}}};\n",
185
- " var render_items = [{\"docid\":\"9024d76f-8d10-4a0a-8327-1e46e4bcf29d\",\"roots\":{\"p1149\":\"ad7e920f-cf41-4c46-8ae3-2357eee49c67\"},\"root_ids\":[\"p1149\"]}];\n",
186
- " var docs = Object.values(docs_json)\n",
187
- " if (!docs) {\n",
188
- " return\n",
189
- " }\n",
190
- " const py_version = docs[0].version.replace('rc', '-rc.').replace('.dev', '-dev.')\n",
191
- " const is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1\n",
192
- " function embed_document(root) {\n",
193
- " var Bokeh = get_bokeh(root)\n",
194
- " Bokeh.embed.embed_items_notebook(docs_json, render_items);\n",
195
- " for (const render_item of render_items) {\n",
196
- " for (const root_id of render_item.root_ids) {\n",
197
- "\tconst id_el = document.getElementById(root_id)\n",
198
- "\tif (id_el.children.length && (id_el.children[0].className === 'bk-root')) {\n",
199
- "\t const root_el = id_el.children[0]\n",
200
- "\t root_el.id = root_el.id + '-rendered'\n",
201
- "\t}\n",
202
- " }\n",
203
- " }\n",
204
- " }\n",
205
- " function get_bokeh(root) {\n",
206
- " if (root.Bokeh === undefined) {\n",
207
- " return null\n",
208
- " } else if (root.Bokeh.version !== py_version && !is_dev) {\n",
209
- " if (root.Bokeh.versions === undefined || !root.Bokeh.versions.has(py_version)) {\n",
210
- "\treturn null\n",
211
- " }\n",
212
- " return root.Bokeh.versions.get(py_version);\n",
213
- " } else if (root.Bokeh.version === py_version) {\n",
214
- " return root.Bokeh\n",
215
- " }\n",
216
- " return null\n",
217
- " }\n",
218
- " function is_loaded(root) {\n",
219
- " var Bokeh = get_bokeh(root)\n",
220
- " return (Bokeh != null && Bokeh.Panel !== undefined)\n",
221
- " }\n",
222
- " if (is_loaded(root)) {\n",
223
- " embed_document(root);\n",
224
- " } else {\n",
225
- " var attempts = 0;\n",
226
- " var timer = setInterval(function(root) {\n",
227
- " if (is_loaded(root)) {\n",
228
- " clearInterval(timer);\n",
229
- " embed_document(root);\n",
230
- " } else if (document.readyState == \"complete\") {\n",
231
- " attempts++;\n",
232
- " if (attempts > 200) {\n",
233
- " clearInterval(timer);\n",
234
- "\t var Bokeh = get_bokeh(root)\n",
235
- "\t if (Bokeh == null || Bokeh.Panel == null) {\n",
236
- " console.warn(\"Panel: ERROR: Unable to run Panel code because Bokeh or Panel library is missing\");\n",
237
- "\t } else {\n",
238
- "\t console.warn(\"Panel: WARNING: Attempting to render but not all required libraries could be resolved.\")\n",
239
- "\t embed_document(root)\n",
240
- "\t }\n",
241
- " }\n",
242
- " }\n",
243
- " }, 25, root)\n",
244
- " }\n",
245
- "})(window);</script>"
246
- ],
247
- "text/plain": [
248
- ":Bars [period,Variable] (value)"
249
- ]
250
- },
251
- "execution_count": 20,
252
- "metadata": {
253
- "application/vnd.holoviews_exec.v0+json": {
254
- "id": "p1149"
255
- }
256
- },
257
- "output_type": "execute_result"
258
- }
259
- ],
260
- "source": [
261
- "agg_b = processing.aggregate_analytic_df_by_period(analytic_b, 'D')\n",
262
- "agg_p = processing.aggregate_analytic_df_by_period(analytic_p, 'D')\n",
263
- "bhb_result = processing.calculate_periodic_BHB(agg_b, agg_p)\n",
264
- "agg_bhb_result = processing.aggregate_bhb_df(bhb_result)\n",
265
- "agg_bhb_result.hvplot.bar(\n",
266
- " y=['active_return','allocation',\n",
267
- " 'interaction','selection',\n",
268
- " 'notional_active_return'],rot=45,legend='top')"
269
- ]
270
- },
271
- {
272
- "cell_type": "code",
273
- "execution_count": 131,
274
- "metadata": {},
275
- "outputs": [],
276
- "source": [
277
- "agg_bhb_result['period_str'] = agg_bhb_result.index.map(lambda x: str(x))"
278
- ]
279
- },
280
- {
281
- "cell_type": "code",
282
- "execution_count": 132,
283
- "metadata": {},
284
- "outputs": [
285
- {
286
- "data": {
287
- "text/html": [
288
- "<div>\n",
289
- "<style scoped>\n",
290
- " .dataframe tbody tr th:only-of-type {\n",
291
- " vertical-align: middle;\n",
292
- " }\n",
293
- "\n",
294
- " .dataframe tbody tr th {\n",
295
- " vertical-align: top;\n",
296
- " }\n",
297
- "\n",
298
- " .dataframe thead th {\n",
299
- " text-align: right;\n",
300
- " }\n",
301
- "</style>\n",
302
- "<table border=\"1\" class=\"dataframe\">\n",
303
- " <thead>\n",
304
- " <tr style=\"text-align: right;\">\n",
305
- " <th></th>\n",
306
- " <th>active_return</th>\n",
307
- " <th>allocation</th>\n",
308
- " <th>interaction</th>\n",
309
- " <th>selection</th>\n",
310
- " <th>notional_active_return</th>\n",
311
- " <th>period_str</th>\n",
312
- " </tr>\n",
313
- " <tr>\n",
314
- " <th>period</th>\n",
315
- " <th></th>\n",
316
- " <th></th>\n",
317
- " <th></th>\n",
318
- " <th></th>\n",
319
- " <th></th>\n",
320
- " <th></th>\n",
321
- " </tr>\n",
322
- " </thead>\n",
323
- " <tbody>\n",
324
- " <tr>\n",
325
- " <th>2023-08-08/2023-08-14</th>\n",
326
- " <td>0.000000</td>\n",
327
- " <td>0.000000</td>\n",
328
- " <td>0.000000</td>\n",
329
- " <td>0.00000</td>\n",
330
- " <td>0.000000</td>\n",
331
- " <td>2023-08-08/2023-08-14</td>\n",
332
- " </tr>\n",
333
- " <tr>\n",
334
- " <th>2023-08-15/2023-08-21</th>\n",
335
- " <td>0.043550</td>\n",
336
- " <td>0.043253</td>\n",
337
- " <td>-0.028373</td>\n",
338
- " <td>0.02867</td>\n",
339
- " <td>0.043550</td>\n",
340
- " <td>2023-08-15/2023-08-21</td>\n",
341
- " </tr>\n",
342
- " <tr>\n",
343
- " <th>2023-08-22/2023-08-28</th>\n",
344
- " <td>0.014808</td>\n",
345
- " <td>0.015379</td>\n",
346
- " <td>-0.017291</td>\n",
347
- " <td>0.01672</td>\n",
348
- " <td>0.014808</td>\n",
349
- " <td>2023-08-22/2023-08-28</td>\n",
350
- " </tr>\n",
351
- " <tr>\n",
352
- " <th>2023-08-29/2023-09-04</th>\n",
353
- " <td>0.000000</td>\n",
354
- " <td>0.000000</td>\n",
355
- " <td>0.000000</td>\n",
356
- " <td>0.00000</td>\n",
357
- " <td>0.000000</td>\n",
358
- " <td>2023-08-29/2023-09-04</td>\n",
359
- " </tr>\n",
360
- " </tbody>\n",
361
- "</table>\n",
362
- "</div>"
363
- ],
364
- "text/plain": [
365
- " active_return allocation interaction selection \\\n",
366
- "period \n",
367
- "2023-08-08/2023-08-14 0.000000 0.000000 0.000000 0.00000 \n",
368
- "2023-08-15/2023-08-21 0.043550 0.043253 -0.028373 0.02867 \n",
369
- "2023-08-22/2023-08-28 0.014808 0.015379 -0.017291 0.01672 \n",
370
- "2023-08-29/2023-09-04 0.000000 0.000000 0.000000 0.00000 \n",
371
- "\n",
372
- " notional_active_return period_str \n",
373
- "period \n",
374
- "2023-08-08/2023-08-14 0.000000 2023-08-08/2023-08-14 \n",
375
- "2023-08-15/2023-08-21 0.043550 2023-08-15/2023-08-21 \n",
376
- "2023-08-22/2023-08-28 0.014808 2023-08-22/2023-08-28 \n",
377
- "2023-08-29/2023-09-04 0.000000 2023-08-29/2023-09-04 "
378
- ]
379
- },
380
- "execution_count": 132,
381
- "metadata": {},
382
- "output_type": "execute_result"
383
- }
384
- ],
385
- "source": [
386
- "agg_bhb_result"
387
- ]
388
- },
389
- {
390
- "cell_type": "code",
391
- "execution_count": 133,
392
- "metadata": {},
393
- "outputs": [
394
- {
395
- "data": {
396
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = true;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'plotly': 'https://cdn.plot.ly/plotly-2.18.0.min', 'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"plotly\"], function(Plotly) {\n\twindow.Plotly = Plotly\n\ton_load()\n })\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 10;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['Plotly'] !== undefined) && (!(window['Plotly'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/plotlyplot/plotly-2.18.0.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.holoviz.org/panel/1.1.1/dist/bundled/jquery/jquery.slim.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/bundled/plotlyplot/plotly-2.18.0.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
397
- "application/vnd.holoviews_load.v0+json": ""
398
- },
399
- "metadata": {},
400
- "output_type": "display_data"
401
- },
402
- {
403
- "data": {
404
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
405
- "application/vnd.holoviews_load.v0+json": ""
406
- },
407
- "metadata": {},
408
- "output_type": "display_data"
409
- },
410
- {
411
- "data": {
412
- "text/html": [
413
- "<style>*[data-root-id],\n",
414
- "*[data-root-id] > * {\n",
415
- " box-sizing: border-box;\n",
416
- " font-family: var(--jp-ui-font-family);\n",
417
- " font-size: var(--jp-ui-font-size1);\n",
418
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
419
- "}\n",
420
- "\n",
421
- "/* Override VSCode background color */\n",
422
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
423
- " > .lm-Widget\n",
424
- " > *[data-root-id]),\n",
425
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
426
- " background-color: transparent !important;\n",
427
- "}\n",
428
- "</style>"
429
- ]
430
- },
431
- "metadata": {},
432
- "output_type": "display_data"
433
- },
434
- {
435
- "data": {
436
- "application/vnd.jupyter.widget-view+json": {
437
- "model_id": "49cd388784a7420f8243cbcf76d1cd8b",
438
- "version_major": 2,
439
- "version_minor": 0
440
- },
441
- "text/plain": [
442
- "BokehModel(combine_events=True, render_bundle={'docs_json': {'fba37937-2449-4574-bb28-cb6a96c8cbc3': {'version…"
443
- ]
444
- },
445
- "execution_count": 133,
446
- "metadata": {},
447
- "output_type": "execute_result"
448
- }
449
- ],
450
- "source": [
451
- "import plotly.express as px\n",
452
- "import panel as pn\n",
453
- "pn.extension('plotly')\n",
454
- "fig = px.bar(agg_bhb_result,x='period_str',y=[\n",
455
- " 'allocation', 'selection', 'interaction', 'notional_active_return', 'active_return'])\n",
456
- "pn.pane.Plotly(fig)"
457
- ]
458
- },
459
- {
460
- "cell_type": "code",
461
- "execution_count": null,
462
- "metadata": {},
463
- "outputs": [],
464
- "source": [
465
- "bhb_result"
466
- ]
467
- },
468
- {
469
- "cell_type": "code",
470
- "execution_count": null,
471
- "metadata": {},
472
- "outputs": [
473
- {
474
- "data": {
475
- "text/html": [
476
- "<div>\n",
477
- "<style scoped>\n",
478
- " .dataframe tbody tr th:only-of-type {\n",
479
- " vertical-align: middle;\n",
480
- " }\n",
481
- "\n",
482
- " .dataframe tbody tr th {\n",
483
- " vertical-align: top;\n",
484
- " }\n",
485
- "\n",
486
- " .dataframe thead th {\n",
487
- " text-align: right;\n",
488
- " }\n",
489
- "</style>\n",
490
- "<table border=\"1\" class=\"dataframe\">\n",
491
- " <thead>\n",
492
- " <tr style=\"text-align: right;\">\n",
493
- " <th></th>\n",
494
- " <th>time</th>\n",
495
- " <th>ticker</th>\n",
496
- " <th>open</th>\n",
497
- " <th>close</th>\n",
498
- " <th>high</th>\n",
499
- " <th>low</th>\n",
500
- " <th>volume</th>\n",
501
- " <th>money</th>\n",
502
- " <th>shares</th>\n",
503
- " <th>sector</th>\n",
504
- " <th>aggregate_sector</th>\n",
505
- " <th>display_name</th>\n",
506
- " <th>name</th>\n",
507
- " <th>cash</th>\n",
508
- " <th>ini_w</th>\n",
509
- " <th>ave_price</th>\n",
510
- " <th>weight</th>\n",
511
- " <th>pct</th>\n",
512
- " <th>norm_pct</th>\n",
513
- " <th>return</th>\n",
514
- " </tr>\n",
515
- " </thead>\n",
516
- " <tbody>\n",
517
- " </tbody>\n",
518
- "</table>\n",
519
- "</div>"
520
- ],
521
- "text/plain": [
522
- "Empty DataFrame\n",
523
- "Columns: [time, ticker, open, close, high, low, volume, money, shares, sector, aggregate_sector, display_name, name, cash, ini_w, ave_price, weight, pct, norm_pct, return]\n",
524
- "Index: []"
525
- ]
526
- },
527
- "execution_count": 11,
528
- "metadata": {},
529
- "output_type": "execute_result"
530
- }
531
- ],
532
- "source": [
533
- "# check if there a row with same ticker and time\n",
534
- "analytic_b[analytic_b.duplicated(['ticker', 'time'])]\n",
535
- "analytic_p[analytic_p.duplicated(['ticker', 'time'])]"
536
- ]
537
- }
538
- ],
539
- "metadata": {
540
- "kernelspec": {
541
- "display_name": "risk-dashboard",
542
- "language": "python",
543
- "name": "python3"
544
- },
545
- "language_info": {
546
- "codemirror_mode": {
547
- "name": "ipython",
548
- "version": 3
549
- },
550
- "file_extension": ".py",
551
- "mimetype": "text/x-python",
552
- "name": "python",
553
- "nbconvert_exporter": "python",
554
- "pygments_lexer": "ipython3",
555
- "version": "3.11.4"
556
- },
557
- "orig_nbformat": 4
558
- },
559
- "nbformat": 4,
560
- "nbformat_minor": 2
561
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
total_return.ipynb DELETED
@@ -1,713 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
11
- "application/vnd.holoviews_load.v0+json": ""
12
- },
13
- "metadata": {},
14
- "output_type": "display_data"
15
- },
16
- {
17
- "data": {
18
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
19
- "application/vnd.holoviews_load.v0+json": ""
20
- },
21
- "metadata": {},
22
- "output_type": "display_data"
23
- },
24
- {
25
- "data": {
26
- "text/html": [
27
- "<style>*[data-root-id],\n",
28
- "*[data-root-id] > * {\n",
29
- " box-sizing: border-box;\n",
30
- " font-family: var(--jp-ui-font-family);\n",
31
- " font-size: var(--jp-ui-font-size1);\n",
32
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
33
- "}\n",
34
- "\n",
35
- "/* Override VSCode background color */\n",
36
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
37
- " > .lm-Widget\n",
38
- " > *[data-root-id]),\n",
39
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
40
- " background-color: transparent !important;\n",
41
- "}\n",
42
- "</style>"
43
- ]
44
- },
45
- "metadata": {},
46
- "output_type": "display_data"
47
- },
48
- {
49
- "data": {
50
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = true;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
51
- "application/vnd.holoviews_load.v0+json": ""
52
- },
53
- "metadata": {},
54
- "output_type": "display_data"
55
- },
56
- {
57
- "data": {
58
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
59
- "application/vnd.holoviews_load.v0+json": ""
60
- },
61
- "metadata": {},
62
- "output_type": "display_data"
63
- },
64
- {
65
- "data": {
66
- "text/html": [
67
- "<style>*[data-root-id],\n",
68
- "*[data-root-id] > * {\n",
69
- " box-sizing: border-box;\n",
70
- " font-family: var(--jp-ui-font-family);\n",
71
- " font-size: var(--jp-ui-font-size1);\n",
72
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
73
- "}\n",
74
- "\n",
75
- "/* Override VSCode background color */\n",
76
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
77
- " > .lm-Widget\n",
78
- " > *[data-root-id]),\n",
79
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
80
- " background-color: transparent !important;\n",
81
- "}\n",
82
- "</style>"
83
- ]
84
- },
85
- "metadata": {},
86
- "output_type": "display_data"
87
- },
88
- {
89
- "data": {
90
- "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = true;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'mathjax': '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML', 'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'mathjax': {'exports': 'MathJax'}, 'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"mathjax\"], function() {\n\ton_load()\n })\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 10;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['MathJax'] !== undefined) && (!(window['MathJax'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.1.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));",
91
- "application/vnd.holoviews_load.v0+json": ""
92
- },
93
- "metadata": {},
94
- "output_type": "display_data"
95
- },
96
- {
97
- "data": {
98
- "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n",
99
- "application/vnd.holoviews_load.v0+json": ""
100
- },
101
- "metadata": {},
102
- "output_type": "display_data"
103
- },
104
- {
105
- "data": {
106
- "text/html": [
107
- "<style>*[data-root-id],\n",
108
- "*[data-root-id] > * {\n",
109
- " box-sizing: border-box;\n",
110
- " font-family: var(--jp-ui-font-family);\n",
111
- " font-size: var(--jp-ui-font-size1);\n",
112
- " color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
113
- "}\n",
114
- "\n",
115
- "/* Override VSCode background color */\n",
116
- ".cell-output-ipywidget-background:has(> .cell-output-ipywidget-background\n",
117
- " > .lm-Widget\n",
118
- " > *[data-root-id]),\n",
119
- ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
120
- " background-color: transparent !important;\n",
121
- "}\n",
122
- "</style>"
123
- ]
124
- },
125
- "metadata": {},
126
- "output_type": "display_data"
127
- }
128
- ],
129
- "source": [
130
- "import panel as pn\n",
131
- "import pandas as pd\n",
132
- "import scipy.stats as stats\n",
133
- "from sqlalchemy import create_engine\n",
134
- "import hvplot.pandas\n",
135
- "from datetime import datetime, timedelta\n",
136
- "from script import processing\n",
137
- "import numpy as np\n",
138
- "pn.extension()\n",
139
- "db_url = 'sqlite:///instance/local.db'\n",
140
- "engine = create_engine(db_url)\n",
141
- "import plotly.express as px\n",
142
- "pn.extension('mathjax')"
143
- ]
144
- },
145
- {
146
- "cell_type": "code",
147
- "execution_count": 2,
148
- "metadata": {},
149
- "outputs": [],
150
- "source": [
151
- "%load_ext autoreload\n",
152
- "%autoreload 2"
153
- ]
154
- },
155
- {
156
- "cell_type": "code",
157
- "execution_count": 3,
158
- "metadata": {},
159
- "outputs": [],
160
- "source": [
161
- "p_eval_df = None\n",
162
- "calculated_b_stock = None\n",
163
- "calculated_p_stock = None\n",
164
- "# load benchmark stock\n",
165
- "with engine.connect() as connection:\n",
166
- " calculated_b_stock = pd.read_sql('calculated_b_stock', con=connection)\n",
167
- " calculated_p_stock = pd.read_sql('calculated_p_stock', con=connection)\n",
168
- " p_eval_df = pd.read_sql('p_eval_result', con=connection)"
169
- ]
170
- },
171
- {
172
- "cell_type": "code",
173
- "execution_count": 139,
174
- "metadata": {},
175
- "outputs": [
176
- {
177
- "name": "stdout",
178
- "output_type": "stream",
179
- "text": [
180
- "2023-06-29 00:00:00\n",
181
- "interaction 0.012116\n",
182
- "allocation 0.002211\n",
183
- "selection -0.012116\n",
184
- "active_return 0.002211\n",
185
- "notional_return 0.002211\n",
186
- "dtype: float64\n"
187
- ]
188
- },
189
- {
190
- "data": {
191
- "text/html": [
192
- "<div>\n",
193
- "<style scoped>\n",
194
- " .dataframe tbody tr th:only-of-type {\n",
195
- " vertical-align: middle;\n",
196
- " }\n",
197
- "\n",
198
- " .dataframe tbody tr th {\n",
199
- " vertical-align: top;\n",
200
- " }\n",
201
- "\n",
202
- " .dataframe thead th {\n",
203
- " text-align: right;\n",
204
- " }\n",
205
- "</style>\n",
206
- "<table border=\"1\" class=\"dataframe\">\n",
207
- " <thead>\n",
208
- " <tr style=\"text-align: right;\">\n",
209
- " <th></th>\n",
210
- " <th>date</th>\n",
211
- " <th>portfolio_return_p</th>\n",
212
- " <th>portfolio_pct_p</th>\n",
213
- " <th>portfolio_return_b</th>\n",
214
- " <th>portfolio_pct_b</th>\n",
215
- " <th>mkt_cap</th>\n",
216
- " <th>prev_mkt_cap</th>\n",
217
- " <th>pnl</th>\n",
218
- " <th>risk</th>\n",
219
- " <th>active_return</th>\n",
220
- " <th>tracking_error</th>\n",
221
- " <th>cum_pnl</th>\n",
222
- " <th>return_p</th>\n",
223
- " <th>return_b</th>\n",
224
- " </tr>\n",
225
- " </thead>\n",
226
- " <tbody>\n",
227
- " <tr>\n",
228
- " <th>600</th>\n",
229
- " <td>2023-06-29</td>\n",
230
- " <td>0.343213</td>\n",
231
- " <td>0.006552</td>\n",
232
- " <td>-0.017097</td>\n",
233
- " <td>-0.000125</td>\n",
234
- " <td>1219.334595</td>\n",
235
- " <td>1211.396987</td>\n",
236
- " <td>7.937608</td>\n",
237
- " <td>0.309501</td>\n",
238
- " <td>0.002785</td>\n",
239
- " <td>0.218361</td>\n",
240
- " <td>140.338486</td>\n",
241
- " <td>0.014219</td>\n",
242
- " <td>0.011434</td>\n",
243
- " </tr>\n",
244
- " </tbody>\n",
245
- "</table>\n",
246
- "</div>"
247
- ],
248
- "text/plain": [
249
- " date portfolio_return_p portfolio_pct_p portfolio_return_b \\\n",
250
- "600 2023-06-29 0.343213 0.006552 -0.017097 \n",
251
- "\n",
252
- " portfolio_pct_b mkt_cap prev_mkt_cap pnl risk \\\n",
253
- "600 -0.000125 1219.334595 1211.396987 7.937608 0.309501 \n",
254
- "\n",
255
- " active_return tracking_error cum_pnl return_p return_b \n",
256
- "600 0.002785 0.218361 140.338486 0.014219 0.011434 "
257
- ]
258
- },
259
- "execution_count": 139,
260
- "metadata": {},
261
- "output_type": "execute_result"
262
- }
263
- ],
264
- "source": [
265
- "## check why activate return and nominal return is not same \n",
266
- "# start_date = p_eval_df['date'].min()\n",
267
- "# start_date = datetime(2022, 12, 14)\n",
268
- "start_date = datetime(2023,6,25)\n",
269
- "end_date = p_eval_df['date'].max()\n",
270
- "print(end_date)\n",
271
- "ticker = \"601117.XSHG\"\n",
272
- "attributes_df = processing.calculate_attributes_between_dates(\n",
273
- " start_date, end_date, calculated_b_stock=calculated_b_stock, calculated_p_stock=calculated_p_stock)\n",
274
- "total_attributes = attributes_df.aggregate({\n",
275
- " 'interaction': 'sum',\n",
276
- " 'allocation': 'sum',\n",
277
- " 'selection': 'sum',\n",
278
- " 'active_return': 'sum',\n",
279
- " 'notional_return': 'sum'\n",
280
- " }) \n",
281
- "# print(attributes_df.columns)\n",
282
- "print(total_attributes)\n",
283
- "return_df = processing.calculate_return(p_eval_df, start_date, end_date)\n",
284
- "return_df\n",
285
- "most_recent_row = return_df.tail(1)\n",
286
- "# print(return_df.head(1))\n",
287
- "most_recent_row\n",
288
- "\n",
289
- "\n"
290
- ]
291
- },
292
- {
293
- "cell_type": "code",
294
- "execution_count": 124,
295
- "metadata": {},
296
- "outputs": [
297
- {
298
- "data": {
299
- "text/plain": [
300
- "1219.334714348576"
301
- ]
302
- },
303
- "execution_count": 124,
304
- "metadata": {},
305
- "output_type": "execute_result"
306
- }
307
- ],
308
- "source": [
309
- "1038.573137 * (1 + 0.174048)"
310
- ]
311
- },
312
- {
313
- "cell_type": "code",
314
- "execution_count": 137,
315
- "metadata": {},
316
- "outputs": [
317
- {
318
- "data": {
319
- "text/plain": [
320
- "0.01448137201285984"
321
- ]
322
- },
323
- "execution_count": 137,
324
- "metadata": {},
325
- "output_type": "execute_result"
326
- }
327
- ],
328
- "source": [
329
- "# portfolio return\n",
330
- "attributes_df['w_return_p'] = attributes_df.pct_p * attributes_df.prev_w_in_p_p\n",
331
- "attributes_df.w_return_p.sum()"
332
- ]
333
- },
334
- {
335
- "cell_type": "code",
336
- "execution_count": 129,
337
- "metadata": {},
338
- "outputs": [
339
- {
340
- "data": {
341
- "text/plain": [
342
- "0.09551009084622147"
343
- ]
344
- },
345
- "execution_count": 129,
346
- "metadata": {},
347
- "output_type": "execute_result"
348
- }
349
- ],
350
- "source": [
351
- "0.17190200433908703 - 0.07639191349286556"
352
- ]
353
- },
354
- {
355
- "cell_type": "code",
356
- "execution_count": 138,
357
- "metadata": {},
358
- "outputs": [
359
- {
360
- "data": {
361
- "text/plain": [
362
- "0.011250737770502067"
363
- ]
364
- },
365
- "execution_count": 138,
366
- "metadata": {},
367
- "output_type": "execute_result"
368
- }
369
- ],
370
- "source": [
371
- "# benchmark return\n",
372
- "attributes_df['w_return_b'] = attributes_df.pct_b * attributes_df.prev_w_in_p_b\n",
373
- "attributes_df.w_return_b.sum()"
374
- ]
375
- },
376
- {
377
- "cell_type": "code",
378
- "execution_count": 120,
379
- "metadata": {},
380
- "outputs": [
381
- {
382
- "name": "stderr",
383
- "output_type": "stream",
384
- "text": [
385
- "/var/folders/v5/2108rh5964q9j741wg_s8r1w0000gn/T/ipykernel_87460/2230555833.py:4: SettingWithCopyWarning: \n",
386
- "A value is trying to be set on a copy of a slice from a DataFrame.\n",
387
- "Try using .loc[row_indexer,col_indexer] = value instead\n",
388
- "\n",
389
- "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
390
- " selected_df['return_p'] = (1 + selected_df.portfolio_pct_p).cumprod()\n"
391
- ]
392
- },
393
- {
394
- "data": {
395
- "text/html": [
396
- "<div>\n",
397
- "<style scoped>\n",
398
- " .dataframe tbody tr th:only-of-type {\n",
399
- " vertical-align: middle;\n",
400
- " }\n",
401
- "\n",
402
- " .dataframe tbody tr th {\n",
403
- " vertical-align: top;\n",
404
- " }\n",
405
- "\n",
406
- " .dataframe thead th {\n",
407
- " text-align: right;\n",
408
- " }\n",
409
- "</style>\n",
410
- "<table border=\"1\" class=\"dataframe\">\n",
411
- " <thead>\n",
412
- " <tr style=\"text-align: right;\">\n",
413
- " <th></th>\n",
414
- " <th>date</th>\n",
415
- " <th>portfolio_return_p</th>\n",
416
- " <th>portfolio_pct_p</th>\n",
417
- " <th>portfolio_return_b</th>\n",
418
- " <th>portfolio_pct_b</th>\n",
419
- " <th>mkt_cap</th>\n",
420
- " <th>prev_mkt_cap</th>\n",
421
- " <th>pnl</th>\n",
422
- " <th>risk</th>\n",
423
- " <th>active_return</th>\n",
424
- " <th>tracking_error</th>\n",
425
- " <th>cum_pnl</th>\n",
426
- " <th>return_p</th>\n",
427
- " </tr>\n",
428
- " </thead>\n",
429
- " <tbody>\n",
430
- " <tr>\n",
431
- " <th>471</th>\n",
432
- " <td>2022-12-14</td>\n",
433
- " <td>0.151775</td>\n",
434
- " <td>0.000000</td>\n",
435
- " <td>0.002796</td>\n",
436
- " <td>0.000000</td>\n",
437
- " <td>1038.573137</td>\n",
438
- " <td>1043.453255</td>\n",
439
- " <td>-4.880117</td>\n",
440
- " <td>0.327324</td>\n",
441
- " <td>-0.000508</td>\n",
442
- " <td>0.225463</td>\n",
443
- " <td>-40.422972</td>\n",
444
- " <td>1.000000</td>\n",
445
- " </tr>\n",
446
- " <tr>\n",
447
- " <th>472</th>\n",
448
- " <td>2022-12-15</td>\n",
449
- " <td>0.166816</td>\n",
450
- " <td>0.013638</td>\n",
451
- " <td>0.004505</td>\n",
452
- " <td>0.001707</td>\n",
453
- " <td>1052.737107</td>\n",
454
- " <td>1038.573137</td>\n",
455
- " <td>14.163970</td>\n",
456
- " <td>0.327122</td>\n",
457
- " <td>0.011931</td>\n",
458
- " <td>0.225384</td>\n",
459
- " <td>-26.259002</td>\n",
460
- " <td>1.013638</td>\n",
461
- " </tr>\n",
462
- " <tr>\n",
463
- " <th>473</th>\n",
464
- " <td>2022-12-16</td>\n",
465
- " <td>0.156618</td>\n",
466
- " <td>-0.009792</td>\n",
467
- " <td>-0.000671</td>\n",
468
- " <td>-0.005172</td>\n",
469
- " <td>1042.429190</td>\n",
470
- " <td>1052.737107</td>\n",
471
- " <td>-10.307917</td>\n",
472
- " <td>0.326859</td>\n",
473
- " <td>-0.004619</td>\n",
474
- " <td>0.225175</td>\n",
475
- " <td>-36.566919</td>\n",
476
- " <td>1.003713</td>\n",
477
- " </tr>\n",
478
- " <tr>\n",
479
- " <th>474</th>\n",
480
- " <td>2022-12-19</td>\n",
481
- " <td>0.144766</td>\n",
482
- " <td>-0.012217</td>\n",
483
- " <td>-0.022720</td>\n",
484
- " <td>-0.022046</td>\n",
485
- " <td>1029.693832</td>\n",
486
- " <td>1042.429190</td>\n",
487
- " <td>-12.735359</td>\n",
488
- " <td>0.326642</td>\n",
489
- " <td>0.009829</td>\n",
490
- " <td>0.225043</td>\n",
491
- " <td>-49.302277</td>\n",
492
- " <td>0.991450</td>\n",
493
- " </tr>\n",
494
- " <tr>\n",
495
- " <th>475</th>\n",
496
- " <td>2022-12-20</td>\n",
497
- " <td>0.140936</td>\n",
498
- " <td>-0.003925</td>\n",
499
- " <td>-0.032668</td>\n",
500
- " <td>-0.009947</td>\n",
501
- " <td>1025.652205</td>\n",
502
- " <td>1029.693832</td>\n",
503
- " <td>-4.041626</td>\n",
504
- " <td>0.326312</td>\n",
505
- " <td>0.006022</td>\n",
506
- " <td>0.224844</td>\n",
507
- " <td>-53.343904</td>\n",
508
- " <td>0.987559</td>\n",
509
- " </tr>\n",
510
- " <tr>\n",
511
- " <th>...</th>\n",
512
- " <td>...</td>\n",
513
- " <td>...</td>\n",
514
- " <td>...</td>\n",
515
- " <td>...</td>\n",
516
- " <td>...</td>\n",
517
- " <td>...</td>\n",
518
- " <td>...</td>\n",
519
- " <td>...</td>\n",
520
- " <td>...</td>\n",
521
- " <td>...</td>\n",
522
- " <td>...</td>\n",
523
- " <td>...</td>\n",
524
- " <td>...</td>\n",
525
- " </tr>\n",
526
- " <tr>\n",
527
- " <th>596</th>\n",
528
- " <td>2023-06-21</td>\n",
529
- " <td>0.338226</td>\n",
530
- " <td>-0.012860</td>\n",
531
- " <td>-0.012265</td>\n",
532
- " <td>-0.020746</td>\n",
533
- " <td>1213.343064</td>\n",
534
- " <td>1229.149762</td>\n",
535
- " <td>-15.806698</td>\n",
536
- " <td>0.310372</td>\n",
537
- " <td>0.007886</td>\n",
538
- " <td>0.219003</td>\n",
539
- " <td>134.346955</td>\n",
540
- " <td>1.168279</td>\n",
541
- " </tr>\n",
542
- " <tr>\n",
543
- " <th>597</th>\n",
544
- " <td>2023-06-26</td>\n",
545
- " <td>0.327466</td>\n",
546
- " <td>-0.009151</td>\n",
547
- " <td>-0.028546</td>\n",
548
- " <td>-0.016269</td>\n",
549
- " <td>1202.239760</td>\n",
550
- " <td>1213.343064</td>\n",
551
- " <td>-11.103304</td>\n",
552
- " <td>0.310175</td>\n",
553
- " <td>0.007118</td>\n",
554
- " <td>0.218860</td>\n",
555
- " <td>123.243651</td>\n",
556
- " <td>1.157588</td>\n",
557
- " </tr>\n",
558
- " <tr>\n",
559
- " <th>598</th>\n",
560
- " <td>2023-06-27</td>\n",
561
- " <td>0.339179</td>\n",
562
- " <td>0.010630</td>\n",
563
- " <td>-0.016308</td>\n",
564
- " <td>0.012234</td>\n",
565
- " <td>1215.019735</td>\n",
566
- " <td>1202.239760</td>\n",
567
- " <td>12.779975</td>\n",
568
- " <td>0.309985</td>\n",
569
- " <td>-0.001604</td>\n",
570
- " <td>0.218682</td>\n",
571
- " <td>136.023626</td>\n",
572
- " <td>1.169893</td>\n",
573
- " </tr>\n",
574
- " <tr>\n",
575
- " <th>599</th>\n",
576
- " <td>2023-06-28</td>\n",
577
- " <td>0.335389</td>\n",
578
- " <td>-0.002982</td>\n",
579
- " <td>-0.016974</td>\n",
580
- " <td>-0.000665</td>\n",
581
- " <td>1211.396987</td>\n",
582
- " <td>1215.019735</td>\n",
583
- " <td>-3.622748</td>\n",
584
- " <td>0.309735</td>\n",
585
- " <td>-0.002316</td>\n",
586
- " <td>0.218507</td>\n",
587
- " <td>132.400878</td>\n",
588
- " <td>1.166405</td>\n",
589
- " </tr>\n",
590
- " <tr>\n",
591
- " <th>600</th>\n",
592
- " <td>2023-06-29</td>\n",
593
- " <td>0.343213</td>\n",
594
- " <td>0.006552</td>\n",
595
- " <td>-0.017097</td>\n",
596
- " <td>-0.000125</td>\n",
597
- " <td>1219.334595</td>\n",
598
- " <td>1211.396987</td>\n",
599
- " <td>7.937608</td>\n",
600
- " <td>0.309501</td>\n",
601
- " <td>0.006678</td>\n",
602
- " <td>0.218361</td>\n",
603
- " <td>140.338486</td>\n",
604
- " <td>1.174048</td>\n",
605
- " </tr>\n",
606
- " </tbody>\n",
607
- "</table>\n",
608
- "<p>130 rows × 13 columns</p>\n",
609
- "</div>"
610
- ],
611
- "text/plain": [
612
- " date portfolio_return_p portfolio_pct_p portfolio_return_b \\\n",
613
- "471 2022-12-14 0.151775 0.000000 0.002796 \n",
614
- "472 2022-12-15 0.166816 0.013638 0.004505 \n",
615
- "473 2022-12-16 0.156618 -0.009792 -0.000671 \n",
616
- "474 2022-12-19 0.144766 -0.012217 -0.022720 \n",
617
- "475 2022-12-20 0.140936 -0.003925 -0.032668 \n",
618
- ".. ... ... ... ... \n",
619
- "596 2023-06-21 0.338226 -0.012860 -0.012265 \n",
620
- "597 2023-06-26 0.327466 -0.009151 -0.028546 \n",
621
- "598 2023-06-27 0.339179 0.010630 -0.016308 \n",
622
- "599 2023-06-28 0.335389 -0.002982 -0.016974 \n",
623
- "600 2023-06-29 0.343213 0.006552 -0.017097 \n",
624
- "\n",
625
- " portfolio_pct_b mkt_cap prev_mkt_cap pnl risk \\\n",
626
- "471 0.000000 1038.573137 1043.453255 -4.880117 0.327324 \n",
627
- "472 0.001707 1052.737107 1038.573137 14.163970 0.327122 \n",
628
- "473 -0.005172 1042.429190 1052.737107 -10.307917 0.326859 \n",
629
- "474 -0.022046 1029.693832 1042.429190 -12.735359 0.326642 \n",
630
- "475 -0.009947 1025.652205 1029.693832 -4.041626 0.326312 \n",
631
- ".. ... ... ... ... ... \n",
632
- "596 -0.020746 1213.343064 1229.149762 -15.806698 0.310372 \n",
633
- "597 -0.016269 1202.239760 1213.343064 -11.103304 0.310175 \n",
634
- "598 0.012234 1215.019735 1202.239760 12.779975 0.309985 \n",
635
- "599 -0.000665 1211.396987 1215.019735 -3.622748 0.309735 \n",
636
- "600 -0.000125 1219.334595 1211.396987 7.937608 0.309501 \n",
637
- "\n",
638
- " active_return tracking_error cum_pnl return_p \n",
639
- "471 -0.000508 0.225463 -40.422972 1.000000 \n",
640
- "472 0.011931 0.225384 -26.259002 1.013638 \n",
641
- "473 -0.004619 0.225175 -36.566919 1.003713 \n",
642
- "474 0.009829 0.225043 -49.302277 0.991450 \n",
643
- "475 0.006022 0.224844 -53.343904 0.987559 \n",
644
- ".. ... ... ... ... \n",
645
- "596 0.007886 0.219003 134.346955 1.168279 \n",
646
- "597 0.007118 0.218860 123.243651 1.157588 \n",
647
- "598 -0.001604 0.218682 136.023626 1.169893 \n",
648
- "599 -0.002316 0.218507 132.400878 1.166405 \n",
649
- "600 0.006678 0.218361 140.338486 1.174048 \n",
650
- "\n",
651
- "[130 rows x 13 columns]"
652
- ]
653
- },
654
- "execution_count": 120,
655
- "metadata": {},
656
- "output_type": "execute_result"
657
- }
658
- ],
659
- "source": [
660
- "selected_df = p_eval_df[p_eval_df.date.between(start_date, end_date)]\n",
661
- "selected_df.iloc[0, selected_df.columns.get_indexer(\n",
662
- " ['portfolio_pct_p', 'portfolio_pct_b'])] = 0\n",
663
- "selected_df['return_p'] = (1 + selected_df.portfolio_pct_p).cumprod()\n",
664
- "selected_df"
665
- ]
666
- },
667
- {
668
- "cell_type": "code",
669
- "execution_count": 140,
670
- "metadata": {},
671
- "outputs": [
672
- {
673
- "data": {
674
- "text/plain": [
675
- "Index(['date', 'portfolio_return_p', 'portfolio_pct_p', 'portfolio_return_b',\n",
676
- " 'portfolio_pct_b', 'mkt_cap', 'prev_mkt_cap', 'pnl', 'risk',\n",
677
- " 'active_return', 'tracking_error', 'cum_pnl'],\n",
678
- " dtype='object')"
679
- ]
680
- },
681
- "execution_count": 140,
682
- "metadata": {},
683
- "output_type": "execute_result"
684
- }
685
- ],
686
- "source": [
687
- "p_eval_df.columns"
688
- ]
689
- }
690
- ],
691
- "metadata": {
692
- "kernelspec": {
693
- "display_name": "portfolio_risk_assesment",
694
- "language": "python",
695
- "name": "python3"
696
- },
697
- "language_info": {
698
- "codemirror_mode": {
699
- "name": "ipython",
700
- "version": 3
701
- },
702
- "file_extension": ".py",
703
- "mimetype": "text/x-python",
704
- "name": "python",
705
- "nbconvert_exporter": "python",
706
- "pygments_lexer": "ipython3",
707
- "version": "3.11.4"
708
- },
709
- "orig_nbformat": 4
710
- },
711
- "nbformat": 4,
712
- "nbformat_minor": 2
713
- }