From 847ecbf2b9141658535fbbd8b5d7ab90cf4f311b Mon Sep 17 00:00:00 2001 From: dual-token-model Date: Thu, 12 Mar 2020 13:39:42 +0000 Subject: [PATCH] 0.0.5 --- README.md | 2 + dual-token-model.ipynb | 353 +++++++++++++++++++++++------------------ 2 files changed, 197 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index 90da1d9..7f3ccd5 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,5 @@ Follow the [LINK](dual-token-model.ipynb). ## Github Release Follow the [LINK](https://github.com/vang1ong7ang/DualTokenModel/releases). + +*Interactive figures are lost if you open the article in github preview.* diff --git a/dual-token-model.ipynb b/dual-token-model.ipynb index ce85817..f75b71a 100644 --- a/dual-token-model.ipynb +++ b/dual-token-model.ipynb @@ -1,5 +1,18 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# YOU DON'T NEED TO READ THIS SECTION UNLESS YOU WANT TO KNOW THE IMPLEMENT DETAILS OF FIGURES\n", + "import numpy\n", + "import matplotlib\n", + "import ipywidgets\n", + "%matplotlib inline" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -84,6 +97,44 @@ "*Only the principles are statemented in this section. All the incentive details will be ommited here.*" ] }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# YOU DON'T NEED TO READ THIS SECTION UNLESS YOU WANT TO KNOW THE IMPLEMENT DETAILS OF FIGURES\n", + "class solution:\n", + " S=ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", + " T=ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", + " K=ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", + " @classmethod\n", + " def decorator(self):\n", + " return ipywidgets.interact(\n", + " S=self.S,\n", + " T=self.T,\n", + " K=self.K,\n", + " )\n", + " def __init__(self, S, T, K):\n", + " self.S = S\n", + " self.T = T\n", + " self.K = K\n", + " class r:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def proportion(self, x):\n", + " return self.context.S * numpy.arctan(self.context.K * x) + self.context.T\n", + " def gn(self, g, n):\n", + " return self.proportion(g/n)\n", + " class w:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def nr(self, n, r):\n", + " return n * r\n", + " def gn(self, g, n):\n", + " return n * solution.r(self.context).gn(g, n)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -109,7 +160,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The reward weight rate $r$ is defined in the following expression and it is used in the redistribution of inflation of GAS to evaluate how much weight per NEO the specific governance participant has. The specific governance participant owns $g$ GAS and $n$ NEO. Then an $\\arctan$ function is attached to the proportion of GAS and NEO held by the participant and the proportion will be converged between $0$ and $\\frac{\\pi}{2}$. At last, the additional reward weight rate $S$ and the minimal reward weight rate $T$ is attached in a linear scale to adjust the basic reward rate and addtional reward rate." + "The reward weight rate $r$ is defined in the following expression and it is used in the redistribution of inflation of GAS to evaluate how much weight per NEO the specific governance participant has. The specific governance participant owns $g$ GAS and $n$ NEO. Then an $\\arctan$ function is attached to the proportion of GAS and NEO held by the participant and the proportion will be converged between $0$ and $\\frac{\\pi}{2}$. At last, the additional reward weight rate $S$, the minimal reward weight rate $T$ and the additional reward weight speed $K$ are attached as a linear scale to adjust the basic reward rate and addtional reward rate." ] }, { @@ -117,7 +168,7 @@ "metadata": {}, "source": [ "$$\n", - "r = S \\arctan{\\frac{g}{n}} + T\n", + "r = S \\arctan{\\frac{g}{n} K} + T\n", "$$" ] }, @@ -130,13 +181,13 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "fb37ecf099b841b8831c2481b6aae651", + "model_id": "ed9e6399609041f1a9495bc357829a5b", "version_major": 2, "version_minor": 0 }, @@ -149,19 +200,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "@ipywidgets.interact(S=S, T=T)\n", - "def draw(S, T):\n", + "@solution.decorator()\n", + "def draw(S, T, K):\n", + " c = solution(S, T, K)\n", " x = numpy.arange(0,100,0.001)\n", - " y = S * numpy.arctan(x) + T\n", + " y = solution.r(c).proportion(x)\n", " matplotlib.pyplot.xlabel('g/n')\n", " matplotlib.pyplot.ylabel('r')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -177,13 +220,13 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "079b0c602862425f96ec577516e9dc94", + "model_id": "0ba436fd83a6416d831c1814ae78039f", "version_major": 2, "version_minor": 0 }, @@ -196,20 +239,12 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "@ipywidgets.interact(S=S, T=T)\n", - "def draw(S, T):\n", + "@solution.decorator()\n", + "def draw(S, T, K):\n", + " c = solution(S, T, K)\n", " x = numpy.arange(-8,8,0.001)\n", - " y = S * numpy.arctan(10**x) + T\n", - " matplotlib.pyplot.xlabel('log(g/n)')\n", + " y = solution.r(c).proportion(10**x)\n", + " matplotlib.pyplot.xlabel('g/n')\n", " matplotlib.pyplot.ylabel('r')\n", " matplotlib.pyplot.plot(x, y)\n", " matplotlib.pyplot.show()" @@ -240,13 +275,13 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "07e7997944124aeb9f948eaaab14eab0", + "model_id": "74fd306e94cd4e729071a52ceccc8fc0", "version_major": 2, "version_minor": 0 }, @@ -259,21 +294,13 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "@ipywidgets.interact(S=S, T=T)\n", - "def draw(S, T):\n", + "@solution.decorator()\n", + "def draw(S, T, K):\n", + " c = solution(S, T, K)\n", " x = numpy.arange(1,10,1)\n", " y = numpy.arange(0.1,100,0.1)\n", " x, y = numpy.meshgrid(x, y)\n", - " z = x * S * numpy.arctan(10**(y/x)) + T\n", + " z = solution.w(c).gn(y, x)\n", " matplotlib.pyplot.gca(projection='3d').plot_surface(x, y, z)\n", " matplotlib.pyplot.show()" ] @@ -305,49 +332,51 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "TODO: SPEND ARCTAN" + "## Reward Weight Rate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## More NEO Held, More GAS Rewarded" + "Reward weight rate $r$ is designed to distribute the inflation GAS. The $\\arctan$ function provides pretty good features for the distribution weight. Governance participants will get the basic reward weight if it doesn't hold any GAS, which means, the NEO holder will be incentived if it participated in the on-chain governance. The additional reward is limitted even if the governance participant hold large amount of GAS. However, over all, participants should know:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "$$\\frac{\\partial e}{\\partial n} \\geqslant 0$$" + "More NEO held, more GAS rewarded." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## More GAS Held, More GAS Rewarded" + "$$\n", + "\\frac{\\partial e}{\\partial n} \\gt 0\n", + "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "$$\\frac{\\partial e}{\\partial g} \\geqslant 0$$" + "More GAS held, more GAS rewarded." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# The Experiment" + "$$\\frac{\\partial e}{\\partial g} \\gt 0$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "TODO" + "It is harmless for participants to spend a bit GAS if it need to because only a bit GAS will not decrease much of your reward weight rate if the governance participant hold enough GAS." ] }, { @@ -371,6 +400,73 @@ "By assuming Alice has $A$ dollars and $N$ is the price of NEO in dollar and $G$ is the price of GAS in dollar, the following expression is statemented because Alice spend all her money to buy NEO and GAS." ] }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# YOU DON'T NEED TO READ THIS SECTION UNLESS YOU WANT TO KNOW THE IMPLEMENT DETAILS OF FIGURES\n", + "class retial_investor(solution):\n", + " A=ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", + " G=ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", + " N=ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", + " I = ipywidgets.widgets.FloatSlider(min=10**6, max=10**8, step=10**6, value=10**7)\n", + " U = ipywidgets.widgets.FloatSlider(min=10**8, max=10**8, step=10**8, value=10**8)\n", + " R = ipywidgets.widgets.FloatSlider(min=0, max=1, step=0.01, value=0.25)\n", + " W = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.01, value=0.4)\n", + " @classmethod\n", + " def decorator(self):\n", + " return ipywidgets.interact(\n", + " S=self.S,\n", + " T=self.T,\n", + " K=self.K,\n", + " A=self.A,\n", + " G=self.G,\n", + " N=self.N,\n", + " I=self.I,\n", + " U=self.U,\n", + " R=self.R,\n", + " W=self.W,\n", + " )\n", + " def __init__(self, S, T, K, A, G, N, I, U, R, W):\n", + " super().__init__(S, T, K)\n", + " self.A = A\n", + " self.G = G\n", + " self.N = N\n", + " self.I = I\n", + " self.U = U\n", + " self.R = R\n", + " self.W = W\n", + " class g:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def n(self, n):\n", + " return (self.context.A - n * self.context.N) / self.context.G\n", + " class r:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def n(self, n):\n", + " g = retial_investor.g(self.context).n(n)\n", + " return solution.r(self.context).gn(g, n)\n", + " class w:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def n(self, n):\n", + " g = retial_investor.g(self.context).n(n)\n", + " return solution.w(self.context).gn(g, n)\n", + " class e:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def n(self, n):\n", + " return retial_investor.w(self.context).n(n) * self.context.I / self.context.U / self.context.R / self.context.W\n", + " class p:\n", + " def __init__(self, context):\n", + " self.context = context\n", + " def n(self, n):\n", + " return retial_investor.e(self.context).n(n) * self.context.G / self.context.A" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -405,13 +501,13 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "db152a28ff1e4801abad902d324e25f3", + "model_id": "70cd46d9ede34fb7a5be495ca25e4c3f", "version_major": 2, "version_minor": 0 }, @@ -424,23 +520,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "A = ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", - "G = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", - "N = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", - "\n", - "@ipywidgets.interact(S=S, T=T, A=A, G=G, N=N)\n", - "def draw(S, T, A, G, N):\n", + "@retial_investor.decorator()\n", + "def draw(S, T, K, A, G, N, I, U, R, W):\n", + " c = retial_investor(S, T, K, A, G, N, I, U, R, W)\n", " x = numpy.arange(0.001,A/N,0.001)\n", - " y = (A - x * N) / G\n", + " y = retial_investor.g(c).n(x)\n", " matplotlib.pyplot.xlabel('n')\n", " matplotlib.pyplot.ylabel('g')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -459,7 +543,7 @@ "metadata": {}, "source": [ "$$\n", - "r = S \\arctan{\\frac{A - n N}{n G}} + T\n", + "r = S \\arctan{\\frac{A - n N}{n G} K} + T\n", "$$" ] }, @@ -472,13 +556,13 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d0216c6d66ad491785e0c46ef3d5949a", + "model_id": "ba8a3782e6894fb5a6a90db77a2a62ce", "version_major": 2, "version_minor": 0 }, @@ -491,23 +575,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "A = ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", - "G = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", - "N = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", - "\n", - "@ipywidgets.interact(S=S, T=T, A=A, G=G, N=N)\n", - "def draw(S, T, A, G, N):\n", + "@retial_investor.decorator()\n", + "def draw(S, T, K, A, G, N, I, U, R, W):\n", + " c = retial_investor(S, T, K, A, G, N, I, U, R, W)\n", " x = numpy.arange(0.001,A/N,0.001)\n", - " y = S * numpy.arctan((A - x * N) / (x * G)) + T\n", + " y = retial_investor.r(c).n(x)\n", " matplotlib.pyplot.xlabel('n')\n", " matplotlib.pyplot.ylabel('r')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -526,7 +598,7 @@ "metadata": {}, "source": [ "$$\n", - "w = n S \\arctan{\\frac{A - n N}{n G}} + n T\n", + "w = n S \\arctan{\\frac{A - n N}{n G} K} + n T\n", "$$" ] }, @@ -539,13 +611,13 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "e755ba6c6d9e42a0b8be292c01197574", + "model_id": "f9003296ab44440484cf271699c4ed10", "version_major": 2, "version_minor": 0 }, @@ -558,23 +630,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "A = ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", - "G = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", - "N = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", - "\n", - "@ipywidgets.interact(S=S, T=T, A=A, G=G, N=N)\n", - "def draw(S, T, A, G, N):\n", + "@retial_investor.decorator()\n", + "def draw(S, T, K, A, G, N, I, U, R, W):\n", + " c = retial_investor(S, T, K, A, G, N, I, U, R, W)\n", " x = numpy.arange(0.001,A/N,0.001)\n", - " y = x * S * numpy.arctan((A - x * N) / (x * G)) + x * T\n", + " y = retial_investor.w(c).n(x)\n", " matplotlib.pyplot.xlabel('n')\n", " matplotlib.pyplot.ylabel('w')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -606,13 +666,13 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "229e67b0f350421089a01ed19e59940b", + "model_id": "718be0550ace46f5982ba9adf6a91504", "version_major": 2, "version_minor": 0 }, @@ -625,29 +685,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "A = ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", - "G = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", - "N = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", - "\n", - "I = ipywidgets.widgets.FloatSlider(min=10**6, max=10**8, step=10**6, value=10**7)\n", - "U = ipywidgets.widgets.FloatSlider(min=10**8, max=10**8, step=10**8, value=10**8)\n", - "R = ipywidgets.widgets.FloatSlider(min=0, max=1, step=0.01, value=0.25)\n", - "W = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.01, value=0.4)\n", - "\n", - "@ipywidgets.interact(S=S, T=T, A=A, G=G, N=N, I=I, U=U, R=R, W=W)\n", - "def draw(S, T, A, G, N, I, U, R, W):\n", + "@retial_investor.decorator()\n", + "def draw(S, T, K, A, G, N, I, U, R, W):\n", + " c = retial_investor(S, T, K, A, G, N, I, U, R, W)\n", " x = numpy.arange(0.001,A/N,0.001)\n", - " y = x * S * numpy.arctan((A - x * N) / (x * G)) + x * T\n", - " y = y * I / U / R / W\n", + " y = retial_investor.e(c).n(x)\n", " matplotlib.pyplot.xlabel('n')\n", " matplotlib.pyplot.ylabel('e')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -658,7 +700,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Then the rate of profit $p$ in dollar can be couted:" + "Then the rate of profit $p$ in dollar can be couted, with the assumption that the price of GAS in dollar will not changed after the inflation:" ] }, { @@ -679,13 +721,13 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "9de4d6b503cf41d190dbfb720b0476eb", + "model_id": "01ed7de1d1e545e189d5d68d12a5c3ce", "version_major": 2, "version_minor": 0 }, @@ -698,30 +740,11 @@ } ], "source": [ - "import numpy\n", - "import matplotlib\n", - "import ipywidgets\n", - "\n", - "%matplotlib inline\n", - "\n", - "S = ipywidgets.widgets.FloatSlider(min=0, max=4/numpy.pi, step=2/numpy.pi/10, value=2/numpy.pi)\n", - "T = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.1, value=1)\n", - "\n", - "A = ipywidgets.widgets.FloatSlider(min=0, max=1000, step=10, value=100)\n", - "G = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=2)\n", - "N = ipywidgets.widgets.FloatSlider(min=0, max=100, step=1, value=10)\n", - "\n", - "I = ipywidgets.widgets.FloatSlider(min=10**6, max=10**8, step=10**6, value=10**7)\n", - "U = ipywidgets.widgets.FloatSlider(min=10**8, max=10**8, step=10**8, value=10**8)\n", - "R = ipywidgets.widgets.FloatSlider(min=0, max=1, step=0.01, value=0.25)\n", - "W = ipywidgets.widgets.FloatSlider(min=0, max=2, step=0.01, value=0.4)\n", - "\n", - "@ipywidgets.interact(S=S, T=T, A=A, G=G, N=N, I=I, U=U, R=R, W=W)\n", - "def draw(S, T, A, G, N, I, U, R, W):\n", + "@retial_investor.decorator()\n", + "def draw(S, T, K, A, G, N, I, U, R, W):\n", + " c = retial_investor(S, T, K, A, G, N, I, U, R, W)\n", " x = numpy.arange(0.001,A/N,0.001)\n", - " y = x * S * numpy.arctan((A - x * N) / (x * G)) + x * T\n", - " y = y * I / U / R / W\n", - " y = y * G / A\n", + " y = retial_investor.p(c).n(x)\n", " matplotlib.pyplot.xlabel('n')\n", " matplotlib.pyplot.ylabel('p')\n", " matplotlib.pyplot.plot(x, y)\n", @@ -735,6 +758,20 @@ "As a result, the best strategy for Alice is to buy $n$ NEO to reach the highest rate of profit $p$." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exchange Rate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The solution makes a soft exchange rate for NEO and GAS." + ] + }, { "cell_type": "markdown", "metadata": {},