diff --git a/nbs/sandbox/math_changes_bancor.ipynb b/nbs/sandbox/math_changes_bancor.ipynb new file mode 100644 index 0000000..a9469c2 --- /dev/null +++ b/nbs/sandbox/math_changes_bancor.ipynb @@ -0,0 +1,511 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "df38a4c8-b60f-4fde-9fa9-68f9e58ce4a8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#| hide\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "id": "2553366f-d9cf-4c76-b9d9-92285d80f83a", + "metadata": {}, + "source": [ + "# Math Changes for Shawn\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "59036e90-0ab3-4ee2-a854-06f966caa69e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#| default_exp pamm.bancor" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6cb0793b-5288-4fc9-b627-6bc27b19b893", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\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': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\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 } 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.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/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\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\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 root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\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));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "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", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "#| export\n", + "import param as pm\n", + "import panel as pn\n", + "import pandas as pd\n", + "import numpy as np\n", + "import hvplot.pandas\n", + "import holoviews as hv" + ] + }, + { + "cell_type": "markdown", + "id": "16de9413", + "metadata": {}, + "source": [ + "### Set up Types" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "18e15308", + "metadata": {}, + "outputs": [], + "source": [ + "# types\n", + "\n", + "\"\"\"\n", + "Various Python types used in the model\n", + "\"\"\"\n", + "\n", + "\n", + "# Generic types\n", + "Uninitialized = np.nan\n", + "Percentage = float\n", + "\n", + "# math spec conv types\n", + "\n", + "# Dai = int\n", + "# xDai = int\n", + "# Dai_per_token = float\n", + "# tokens = int " + ] + }, + { + "cell_type": "markdown", + "id": "70ae0d84", + "metadata": {}, + "source": [ + "### Params" + ] + }, + { + "cell_type": "markdown", + "id": "1f01f43a", + "metadata": {}, + "source": [ + "### Open questions to discuss with Shawn" + ] + }, + { + "cell_type": "markdown", + "id": "2d145c33", + "metadata": {}, + "source": [ + "* Think about fee ratio discuss with shawn: current idea was to pull a fee and gas fees before we use the invariant. so its taken from the delta R and then \n", + "* Gas belonging to [gas min, gas max] monte carlo run\n", + "* leaving cost and the wedge discussion\n", + "* Does fee break Pamm??? --> ask jeff Do we need fees in the primary ? \n" + ] + }, + { + "cell_type": "markdown", + "id": "01f7fa96", + "metadata": {}, + "source": [ + "* Will paribu wanna preinitialize into a discretionary treasury (non reserve spendable money)\n", + "* with theta 0 we assume everything goes to reserve \n", + "* reserve ratio = R/S*price ??\n", + "* connector weight = ??? and kappa relation \n", + "* connector weight and reserve ratio !!\n", + "* https://medium.com/huobi-research/huobi-beyond-the-white-paper-vol-4-bancor-algorithm-mathematical-economic-analysis-3d91977b6de1#:~:text=In%20the%20above%20formula%2C%20CW,believe%20this%20formula%20is%20flawed.\n" + ] + }, + { + "cell_type": "markdown", + "id": "9acc8232", + "metadata": {}, + "source": [ + "## Hatch Params in BSCi Notation" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ab521010", + "metadata": {}, + "outputs": [], + "source": [ + "# state variables\n", + "\n", + "# S_supply = S0_initial_supply\n", + "# R_reserve = R0_initial_reserve\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "9648015a", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Hatch params (stay const after hatch)\n", + "\n", + "d0_initial_raise = 100 #(Dai) d0 must be between bounds of dmax dmin \n", + "theta = 0 #must be between 0 and 1\n", + "kappa = 2 # bounds not sure need not be integer either right??\n", + "p0_hatch_sale_price = 1 #(dai per token)\n", + "\n", + "R0_initial_reserve = (1-theta)*d0_initial_raise \n", + "S0_initial_supply = d0_initial_raise/p0_hatch_sale_price # (tokens)\n", + "V0_power_function_invariant = (S0_initial_supply**kappa)/R0_initial_reserve # (tokens^kappa / dai)\n", + "p1_post_hatch_price = kappa*(1-theta)*p0_hatch_sale_price # (dai per token)\n", + "return_factor = kappa*(1-theta) # (dai per dai) p1/p0\n", + "\n", + "\n", + "# methods\n", + "def deposit_to_mint(delta_R, R_reserve, S_supply):\n", + " ''' Deposit delta R to mint delta S'''\n", + " delta_S = ((V0_power_function_invariant*(R_reserve+delta_R))**(1/kappa) - S_supply)\n", + " return delta_S\n", + "\n", + "def burn_to_withdraw(delta_S, R_reserve, S_supply):\n", + " ''' Burn delta S to withdraw delta R'''\n", + " delta_R = R_reserve - (((S_supply - delta_S)**kappa) / V0_power_function_invariant)\n", + " return delta_R\n", + "\n", + "\n", + "def get_supply_from_reserve(R_reserve):\n", + " '''get supply from new reserve value to conserve invariant'''\n", + " return (R_reserve * V0_power_function_invariant)**(1/kappa)\n", + "\n", + "def get_reserve_from_supply(S_supply):\n", + " '''get reserve from new supply value to conserve invariant'''\n", + " return S_supply**kappa / V0_power_function_invariant\n", + "\n", + "def check_invariant(R_reserve, S_supply):\n", + " '''check if invariant is conserved in current state'''\n", + " return (S_supply**kappa)/R_reserve == V0_power_function_invariant\n", + "\n", + "def realised_price(delta_R, delta_S):\n", + " '''get realised price from delta R and delta S'''\n", + " return delta_R/delta_S\n", + "\n", + "def spot_price(R_reserve, S_supply):\n", + " '''get spot price from current R and S which is a limit of realised price when delta R tends to zero'''\n", + " return kappa*R_reserve**((kappa-1)/kappa)/V0_power_function_invariant**(1/kappa)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "c55a20dd", + "metadata": {}, + "source": [ + "### Attempt to get it in Param class format (need your help here shawn)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "aad4b701", + "metadata": {}, + "outputs": [], + "source": [ + "import param as pm\n", + "# import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "class BC(pm.Parameterized):\n", + " d0_initial_raise = pm.Number(100, bounds=(1, None)) # (Dai) d0 must be between bounds of dmax dmin \n", + " theta = pm.Number(0.8, bounds=(0, 1)) # must be between 0 and 1\n", + " kappa = pm.Number(2, bounds=(1, None)) # bounds not sure need not be integer either right??\n", + " p0_hatch_sale_price = pm.Number(1, bounds=(0.01, None)) # (dai per token)\n", + "\n", + " R0_initial_reserve = pm.Number(constant=True)\n", + " S0_initial_supply = pm.Number(constant=True)\n", + " V0_power_function_invariant = pm.Number(constant=True)\n", + " p1_post_hatch_price = pm.Number(constant=True)\n", + " return_factor = pm.Number(constant=True)\n", + "\n", + " def __init__(self, **params):\n", + " super().__init__(**params)\n", + " self.update()\n", + "\n", + " @pm.depends('d0_initial_raise', 'theta', 'kappa', 'p0_hatch_sale_price', watch=True)\n", + " def update(self):\n", + " with pm.edit_constant(self):\n", + " self.R0_initial_reserve = (1 - self.theta) * self.d0_initial_raise\n", + " self.S0_initial_supply = self.d0_initial_raise / self.p0_hatch_sale_price\n", + " self.V0_power_function_invariant = (self.S0_initial_supply ** self.kappa) / self.R0_initial_reserve\n", + " self.p1_post_hatch_price = self.kappa * (1 - self.theta) * self.p0_hatch_sale_price\n", + " self.return_factor = self.kappa * (1 - self.theta)\n", + "\n", + " def deposit_to_mint(self, delta_R, R_reserve, S_supply):\n", + " ''' Deposit delta R to mint delta S'''\n", + " delta_S = ((self.V0_power_function_invariant * (R_reserve + delta_R)) ** (1 / self.kappa) - S_supply)\n", + " return delta_S\n", + "\n", + " def burn_to_withdraw(self, delta_S, R_reserve, S_supply):\n", + " ''' Burn delta S to withdraw delta R'''\n", + " delta_R = R_reserve - (((S_supply - delta_S) ** self.kappa) / self.V0_power_function_invariant)\n", + " return delta_R\n", + "\n", + " def get_supply_from_reserve(self, R_reserve):\n", + " return (R_reserve * self.V0_power_function_invariant) ** (1 / self.kappa)\n", + "\n", + " def get_reserve_from_supply(self, S_supply):\n", + " return S_supply ** self.kappa / self.V0_power_function_invariant\n", + "\n", + " def check_invariant(self, R_reserve, S_supply):\n", + " return (S_supply ** self.kappa) / R_reserve == self.V0_power_function_invariant\n", + "\n", + " def realised_price(self, delta_R, delta_S):\n", + " return delta_R / delta_S\n", + "\n", + " def spot_price(self, R_reserve, S_supply):\n", + " return self.kappa * R_reserve ** ((self.kappa - 1) / self.kappa) / self.V0_power_function_invariant ** (1 / self.kappa)\n", + " \n", + " def view_chart(self):\n", + " delta_R_values = np.linspace(1, 100, 100)\n", + " delta_S_values = np.linspace(1, 100, 100)\n", + "\n", + " realised_prices = [self.realised_price(delta_R, delta_S) for delta_R, delta_S in zip(delta_R_values, delta_S_values)]\n", + "\n", + " df = pd.DataFrame({\n", + " 'Delta R': delta_R_values,\n", + " 'Realised Price': realised_prices\n", + " })\n", + "\n", + " return df.hvplot.line(x='Delta R', y='Realised Price', grid=True)\n", + "\n", + " def view(self):\n", + " return pn.Row(self, self.view_chart)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "aedce63a", + "metadata": {}, + "outputs": [], + "source": [ + "b = BC()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "69a1ccee", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a4fa2972506c4e26a4760a6467e7380c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "BokehModel(combine_events=True, render_bundle={'docs_json': {'a05b64fc-284b-489f-b51d-59692c2f76b2': {'version…" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.view()" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "0985b99e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.check_invariant(70, 100)" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtAAAADPCAYAAADcSOb7AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAE6aSURBVHhe7d0PcBTnnTf4b16/K2epKGeXWFIRmxyzcWU473lMTlKdLWHKyLoI47JE9oB40SAvgq0F7Eja1CKnAuhqJXIx8sYaqWzMVpAcy6OUkV2JJJdBqoXhXpZROZaqDOMLpdnCHp05jdecpkwhL7XMa6rvebp7pO6enj8t9J/vh2o03T3T/TxP98z8+ulf93xNEUBERERERFn5L/pfIiIiIiLKAgNoIiIiIiIHGEATERERETnAAJqIiIiIyAEG0EREREREDjCAJiIiIiJygAE0EREREZEDDKCJiIiIiBxgAE1ERERE5AADaCIiIiIiBxhAExERERE5wACaiIiIiMgBBtBERERERA4wgCYiIiIicoABNBERERGRAwygiYiIiIgcYABNREREROQAA2giIiIiIgcYQBMREREROcAAmoiIiIjIAQbQREREREQOMIAmIiIiInKAATQRERERkQMMoImIiIiIHGAATURERETkAANoIiIiIiIHGEATERERETnAAJqIiIiIyAEG0EREREREDjCAJiIiIiJygAE0EREREZEDDKCJiIiIiBxgAE1ERERE5AADaKJFJD7UgsoTYX2MiIiIFiMG0Asihr7aQhS2h/TxReBaH+oKRZnE4LuoT7Nz0SeeU4e+a/r4DIXaxbpq+0RLLEf69pXt6XAbR8JBFH7fpY8RERHRYsQAeg7E+uu04Mk0+LCIwmWLEHybm+E6MYKRkRHUr9Mn04yE2svR/ECn2pYjtR59ajZiiHyUD7crRx8nIiKixYgB9KwSgagIlsvPlGJQBk+GobM6gshUr20eKtudBldz6JooG0rgytfH01lXL+rThspV+nhGWptYe7U9taL+7ZWiJZYbEQRfAUrWrNbHHbj9CUZH3FibzXYgIiKiBcMAetbI0/Y1iDQO2gaGnlonQSfdla5GMFy8Fq579HEiIiJalBhAC0ePHsWGDRvUQT6ekYtvonnIi90V2fSpajmydf1aBrCaD5yUK2t+jmRNDTH36k4/X11e4nkZ8ozVZW5uRlD8a94sX6Onmqi5zuKx+tewnMR0+XiKIedXH9Syqc+tgV889O8x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" + } + }, + "cell_type": "markdown", + "id": "60dc64dd", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)\n", + "\n", + "havent understood these yet ^^" + ] + }, + { + "cell_type": "markdown", + "id": "5e7a1a8a", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}