From de434f34d2c5c4aa84cd508308a74af13fcd02ae Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 7 May 2024 17:11:51 +0200 Subject: [PATCH] cleanup --- .gitignore | 6 +- BRANCH_OPTIMIZER_API | 39 - resources/NBTest/NBTEST_013_Convergence.ipynb | 385 ----- resources/NBTest/NBTEST_013_Convergence.py | 168 -- .../NBTest_011_CPCOptimizerNewFeatures.ipynb | 476 ------ .../NBTest_011_CPCOptimizerNewFeatures.py | 141 -- resources/NBTest/NBTest_012_APIBasics.ipynb | 1408 ----------------- resources/NBTest/NBTest_012_APIBasics.py | 402 ----- resources/NBTest/Optimizer_2312_THOR.ipynb | 1140 ------------- resources/NBTest/Optimizer_2312_THOR.py | 291 ---- resources/NBTest/Optimizer_2405_SEI.ipynb | 1140 ------------- resources/NBTest/Optimizer_2405_SEI2.ipynb | 909 ----------- resources/NBTest/Optimizer_2405_SEI2.py | 269 ---- .../NBTest/Optimizer_9999_TEMPLATE.ipynb | 923 ----------- resources/NBTest/Optimizer_9999_TEMPLATE.py | 311 ---- 15 files changed, 2 insertions(+), 8006 deletions(-) delete mode 100644 BRANCH_OPTIMIZER_API delete mode 100644 resources/NBTest/NBTEST_013_Convergence.ipynb delete mode 100644 resources/NBTest/NBTEST_013_Convergence.py delete mode 100644 resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.ipynb delete mode 100644 resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.py delete mode 100644 resources/NBTest/NBTest_012_APIBasics.ipynb delete mode 100644 resources/NBTest/NBTest_012_APIBasics.py delete mode 100644 resources/NBTest/Optimizer_2312_THOR.ipynb delete mode 100644 resources/NBTest/Optimizer_2312_THOR.py delete mode 100644 resources/NBTest/Optimizer_2405_SEI.ipynb delete mode 100644 resources/NBTest/Optimizer_2405_SEI2.ipynb delete mode 100644 resources/NBTest/Optimizer_2405_SEI2.py delete mode 100644 resources/NBTest/Optimizer_9999_TEMPLATE.ipynb delete mode 100644 resources/NBTest/Optimizer_9999_TEMPLATE.py diff --git a/.gitignore b/.gitignore index 5e3d05b03..07d379ea9 100644 --- a/.gitignore +++ b/.gitignore @@ -26,9 +26,8 @@ carbon/tools/* */.coverage */.coverage.* */.cover -NBTest/carbon/* -NBTest/carbon -resources/NBTest/fastlane_bot + +.python-version /.env *.env @@ -72,4 +71,3 @@ logs/* /fastlane_bot/data/blockchain_data/*/token_detail/ missing_tokens_df.csv tokens_and_fee_df.csv -fastlane_bot/tests/nbtest/* diff --git a/BRANCH_OPTIMIZER_API b/BRANCH_OPTIMIZER_API deleted file mode 100644 index a98c2eeb7..000000000 --- a/BRANCH_OPTIMIZER_API +++ /dev/null @@ -1,39 +0,0 @@ -TESTS PASSING -======================================== - -b05cc7534f12cd007331eb8f94d91366b1b0fa19 -3e5e303507aabdba752cbc8c9bb4935fa0fec54b -f1b73c976457fbcdc6b2b6a72ad0f91034a0d9bb -a470917522791c495e390dd00bd84b1e657ab195 -7a48c16548144b9a150ab051d2ed7c688e319fa2 -a9d58676064d864e0a1a1e159b30d48a43b2a2f4 - -8e4aaed530017b6e2afc750d20c624c92f24331e -24eee9ce1c035ba717e2529b31967737fab76b54 -263e0da2ec5c98eee5cceb7d368e1dd8b7373eff -86300491737ef50f77b67822817b04d185a52def -1bc6884fc7db093d45c231aac1557d744e324a27 -1e2c239839e2cb375cf92bf80f88c25dafd97f78 -248848388211f5bbffe675617131b4c6c2caeefd -1b007c1a717b1bdecc9496d5fe4f8a82ff1fe647 -6071f7b9323d07fdf88322e7dc445b04fe253c71 -e4f98ce0c1505b7b8f78701a78f51cc485cb0cbe -f296be6f275c174bdac41abe8a96b7f27ab8b3bf -47868011a432d61aca69634e5434147e7f4206bb -73ee4464579974b9e44dfe24e9f4cd40150a99b7 -2ee0dfc5630c6f347be2a795bb5d3e140c1990c1 - -0b20ce87b7d4f4c9f68c640141833fe48ddd3cb0 -bb67afd363e76e090a1db0248147ebd6d9ee0268 -97ea4f5000c1fdc612a5d2d32228d19c963fc87d -475d1b17441ca76bec0e67ecf6c9fe9655b82c5f -c650a3adfad34ea14aa46b600e415cb448634c64 -8d0dbc9bb5960dd7cdd7a960a4553605690dff11 -8a73a44c4a5f332cc681132f92db05e8c6d5e1e4 -96885de9d6980421e8bab5ce240a2915fff83948 -5b5a3daea85094d12d68a4b1236171780affc897 - - - -ROOT -694c4c38f9df26ac5d75d4a657d2a4fd2cdfe036 \ No newline at end of file diff --git a/resources/NBTest/NBTEST_013_Convergence.ipynb b/resources/NBTest/NBTEST_013_Convergence.ipynb deleted file mode 100644 index 349b75835..000000000 --- a/resources/NBTest/NBTEST_013_Convergence.ipynb +++ /dev/null @@ -1,385 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "dce7f14d-b45a-40fb-9caa-cc82a4ec28be", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require, Timer\n", - "SimplePair v2.2 (30/Apr/2024)\n", - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "CPCArbOptimizer v6.0-beta1 (05/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n", - "PairOptimizer v6.0.2 (03/May/2024)\n" - ] - } - ], - "source": [ - "try:\n", - " from tools import ConstantProductCurve as CPC, CurveContainer\n", - " from tools.curves import T, CPCInverter, Pair\n", - " from tools import MargPOptimizer, PairOptimizer\n", - " from tools.optimizer import CPCArbOptimizer, F\n", - " from tools.analyzer import CPCAnalyzer\n", - " from tools.testing import * \n", - " \n", - " \n", - "\n", - "except:\n", - " from fastlane_bot.tools import ConstantProductCurve as CPC, CurveContainer\n", - " from fastlane_bot.tools.curve import T, CPCInverter, Pair\n", - " from fastlane_bot.tools import MargPOptimizer, PairOptimizer\n", - " from fastlane_bot.tools.optimizer import CPCArbOptimizer, F\n", - " from fastlane_bot.tools.analyzer import CPCAnalyzer\n", - " from fastlane_bot.tools.testing import * \n", - "\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(Pair))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPCArbOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "\n", - "plt.style.use('seaborn-v0_8-dark')\n", - "plt.rcParams['figure.figsize'] = [12,6]" - ] - }, - { - "cell_type": "markdown", - "id": "4c19328a-c4b5-453e-9555-465ef6a34a60", - "metadata": {}, - "source": [ - "# Optimizer Testing Convergence Changes [NBTest013, ex 100]" - ] - }, - { - "cell_type": "markdown", - "id": "b970aaac-b29c-468d-a1af-5b094eea1398", - "metadata": {}, - "source": [ - "## THOR related Tests\n", - "\n", - "this test originates in the `Optimizer_2312_THOR` notebook" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "bb524ba1-5481-4a6d-b551-48f778b7e427", - "metadata": {}, - "outputs": [], - "source": [ - "curves_as_dicts = [{'k': 4.3078885616238194e+24,\n", - " 'x': 1250505254484.4102,\n", - " 'x_act': 0,\n", - " 'y_act': 344491.8061533139,\n", - " 'alpha': 0.5,\n", - " 'pair': 'USDC-eB48/THOR-8044',\n", - " 'cid': '74181555988764585035015664420125470098056-1',\n", - " 'fee': 2000.0,\n", - " 'descr': 'carbon_v1 THOR-8044/USDC-eB48 2000',\n", - " 'constr': 'carb',\n", - " 'params': {'exchange': 'carbon_v1',\n", - " 'tknx_dec': 18,\n", - " 'tkny_dec': 6,\n", - " 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044',\n", - " 'tkny_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n", - " 'blocklud': 18758319,\n", - " 'y': 344491.8061533139,\n", - " 'yint': 344491.8061533139,\n", - " 'A': 0,\n", - " 'B': 1.659765242784964,\n", - " 'pa': 2.754820936639097,\n", - " 'pb': 2.754820936639097}},\n", - " {'k': 1106096356.8039548,\n", - " 'x': 2619874.8519412754,\n", - " 'x_act': 2619874.8519412754,\n", - " 'y_act': 422.1943487049999,\n", - " 'alpha': 0.5,\n", - " 'pair': 'THOR-8044/WETH-6Cc2',\n", - " 'cid': '0xbf1875da0431343b56ec6295f706e257dbe85696e5270a5bdad005d37cc2fd9c',\n", - " 'fee': 0.003,\n", - " 'descr': 'sushiswap_v2 THOR-8044/WETH-6Cc2 0.003',\n", - " 'constr': 'uv2',\n", - " 'params': {'exchange': 'sushiswap_v2',\n", - " 'tknx_dec': 18,\n", - " 'tkny_dec': 18,\n", - " 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044',\n", - " 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n", - " 'blocklud': 18758340}},\n", - " {'k': 1233376864385.0625,\n", - " 'x': 54102579.539405,\n", - " 'x_act': 54102579.539405,\n", - " 'y_act': 22797.00662861641,\n", - " 'alpha': 0.5,\n", - " 'pair': 'USDC-eB48/WETH-6Cc2',\n", - " 'cid': '0x68bd2250b4b44996e193e9e001f74a5e5a31b31fbd0bb7df34c66eb8da7e6be2',\n", - " 'fee': 3000.0,\n", - " 'descr': 'uniswap_v2 USDC-eB48/WETH-6Cc2 0.003',\n", - " 'constr': 'uv2',\n", - " 'params': {'exchange': 'uniswap_v2',\n", - " 'tknx_dec': 6,\n", - " 'tkny_dec': 18,\n", - " 'tknx_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n", - " 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n", - " 'blocklud': 18758413}}]" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "45121819-184f-469c-a51d-6e25616591d8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(3, 3)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC = CurveContainer.from_dicts(curves_as_dicts)\n", - "len(CC), len(curves_as_dicts)" - ] - }, - { - "cell_type": "markdown", - "id": "0784424b-ba27-42fb-8c45-9b527b155ae2", - "metadata": {}, - "source": [ - "### CPC min range width functionality" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "52949438-148a-4581-b9c8-d44a7e4c8d0a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "ConstantProductCurve(k=400000399924037.75, x=2000000.4998099068, x_act=0, y_act=100, alpha=0.5, pair='WETH-6Cc2/USDC-eB48', cid='None', fee=None, descr=None, constr='carb', params={'y': 100, 'yint': 100, 'A': 0, 'B': 9.999997500001562, 'pa': 100, 'pb': 100, 'minrw': 1e-06})" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cdata = dict(y=100, yint=100, pa=100, pb=100, pair=\"WETH-6Cc2/USDC-eB48\", tkny=\"USDC-eB48\")\n", - "c = CPC.from_carbon(**cdata)\n", - "c2 = CPC.from_carbon(**cdata, minrw=1e-2)\n", - "c4 = CPC.from_carbon(**cdata, minrw=1e-4)\n", - "c6 = CPC.from_carbon(**cdata, minrw=1e-6)\n", - "c" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "78b7c8ab-9f65-4318-9dce-bdb1e68b0871", - "metadata": {}, - "outputs": [], - "source": [ - "assert c2.params.minrw==0.01\n", - "assert c4.params.minrw==0.0001\n", - "assert c6.params.minrw==0.000001\n", - "assert c.params.minrw==0.000001" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "44170a39-b0e6-4b08-867a-7e5960c9233a", - "metadata": {}, - "outputs": [], - "source": [ - "assert iseq(c2.p**2/100**2, 1.01)\n", - "assert iseq(c4.p**2/100**2, 1.0001)\n", - "assert iseq(c6.p**2/100**2, 1.000001)\n", - "assert iseq(c.p, c6.p)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "0cfdf148-064c-4f8c-8d1d-ca9aca61e117", - "metadata": {}, - "outputs": [], - "source": [ - "assert iseq(c2.p-100, 0.49875621120, eps=1e-3)\n", - "assert iseq(c4.p-100, 0.00499987500, eps=1e-3)\n", - "assert iseq(c6.p-100, 0.00004999875, eps=1e-3)\n", - "assert iseq((c2.p-100)/(c4.p-100), 99.75373596136635, eps=1e-4)\n", - "assert iseq((c4.p-100)/(c6.p-100), 99.99752507444194, eps=1e-4)" - ] - }, - { - "cell_type": "markdown", - "id": "0aa09514-2ee9-4208-8f6d-2165f357946e", - "metadata": {}, - "source": [ - "### margpoptimizer absolute convergence" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "bd50fc37-580f-480b-af91-a86670b25e54", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] targettkn = USDC-eB48\n", - "[margp_optimizer] calculating price estimates\n", - "[margp_optimizer] tknq=USDC-eB48, tknbs=('WETH-6Cc2',)\n", - "[margp_optimizer] error calculating price estimates: [('no price found for 1 pairs', {'WETH-6Cc2/USDC-eB48'}, array([[None]], dtype=object))]\n", - "[margp_optimizer] price estimates = None\n", - "[margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n" - ] - } - ], - "source": [ - "cdata = dict(y=100, yint=100, pa=100, pb=100, pair=\"WETH-6Cc2/USDC-eB48\", tkny=\"USDC-eB48\")\n", - "c = CPC.from_carbon(**cdata)\n", - "O = MargPOptimizer(CurveContainer([c,c]))\n", - "r = O.optimize(\"USDC-eB48\", params=dict(verbose=True, debug=True), result=O.MO_DEBUG)\n", - "assert r[\"crit\"][\"crit\"] == O.MO_MODE_REL\n", - "assert r[\"crit\"][\"epsr\"] == O.MO_EPSR\n", - "assert r[\"crit\"][\"epsa\"] == O.MO_EPSA\n", - "assert r[\"crit\"][\"epsaunit\"] == O.MO_EPSAUNIT\n", - "assert r[\"crit\"][\"pstart\"] is None" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "500a347a-8e9c-45ac-8b42-89312f8edf60", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "\"('no price found for 1 pairs', {'WETH-6Cc2/USDC-eB48'}, array([[None]], dtype=object))\"" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "raises(O.optimize, \"USDC-eB48\", params=dict(crit=\"meh\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "bc2ce9fb-7deb-4dc3-87d4-99a6284e9996", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'crit must be rel or abs'" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "raises(O.optimize, \"USDC-eB48\", mode=\"meh\", params=dict(), result=O.MO_DEBUG)\n", - "#raises(O.optimize, \"USDC-eB48\", mode=O.MO_MODE_ABS, params=dict(), result=O.MO_DEBUG)\n", - "#raises(O.optimize, \"USDC-eB48\", mode=O.MO_MODE_ABS, params=dict(), pstart=dict(FOO=1)))\n", - "#raises(O.optimize, \"USDC-eB48\", mode=O.MO_MODE_ABS, params=dict(), pstart={\"WETH-6Cc2\":2000, \"USDC-eB48\":1}))" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "432209be-590e-4838-9bd0-7493a57756c1", - "metadata": {}, - "outputs": [ - { - "ename": "AssertionError", - "evalue": "pstart must now be provided as argument pstart=..., not as parameter", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[11], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m r \u001b[38;5;241m=\u001b[39m O\u001b[38;5;241m.\u001b[39moptimize(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUSDC-eB48\u001b[39m\u001b[38;5;124m\"\u001b[39m, mode\u001b[38;5;241m=\u001b[39mO\u001b[38;5;241m.\u001b[39mMO_MODE_ABS, params\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(\n\u001b[1;32m 2\u001b[0m eps \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1e-10\u001b[39m,\n\u001b[1;32m 3\u001b[0m epsa \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m,\n\u001b[1;32m 4\u001b[0m epsaunit \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdollah\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 5\u001b[0m pstart \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdollah\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;241m1\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWETH-6Cc2\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m2000\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUSDC-eB48\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;241m1\u001b[39m},\n\u001b[1;32m 6\u001b[0m ), result\u001b[38;5;241m=\u001b[39mO\u001b[38;5;241m.\u001b[39mMO_DEBUG)\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m r[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcrit\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcrit\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m==\u001b[39m O\u001b[38;5;241m.\u001b[39mMO_MODE_ABS\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m r[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcrit\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mepsa\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m100\u001b[39m\n", - "File \u001b[0;32m~/REPOES/Bancor/FLBot/resources/NBTest/tools/optimizer/margpoptimizer.py:227\u001b[0m, in \u001b[0;36mMargPOptimizer.optimize\u001b[0;34m(self, sfc, pstart, mode, result, params)\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m P(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart must not be in params dict if pstart is provided as argument\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 226\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 227\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m P(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart must now be provided as argument pstart=..., not as parameter\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 228\u001b[0m pstart \u001b[38;5;241m=\u001b[39m P(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 229\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m P(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpstart\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", - "\u001b[0;31mAssertionError\u001b[0m: pstart must now be provided as argument pstart=..., not as parameter" - ] - } - ], - "source": [ - "r = O.optimize(\"USDC-eB48\", mode=O.MO_MODE_ABS, params=dict(\n", - " eps = 1e-10,\n", - " epsa = 100,\n", - " epsaunit = \"dollah\",\n", - " pstart = {\"dollah\":1, \"WETH-6Cc2\": 2000, \"USDC-eB48\":1},\n", - "), result=O.MO_DEBUG)\n", - "assert r[\"crit\"][\"crit\"] == O.MO_MODE_ABS\n", - "assert r[\"crit\"][\"epsa\"] == 100\n", - "assert r[\"crit\"][\"epsaunit\"] == \"dollah\"\n", - "assert r[\"crit\"][\"pstart\"] == {\"dollah\":1, \"WETH-6Cc2\": 2000, \"USDC-eB48\":1}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "843f54e3-2e56-4d00-bdb6-6b2d235aa21a", - "metadata": {}, - "outputs": [], - "source": [ - "1" - ] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/NBTEST_013_Convergence.py b/resources/NBTest/NBTEST_013_Convergence.py deleted file mode 100644 index f2b0d26eb..000000000 --- a/resources/NBTest/NBTEST_013_Convergence.py +++ /dev/null @@ -1,168 +0,0 @@ -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -try: - from tools import ConstantProductCurve as CPC, CurveContainer - from tools.curves import T, CPCInverter, Pair - from tools import MargPOptimizer, PairOptimizer - from tools.optimizer import CPCArbOptimizer, F - from tools.analyzer import CPCAnalyzer - from tools.testing import * - - - -except: - from fastlane_bot.tools import ConstantProductCurve as CPC, CurveContainer - from fastlane_bot.tools.curve import T, CPCInverter, Pair - from fastlane_bot.tools import MargPOptimizer, PairOptimizer - from fastlane_bot.tools.optimizer import CPCArbOptimizer, F - from fastlane_bot.tools.analyzer import CPCAnalyzer - from fastlane_bot.tools.testing import * - - -import numpy as np -import matplotlib.pyplot as plt - -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(Pair)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPCArbOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(PairOptimizer)) - -plt.style.use('seaborn-v0_8-dark') -plt.rcParams['figure.figsize'] = [12,6] -# - - -# # Optimizer Testing Convergence Changes [NBTest013, ex 100] - -# ## THOR related Tests -# -# this test originates in the `Optimizer_2312_THOR` notebook - -curves_as_dicts = [{'k': 4.3078885616238194e+24, - 'x': 1250505254484.4102, - 'x_act': 0, - 'y_act': 344491.8061533139, - 'alpha': 0.5, - 'pair': 'USDC-eB48/THOR-8044', - 'cid': '74181555988764585035015664420125470098056-1', - 'fee': 2000.0, - 'descr': 'carbon_v1 THOR-8044/USDC-eB48 2000', - 'constr': 'carb', - 'params': {'exchange': 'carbon_v1', - 'tknx_dec': 18, - 'tkny_dec': 6, - 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044', - 'tkny_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - 'blocklud': 18758319, - 'y': 344491.8061533139, - 'yint': 344491.8061533139, - 'A': 0, - 'B': 1.659765242784964, - 'pa': 2.754820936639097, - 'pb': 2.754820936639097}}, - {'k': 1106096356.8039548, - 'x': 2619874.8519412754, - 'x_act': 2619874.8519412754, - 'y_act': 422.1943487049999, - 'alpha': 0.5, - 'pair': 'THOR-8044/WETH-6Cc2', - 'cid': '0xbf1875da0431343b56ec6295f706e257dbe85696e5270a5bdad005d37cc2fd9c', - 'fee': 0.003, - 'descr': 'sushiswap_v2 THOR-8044/WETH-6Cc2 0.003', - 'constr': 'uv2', - 'params': {'exchange': 'sushiswap_v2', - 'tknx_dec': 18, - 'tkny_dec': 18, - 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044', - 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - 'blocklud': 18758340}}, - {'k': 1233376864385.0625, - 'x': 54102579.539405, - 'x_act': 54102579.539405, - 'y_act': 22797.00662861641, - 'alpha': 0.5, - 'pair': 'USDC-eB48/WETH-6Cc2', - 'cid': '0x68bd2250b4b44996e193e9e001f74a5e5a31b31fbd0bb7df34c66eb8da7e6be2', - 'fee': 3000.0, - 'descr': 'uniswap_v2 USDC-eB48/WETH-6Cc2 0.003', - 'constr': 'uv2', - 'params': {'exchange': 'uniswap_v2', - 'tknx_dec': 6, - 'tkny_dec': 18, - 'tknx_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - 'blocklud': 18758413}}] - -CC = CurveContainer.from_dicts(curves_as_dicts) -len(CC), len(curves_as_dicts) - -# ### CPC min range width functionality - -cdata = dict(y=100, yint=100, pa=100, pb=100, pair="WETH-6Cc2/USDC-eB48", tkny="USDC-eB48") -c = CPC.from_carbon(**cdata) -c2 = CPC.from_carbon(**cdata, minrw=1e-2) -c4 = CPC.from_carbon(**cdata, minrw=1e-4) -c6 = CPC.from_carbon(**cdata, minrw=1e-6) -c - -assert c2.params.minrw==0.01 -assert c4.params.minrw==0.0001 -assert c6.params.minrw==0.000001 -assert c.params.minrw==0.000001 - -assert iseq(c2.p**2/100**2, 1.01) -assert iseq(c4.p**2/100**2, 1.0001) -assert iseq(c6.p**2/100**2, 1.000001) -assert iseq(c.p, c6.p) - -assert iseq(c2.p-100, 0.49875621120, eps=1e-3) -assert iseq(c4.p-100, 0.00499987500, eps=1e-3) -assert iseq(c6.p-100, 0.00004999875, eps=1e-3) -assert iseq((c2.p-100)/(c4.p-100), 99.75373596136635, eps=1e-4) -assert iseq((c4.p-100)/(c6.p-100), 99.99752507444194, eps=1e-4) - -# ### margpoptimizer absolute convergence - -cdata = dict(y=100, yint=100, pa=100, pb=100, pair="WETH-6Cc2/USDC-eB48", tkny="USDC-eB48") -c = CPC.from_carbon(**cdata) -O = MargPOptimizer(CurveContainer([c,c])) -r = O.optimize("USDC-eB48", params=dict(verbose=True, debug=True), result=O.MO_DEBUG) -assert r["crit"]["crit"] == O.MO_MODE_REL -assert r["crit"]["epsr"] == O.MO_EPSR -assert r["crit"]["epsa"] == O.MO_EPSA -assert r["crit"]["epsaunit"] == O.MO_EPSAUNIT -assert r["crit"]["pstart"] is None - -raises(O.optimize, "USDC-eB48", params=dict(crit="meh")) - -raises(O.optimize, "USDC-eB48", mode="meh", params=dict(), result=O.MO_DEBUG) -#raises(O.optimize, "USDC-eB48", mode=O.MO_MODE_ABS, params=dict(), result=O.MO_DEBUG) -#raises(O.optimize, "USDC-eB48", mode=O.MO_MODE_ABS, params=dict(), pstart=dict(FOO=1))) -#raises(O.optimize, "USDC-eB48", mode=O.MO_MODE_ABS, params=dict(), pstart={"WETH-6Cc2":2000, "USDC-eB48":1})) - -r = O.optimize("USDC-eB48", mode=O.MO_MODE_ABS, params=dict( - eps = 1e-10, - epsa = 100, - epsaunit = "dollah", - pstart = {"dollah":1, "WETH-6Cc2": 2000, "USDC-eB48":1}, -), result=O.MO_DEBUG) -assert r["crit"]["crit"] == O.MO_MODE_ABS -assert r["crit"]["epsa"] == 100 -assert r["crit"]["epsaunit"] == "dollah" -assert r["crit"]["pstart"] == {"dollah":1, "WETH-6Cc2": 2000, "USDC-eB48":1} - -1 diff --git a/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.ipynb b/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.ipynb deleted file mode 100644 index 594e33ae1..000000000 --- a/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.ipynb +++ /dev/null @@ -1,476 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cc40bc23-abde-4094-abec-419f0a7fa81e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require, Timer\n", - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "CurveContainer v4.0-beta1 (04/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n", - "PairOptimizer v6.0.2 (03/May/2024)\n" - ] - } - ], - "source": [ - "try:\n", - " from tools import ConstantProductCurve as CPC, CurveContainer\n", - " from tools import MargPOptimizer, PairOptimizer\n", - " from tools.testing import *\n", - " \n", - "except:\n", - " from fastlane_bot.tools import ConstantProductCurve as CPC, CurveContainer\n", - " from fastlane_bot.tools import MargPOptimizer, PairOptimizer\n", - " from fastlane_bot.tools.testing import *\n", - "\n", - "\n", - "ConstantProductCurve = CPC\n", - "\n", - "from io import StringIO\n", - "\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveContainer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "\n", - "#plt.style.use('seaborn-dark')\n", - "#plt.rcParams['figure.figsize'] = [12,6]\n", - "# from fastlane_bot import __VERSION__\n", - "# require(\"3.0\", __VERSION__)" - ] - }, - { - "cell_type": "markdown", - "id": "b3f59f14-b91b-4dba-94b0-3d513aaf41c7", - "metadata": {}, - "source": [ - "# CPC and Optimizer New Features [NBTest011, ex 101]" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d5b9c0a7-2697-417c-bdcc-b19084db6552", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "Curves = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='LINK/USDP', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - " ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='USDP/LINK', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n", - " ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='LINK/ETH', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}),\n", - " ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='ETH/LINK', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}),\n", - " ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='ETH/USDP', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}),\n", - " ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='USDP/ETH', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352}),\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "4bd5baac-72c1-4f3b-8b99-b9de147bf32d", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CC1 = CurveContainer(Curves[0:1])\n", - "CC2 = CurveContainer(Curves[0:2])\n", - "CC6 = CurveContainer(Curves)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "be5cb7bb-9227-4083-9c55-d0a259076c3f", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "O1 = MargPOptimizer(CC1)\n", - "O2 = MargPOptimizer(CC2)\n", - "O6 = MargPOptimizer(CC6)" - ] - }, - { - "cell_type": "markdown", - "id": "5d33fbc5-bf2f-45e0-8b50-b7bdef16f0ad", - "metadata": {}, - "source": [ - "## CPCArbOptimizer Dump Curves [NOTEST]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "2b0023d2-0a75-4a6c-aeb9-c74ce7d4d97b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "O = O6" - ] - }, - { - "cell_type": "markdown", - "id": "78244239-11d4-4cd7-9d86-0587ff979a9d", - "metadata": {}, - "source": [ - "### Dump as json\n", - "\n", - "dumps the dict representation as json" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e8a17f53-966b-407c-b997-62febffdda57", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[{\"k\": 27518385.40998667, \"x\": 1272.2926367501436, \"x_act\": 0, \"y_act\": 2000.9999995236503, \"alpha\": 0.5, \"pair\": \"LINK/USDP\", \"cid\": \"0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0\", \"fee\": 2000, \"descr\": \"carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000\", \"constr\": \"carb\", \"params\": {\"exchange\": \"carbon_v1\", \"y\": 2000.9999995236503, \"yint\": 2000.9999995236503, \"A\": 0.38144823884371704, \"B\": 3.7416573867739373, \"pa\": 16.99999999999995, \"pb\": 13.99999999999997}}, {\"k\": 6.160500599566333e+18, \"x\": 11099999985.149971, \"x_act\": 0, \"y_act\": 55.50000002646446, \"alpha\": 0.5, \"pair\": \"USDP/LINK\", \"cid\": \"0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1\", \"fee\": 2000, \"descr\": \"carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000\", \"constr\": \"carb\", \"params\": {\"exchange\": \"carbon_v1\", \"y\": 55.50000002646446, \"yint\": 55.50000002646446, \"A\": 0, \"B\": 0.22360678656963742, \"pa\": 0.04999999999999889, \"pb\": 0.04999999999999889}}]\n" - ] - } - ], - "source": [ - "O2.dump_curves(O.DC_JSON)" - ] - }, - { - "cell_type": "markdown", - "id": "b2368443-0531-4330-8ca9-afed099dd838", - "metadata": {}, - "source": [ - "### Dump as dicts\n", - "\n", - "similar to json dumping, except that the result is a Python representation of dicts that can be directly run as Python code" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "7c37f971-628d-4225-8702-9aaa3705252f", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[{'k': 27518385.40998667, 'x': 1272.2926367501436, 'x_act': 0, 'y_act': 2000.9999995236503, 'alpha': 0.5, 'pair': 'LINK/USDP', 'cid': '0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', 'fee': 2000, 'descr': 'carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', 'constr': 'carb', 'params': {'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}}, {'k': 6.160500599566333e+18, 'x': 11099999985.149971, 'x_act': 0, 'y_act': 55.50000002646446, 'alpha': 0.5, 'pair': 'USDP/LINK', 'cid': '0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', 'fee': 2000, 'descr': 'carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', 'constr': 'carb', 'params': {'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}}]\n" - ] - } - ], - "source": [ - "O2.dump_curves(O.DC_DICTS)" - ] - }, - { - "cell_type": "markdown", - "id": "a9e5cf16-e71b-4fc4-b282-39e3b83158d9", - "metadata": {}, - "source": [ - "### Dump as data frame\n", - "\n", - "dumps as Pandas data frame" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "6730aad0-48ff-4263-87f6-5dcdf4e2768a", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#O1.dump_curves(O.DC_DF)" - ] - }, - { - "cell_type": "markdown", - "id": "131ee279-7a81-4109-80e7-6daff4e5c6ae", - "metadata": {}, - "source": [ - "### Dump as constructor\n", - "\n", - "dumps as CPC constructors (one per line; every line ends with comma, including last)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "389e8e8b-a6e4-4181-81f9-2d090f23ccbc", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='LINK/USDP', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - "ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='USDP/LINK', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n" - ] - } - ], - "source": [ - "O2.dump_curves(O.DC_CONSTR)" - ] - }, - { - "cell_type": "markdown", - "id": "c9ad1ac8-f7d6-4126-af25-88a7c8de146b", - "metadata": {}, - "source": [ - "### Dump into StringIO to capture output\n", - "\n", - "A StringIO object (or any other open file object for that matter) can be passed via the `dest` parameter. The value can then be extracted using `getvalue()`, or as generally for file using `seek(0)` and `read()`" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "fe4dde42-6d4b-43e6-a7b2-444a078f9cbc", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(6,\n", - " \"ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='LINK/USDP', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\")" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = StringIO()\n", - "O6.dump_curves(O.DC_CONSTR, dest=out)\n", - "outl = out.getvalue().splitlines()\n", - "len(outl), outl[0]" - ] - }, - { - "cell_type": "markdown", - "id": "61c1f220-2d54-4141-9de7-edf75ba94d7e", - "metadata": {}, - "source": [ - "## CPCArbOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "ff884fc5-7a11-468e-b26b-61ea962ff005", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "O = O6" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "bfc298e7-171a-49ee-807c-24b0f6d357c6", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "out1 = StringIO()\n", - "O.dump_curves(O.DC_JSON, dest=out1)\n", - "r = out1.getvalue()\n", - "assert r.startswith('[{\"k\": 27518385.40998667, \"x\": 1272.2926367501436,')\n", - "#r" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "aabf93e5-694f-458c-ba98-d0f29c36f07c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "out1 = StringIO()\n", - "O.dump_curves(O.DC_DICTS, dest=out1)\n", - "r = out1.getvalue()\n", - "assert r.startswith(\"[{'k': 27518385.40998667, 'x': 1272.2926367501436,\")\n", - "#r" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "b58446c1-e879-4212-ab42-c986b385b589", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "out1 = StringIO()\n", - "O.dump_curves(O.DC_CONSTR, dest=out1)\n", - "rl = out1.getvalue().splitlines()\n", - "assert len(rl) == len(O.curves)\n", - "assert rl[0].startswith(\"ConstantProductCurve(k=27518385\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "ae0e958d-a073-4a5a-b26a-453092b2487d", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "\"ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='LINK/USDP', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\"" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rl[0]" - ] - }, - { - "cell_type": "markdown", - "id": "50300414-4720-4e37-9e75-442a3270c9e8", - "metadata": {}, - "source": [ - "## CPCArbOptimizer bugfix\n", - "https://github.com/bancorprotocol/fastlane-bot/pull/614" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "4b361860-2a78-4313-b46c-dba0c7f6dc8c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "curves = [CPC.from_pk(p, 100) for p in range(20,30)]\n", - "O = MargPOptimizer(curves)\n", - "assert isinstance(O.curves, CurveContainer)" - ] - }, - { - "cell_type": "markdown", - "id": "c7d786d6-e57a-4f37-95f7-f8153720f88b", - "metadata": {}, - "source": [ - "## MargPOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "4e44296a-1b7f-4a26-bc00-31e680007c84", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "pass" - ] - }, - { - "cell_type": "markdown", - "id": "fe9ceba0-b63c-44da-98ba-ffd105d7a915", - "metadata": { - "tags": [] - }, - "source": [ - "## CPC" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "37248169-fbfb-4e86-85fb-b5135329ea42", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "pass" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "298e4f31-24d1-4ff5-b9c4-8238ee272589", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1" - ] - } - ], - "metadata": { - "jupytext": { - "encoding": "# -*- coding: utf-8 -*-", - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.py b/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.py deleted file mode 100644 index 1c1798c4e..000000000 --- a/resources/NBTest/NBTest_011_CPCOptimizerNewFeatures.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- coding: utf-8 -*- -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -try: - from tools import ConstantProductCurve as CPC, CurveContainer - from tools import MargPOptimizer, PairOptimizer - from tools.testing import * - -except: - from fastlane_bot.tools import ConstantProductCurve as CPC, CurveContainer - from fastlane_bot.tools import MargPOptimizer, PairOptimizer - from fastlane_bot.tools.testing import * - - -ConstantProductCurve = CPC - -from io import StringIO - -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CurveContainer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(PairOptimizer)) - -#plt.style.use('seaborn-dark') -#plt.rcParams['figure.figsize'] = [12,6] -# from fastlane_bot import __VERSION__ -# require("3.0", __VERSION__) -# - - -# # CPC and Optimizer New Features [NBTest011, ex 101] - -Curves = [ - ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='LINK/USDP', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}), - ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='USDP/LINK', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}), - ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='LINK/ETH', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}), - ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='ETH/LINK', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}), - ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='ETH/USDP', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}), - ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='USDP/ETH', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352}), -] - -CC1 = CurveContainer(Curves[0:1]) -CC2 = CurveContainer(Curves[0:2]) -CC6 = CurveContainer(Curves) - -O1 = MargPOptimizer(CC1) -O2 = MargPOptimizer(CC2) -O6 = MargPOptimizer(CC6) - -# ## CPCArbOptimizer Dump Curves [NOTEST] - -O = O6 - -# ### Dump as json -# -# dumps the dict representation as json - -O2.dump_curves(O.DC_JSON) - -# ### Dump as dicts -# -# similar to json dumping, except that the result is a Python representation of dicts that can be directly run as Python code - -O2.dump_curves(O.DC_DICTS) - -# ### Dump as data frame -# -# dumps as Pandas data frame - -# + -#O1.dump_curves(O.DC_DF) -# - - -# ### Dump as constructor -# -# dumps as CPC constructors (one per line; every line ends with comma, including last) - -O2.dump_curves(O.DC_CONSTR) - -# ### Dump into StringIO to capture output -# -# A StringIO object (or any other open file object for that matter) can be passed via the `dest` parameter. The value can then be extracted using `getvalue()`, or as generally for file using `seek(0)` and `read()` - -out = StringIO() -O6.dump_curves(O.DC_CONSTR, dest=out) -outl = out.getvalue().splitlines() -len(outl), outl[0] - -# ## CPCArbOptimizer - -O = O6 - -out1 = StringIO() -O.dump_curves(O.DC_JSON, dest=out1) -r = out1.getvalue() -assert r.startswith('[{"k": 27518385.40998667, "x": 1272.2926367501436,') -#r - -out1 = StringIO() -O.dump_curves(O.DC_DICTS, dest=out1) -r = out1.getvalue() -assert r.startswith("[{'k': 27518385.40998667, 'x': 1272.2926367501436,") -#r - -out1 = StringIO() -O.dump_curves(O.DC_CONSTR, dest=out1) -rl = out1.getvalue().splitlines() -assert len(rl) == len(O.curves) -assert rl[0].startswith("ConstantProductCurve(k=27518385") - -rl[0] - -# ## CPCArbOptimizer bugfix -# https://github.com/bancorprotocol/fastlane-bot/pull/614 - -curves = [CPC.from_pk(p, 100) for p in range(20,30)] -O = MargPOptimizer(curves) -assert isinstance(O.curves, CurveContainer) - -# ## MargPOptimizer - -pass - -# ## CPC - -pass - -1 diff --git a/resources/NBTest/NBTest_012_APIBasics.ipynb b/resources/NBTest/NBTest_012_APIBasics.ipynb deleted file mode 100644 index 2a325a95d..000000000 --- a/resources/NBTest/NBTest_012_APIBasics.ipynb +++ /dev/null @@ -1,1408 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cc40bc23-abde-4094-abec-419f0a7fa81e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require, Timer\n", - "CurveBase v1.0 (23/Jan/2024)\n", - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "CurveContainer v4.0-beta1 (04/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n" - ] - } - ], - "source": [ - "try:\n", - " from tools import CurveBase, ConstantProductCurve as CPC, CurveContainer\n", - " from tools import MargPOptimizer\n", - " from tools.testing import *\n", - "\n", - "except:\n", - " from fastlane_bot.tools.curves import CurveBase, ConstantProductCurve as CPC, CurveContainer\n", - " from fastlane_bot.tools.optimizer import MargPOptimizer\n", - " from fastlane_bot.testing import *\n", - "\n", - "ConstantProductCurve = CPC\n", - "\n", - "#from io import StringIO\n", - "import types\n", - "import math as m\n", - "\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveBase))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveContainer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))\n", - "\n", - "#plt.style.use('seaborn-dark')\n", - "#plt.rcParams['figure.figsize'] = [12,6]\n", - "# from fastlane_bot import __VERSION__\n", - "# require(\"3.0\", __VERSION__)" - ] - }, - { - "cell_type": "markdown", - "id": "b3f59f14-b91b-4dba-94b0-3d513aaf41c7", - "metadata": {}, - "source": [ - "# API Basics [NBTest012, ex 102]\n", - "\n", - "This notebook describes API features of the Optimizer library. Everything contained in this notebook's tests here should be considered stable, and breaking changes will only ever happen a major version number increases" - ] - }, - { - "cell_type": "markdown", - "id": "3971ba2d-7ba3-4bff-a54e-82a94152232d", - "metadata": {}, - "source": [ - "## CurveBase ConstantProductCurve CPC CurveContainer\n", - "\n", - "The `CurveBase` object is the base class of all curve objects fed into the optimizer. Currently only the `ConstantProductCurve` object -- typically imported as `CPC` -- is providing an actual implementation for that class, and it can only describe (or approximate) constant product curves." - ] - }, - { - "cell_type": "markdown", - "id": "e56487dc-5dd5-451a-9e4b-268b60f44d85", - "metadata": {}, - "source": [ - "### CurveBase" - ] - }, - { - "cell_type": "markdown", - "id": "22493f6c-e961-4d3d-99c5-a37a410ec897", - "metadata": {}, - "source": [ - "assert that certain functions exist on `CurveBase`" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "51ac566e-7e52-4ce4-a889-e7885558f044", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "assert isinstance(CurveBase.dxvecfrompvec_f, types.FunctionType)\n", - "assert isinstance(CurveBase.xvecfrompvec_f, types.FunctionType)\n", - "assert isinstance(CurveBase.invariant, types.FunctionType)" - ] - }, - { - "cell_type": "markdown", - "id": "8b7a58c8-711b-48ea-9f67-4c11f4f283ca", - "metadata": {}, - "source": [ - "assert that CurveBase cannot be instantiated with one of the functions missing" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "260e9ab0-9fa1-481f-948c-cf7ab21db31e", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "assert raises(CurveBase)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "03c4a6d1-265f-4b87-b426-c5f9a3b6033c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "class Curve(CurveBase):\n", - " def dxvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " ...\n", - " def xvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " ...\n", - " # def invariant(self, include_target=False): \n", - " # ...\n", - "assert raises(Curve)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "dedf5019-6797-458f-b34a-418d4fb78490", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "class Curve(CurveBase):\n", - " def dxvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " ...\n", - " # def xvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " # ...\n", - " def invariant(self, include_target=False): \n", - " ...\n", - "assert raises(Curve)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "f57dc72c-1ea4-441c-93b5-a011b53e0431", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "class Curve(CurveBase):\n", - " # def dxvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " # ...\n", - " def xvecfrompvec_f(self, pvec, *, ignorebounds=False):\n", - " ...\n", - " def invariant(self, include_target=False): \n", - " ...\n", - "assert raises(Curve)" - ] - }, - { - "cell_type": "markdown", - "id": "51e22e2a-68cb-460e-9fb2-01ac5cb280dc", - "metadata": {}, - "source": [ - "### ConstantProductCurve" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "70d2d955-0a8f-4d2e-bb54-1bfb39f378bd", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "p = dict(foo=1, bar=2, baz=3)\n", - "kwargs = dict(pair=\"TKNB/TKNQ\", cid=\"c_cid\", descr=\"des\", fee=0.005, params=p)" - ] - }, - { - "cell_type": "markdown", - "id": "70a9e00f-6475-427b-ba55-c734f690cc35", - "metadata": {}, - "source": [ - "#### unlevered generic constructors" - ] - }, - { - "cell_type": "markdown", - "id": "a49272ce-ebe2-478d-9d74-85cf45fa8b0a", - "metadata": { - "tags": [] - }, - "source": [ - "the `from_pk` constructor takes a price `p` and a constant `k`" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "41200a28-3176-4aa8-9c00-1a0b6e37320d", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = CPC.from_pk(10, 10*1*25**2, **kwargs)\n", - "assert raises(CPC.from_pk, 10, 10*1*10**2, 10)\n", - "assert iseq(c.p, 10)\n", - "assert iseq(c.x, 25)\n", - "assert iseq(c.x, c.x_act)\n", - "assert iseq(c.y, 250)\n", - "assert iseq(c.y, c.y_act)\n", - "assert iseq(c.k, 6250)\n", - "assert c.pair == \"TKNB/TKNQ\"\n", - "assert c.cid == \"c_cid\"\n", - "assert c.descr == \"des\"\n", - "assert c.fee == 0.005\n", - "assert c.params == p" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "92452ee0-38a9-4bc5-9f09-580914637481", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'ConstantProductCurve.from_pk() takes 3 positional arguments but 4 were given'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "raises(CPC.from_pk, 10, 10*1*10**2, 10)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "477b3601-4b16-47f3-bffe-0c094cd8579b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_kx(c.k, c.x, **kwargs)\n", - "assert CPC.from_kx(k=c.k, x=c.x, **kwargs) == c1\n", - "assert raises(CPC.from_kx, 10, 10*1*10**2, 10)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)\n", - "assert c1.pair == c1.pair\n", - "assert c1.cid == c1.cid\n", - "assert c1.descr == c1.descr\n", - "assert c.fee == c1.fee\n", - "assert c1.params == c1.params" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "1fe29598-0cd0-46bb-a8bf-6e568001a653", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_ky(c.k, c.y, **kwargs)\n", - "assert CPC.from_ky(k=c.k, y=c.y, **kwargs) == c1\n", - "assert raises(CPC.from_ky, 10, 10*1*10**2, 10)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)\n", - "assert c1.pair == c1.pair\n", - "assert c1.cid == c1.cid\n", - "assert c1.descr == c1.descr\n", - "assert c.fee == c1.fee\n", - "assert c1.params == c1.params" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "cc1a3920-6b6d-4c30-a034-175f3f977b79", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_xy(c.x, c.y, **kwargs)\n", - "assert CPC.from_xy(x=c.x, y=c.y, **kwargs) == c1\n", - "assert raises(CPC.from_xy, 10, 10*1*10**2, 10)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)\n", - "assert c1.pair == c1.pair\n", - "assert c1.cid == c1.cid\n", - "assert c1.descr == c1.descr\n", - "assert c.fee == c1.fee\n", - "assert c1.params == c1.params" - ] - }, - { - "cell_type": "markdown", - "id": "38c3130c-3e93-4c9d-b568-652c52abc232", - "metadata": { - "tags": [] - }, - "source": [ - "#### levered generic constructors" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "424fdcc2-d764-4d3e-9d8a-5870af35cd64", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = CPC.from_pkpp(10, 10*1*25**2, 8, 12, **kwargs)\n", - "assert raises(CPC.from_pkpp, 10, 10*1*10**2, 8, 12, 10)\n", - "assert iseq(c.p, 10)\n", - "assert iseq(c.p_min, 8)\n", - "assert iseq(c.p_max, 12)\n", - "assert iseq(c.x, 25)\n", - "assert iseq(c.x_act, 2.1782267706180782)\n", - "assert iseq(c.y, 250)\n", - "assert iseq(c.y_act, 26.393202250021034)\n", - "assert iseq(c.k, 6250)\n", - "assert c.pair == \"TKNB/TKNQ\"\n", - "assert c.cid == \"c_cid\"\n", - "assert c.descr == \"des\"\n", - "assert c.fee == c1.fee\n", - "assert c.params == p" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "ab6f7df7-f8f8-422a-9664-5ca57617ff2c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_kx(c.k, c.x, x_act=c.x_act, y_act = c.y_act, **kwargs)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "5c773ae9-c968-4f1b-9816-935a1ba55883", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_ky(c.k, c.y, x_act=c.x_act, y_act = c.y_act, **kwargs)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "a289614e-5f97-4bd4-8609-f9e069c89e1e", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_xy(c.x, c.y, x_act=c.x_act, y_act = c.y_act, **kwargs)\n", - "assert iseq(c1.p, c.p)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.x_act, c.x_act)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.y_act, c.y_act)\n", - "assert iseq(c1.k, c.k)" - ] - }, - { - "cell_type": "markdown", - "id": "4fcfaef5-66ee-4e66-8bd1-f53e0a5bd6a5", - "metadata": {}, - "source": [ - "#### Carbon constructor\n", - "\n", - "note: the Carbon constructor takes _only_ keyword arguments" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "971e0f98-03b0-4fb9-9ca7-9f329d1df81f", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "assert raises(CPC.from_carbon, 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "6170a94f-a0ad-4292-b8ce-eb7941cdbafc", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "pa, pb = 12, 8 # USDC per LINK\n", - "yint = y = 25 # LINK" - ] - }, - { - "cell_type": "markdown", - "id": "7b3071cb-cd87-403d-a4ba-c927e651710e", - "metadata": {}, - "source": [ - "with prices, `tkny` is the quote token (USDC)\n", - "\n", - "_note: isdydx does not matter because dy per dx is same as tknq per tknb_" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "ae8a9711-0988-477d-91fa-c6f912ba3f39", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = CPC.from_carbon(pair=\"LINK/USDC\", tkny=\"USDC\", yint=yint, y=y, pa=pa, pb=pb, isdydx=False)\n", - "c2 = CPC.from_carbon(pair=\"LINK/USDC\", tkny=\"USDC\", yint=yint, y=y, pa=pa, pb=pb, isdydx=True)\n", - "assert c.pair == \"LINK/USDC\"\n", - "assert c2 == c\n", - "assert iseq(c.p_max, pa)\n", - "assert iseq(c.p_min, pb)\n", - "assert iseq(c.p, c.p_max)\n", - "assert iseq(c.x_act, 0)\n", - "assert iseq(c.y_act, yint)\n", - "assert iseq(c.x, 11.353103630798294)\n", - "assert iseq(c.y, 136.23724356957953)\n", - "assert iseq(c.y/c.x, pa)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "44ebc661-00ca-4e31-af33-532d36bf8685", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "dx, dy, p_ = c.dxdyfromp_f(p=c.p_min)\n", - "dxvec = c.dxvecfrompvec_f(pvec=dict(LINK=p_, USDC=1))\n", - "assert iseq(dx, yint/m.sqrt(pa*pb))\n", - "assert iseq(dy, -yint)\n", - "assert iseq(p_, c.p_min)\n", - "assert iseq(dxvec[\"USDC\"], dy)\n", - "assert iseq(dxvec[\"LINK\"], dx)" - ] - }, - { - "cell_type": "markdown", - "id": "39f30da0-8182-43ba-a88f-4f970afabe18", - "metadata": { - "tags": [] - }, - "source": [ - "same, but with A,B (A = sqrt(pa)-sqrt(pb), B = sqrt(pb), pa > pb in dy/dx)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "46b265c3-d9d3-4185-ba95-48279e6a3ac3", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "A = m.sqrt(pa)-m.sqrt(pb)\n", - "B = m.sqrt(pb)\n", - "c1 = CPC.from_carbon(pair=\"LINK/USDC\", tkny=\"LINK\", yint=yint, y=y, A=A, B=B)\n", - "assert iseq(c1.p_max, c.p_max)\n", - "assert iseq(c1.p_min, c.p_min)\n", - "assert iseq(c1.p, c.p)" - ] - }, - { - "cell_type": "markdown", - "id": "dfe32f7b-1097-46f0-9b8a-d93bfef8c685", - "metadata": {}, - "source": [ - "with prices, `tkny` is the base token (LINK)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "7d906756-caf5-47bb-b2b3-2e94e2f0a1fb", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.125, 0.08333333333333333, 200.0)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pa_ = 1/pb\n", - "pb_ = 1/pa\n", - "yint_ = y_ = yint / pa_\n", - "pa_, pb_, yint_" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "abec0ce8-601a-4958-9c05-11e441a9c956", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = CPC.from_carbon(pair=\"LINK/USDC\", tkny=\"LINK\", yint=yint_, y=y_, pa=pa_, pb=pb_, isdydx=True)\n", - "c2 = CPC.from_carbon(pair=\"LINK/USDC\", tkny=\"LINK\", yint=yint_, y=y_, pa=pb, pb=pa, isdydx=False)\n", - "assert c.pair == \"USDC/LINK\"\n", - "assert c2.pair == c.pair \n", - "assert iseq(c.p_max, pa_)\n", - "assert iseq(c2.p_max, c.p_max)\n", - "assert iseq(c.p_min, pb_)\n", - "assert iseq(c2.p_min, c.p_min)\n", - "assert iseq(c.p, c.p_max)\n", - "assert iseq(c2.p, c2.p_max)\n", - "assert iseq(c.x_act, 0)\n", - "assert iseq(c2.x_act, c.x_act)\n", - "assert iseq(c.y_act, yint_)\n", - "assert iseq(c2.y_act, c.y_act)\n", - "assert iseq(c.x, 8719.18358845308)\n", - "assert iseq(c2.x, c.x)\n", - "assert iseq(c.y, 1089.897948556635)\n", - "assert iseq(c2.y, c.y)\n", - "assert iseq(c.y/c.x, pa_)\n", - "assert iseq(c2.y/c2.x, pa_)" - ] - }, - { - "cell_type": "markdown", - "id": "a28239aa-b503-4e0a-bfcb-3180738e92d6", - "metadata": {}, - "source": [ - "#### Uniswap v2 constructor" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "f53cc512-f528-42d0-99d4-c7cede82c785", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "kwargs = dict(pair=\"LINK/USDC\", descr=\"des\", cid=\"cid\", fee=0.005, params=p)" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "b45b2201-ab52-4f5e-b484-1a9fd32e262e", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = CPC.from_univ2(liq_tknb=10, liq_tknq=20, **kwargs)\n", - "assert iseq(c.x, 10)\n", - "assert iseq(c.y, 20)\n", - "assert iseq(c.k, c.x*c.y)\n", - "assert c.pair == kwargs[\"pair\"]\n", - "assert c.descr == kwargs[\"descr\"]\n", - "assert c.cid == kwargs[\"cid\"]\n", - "assert c.fee == kwargs[\"fee\"]\n", - "assert c.params == kwargs[\"params\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "33f9d7f4-e50e-4be2-90fb-181aaa9d43cf", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c1 = CPC.from_univ2(liq_tknb=c.x, k=c.k, **kwargs)\n", - "assert iseq(c1.x, c.x)\n", - "assert iseq(c1.y, c.y)\n", - "assert iseq(c1.k, c.k)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "303d06fc-d9ee-438e-8e22-0aa13d450c76", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c2 = CPC.from_univ2(liq_tknq=c.y, k=c.k, **kwargs)\n", - "assert iseq(c2.x, c.x)\n", - "assert iseq(c2.y, c.y)\n", - "assert iseq(c2.k, c.k)" - ] - }, - { - "cell_type": "markdown", - "id": "c40daefb-9348-4fe7-9708-85188d05a33b", - "metadata": {}, - "source": [ - "#### Uniswap v3 constructor" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "5595ed0d-c56d-47af-bebe-b68180365ddd", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# TODO" - ] - }, - { - "cell_type": "markdown", - "id": "966de7fd-130a-4c35-b665-833f4a833173", - "metadata": {}, - "source": [ - "### CurveContainer\n", - "\n", - "A `CurveContainer` (legacy name: `CPCContainer`) is a container object for curve objects (`CurveBase` derivatives)" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "b1d38195-171c-4363-9477-b9ed8735b6e5", - "metadata": {}, - "outputs": [], - "source": [ - "# TODO" - ] - }, - { - "cell_type": "markdown", - "id": "61c1f220-2d54-4141-9de7-edf75ba94d7e", - "metadata": {}, - "source": [ - "## MargPOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "03765e57-a600-4dfe-9b5a-bdffa9693f41", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CC = CurveContainer([\n", - " CPC.from_pk(pair=\"LINK/USDC\", p=10, k = 10*250_000**2, cid=\"c10\"),\n", - " CPC.from_pk(pair=\"LINK/USDC\", p=12, k = 10*250_000**2, cid=\"c12\"),\n", - "])\n", - "pstart = dict(LINK=10.3, USDC=1)" - ] - }, - { - "cell_type": "markdown", - "id": "9403f6d4-01fe-4f9f-b82e-80fecd6c628b", - "metadata": {}, - "source": [ - "### Running the optimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "76bc7020-7552-49e1-bcd1-8487c8114557", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-10868.538042440545, time=0.0005507469177246094, method='margp', targettkn='USDC', p_optimal_t=(10.931723975202656,), dtokens_t=(-2.9103830456733704e-11,), tokens_t=('LINK',), errormsg=None)" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(\"USDC\")\n", - "assert not r.is_error\n", - "assert r.errormsg is None\n", - "assert iseq(r.result, -10868.538042440545)\n", - "assert iseq(r.p_optimal_t[0], 10.931723975214778)\n", - "assert r.method == 'margp'\n", - "assert r.targettkn == \"USDC\"\n", - "assert r.time > 0\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "c7c74040-e8ef-4401-80d7-9cfea30a99e2", - "metadata": {}, - "source": [ - "#### pstart" - ] - }, - { - "cell_type": "markdown", - "id": "93a5fa01-e5bc-43e2-9b97-a658ecf5fa5c", - "metadata": {}, - "source": [ - "pstart must be a kwarg if provided" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "0defc16c-8434-4e53-93ce-e13d4d01567e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'MargPOptimizer.optimize() takes from 1 to 2 positional arguments but 3 were given'" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "assert raises(O.optimize, \"USDC\", pstart)\n", - "assert not raises(O.optimize, \"USDC\")\n", - "assert not raises(O.optimize, \"USDC\", pstart=pstart)\n", - "raises(O.optimize, \"USDC\", pstart)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "e9c30b78-c170-4a44-9dab-8bb1b464f3bf", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-10868.5380395432, time=0.0002989768981933594, method='margp', targettkn='USDC', p_optimal_t=(10.931723975214778,), dtokens_t=(-2.651067916303873e-07,), tokens_t=('LINK',), errormsg=None)" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r1 = O.optimize(\"USDC\", pstart=pstart)\n", - "assert iseq(r.result, r1.result, eps=1e-3)\n", - "assert iseq(r.p_optimal_t[0], r1.p_optimal_t[0], eps=1e-3)\n", - "r1" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "75dbb028-5e30-4cae-b7b5-3c5dcf1184b8", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'pstart must not be in params dict if pstart is provided as argument'" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "assert raises(O.optimize, \"USDC\", pstart=pstart, params=dict(pstart=pstart))\n", - "raises(O.optimize, \"USDC\", pstart=pstart, params=dict(pstart=pstart))" - ] - }, - { - "cell_type": "markdown", - "id": "c7c7f638-8dea-4625-b950-ac986b37fd77", - "metadata": {}, - "source": [ - "### Trade instructions" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "bd25a42e-f325-43b3-a7aa-c04cfdb14103", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(\"USDC\")\n", - "assert len(r.trade_instructions()) == 2\n", - "assert r.trade_instructions() == r.trade_instructions(O.TIF_OBJECTS) " - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "e99d026a-9ed6-4157-8557-7c171a5f7d46", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(CPCArbOptimizer.TradeInstruction(cid='c10', tknin='USDC', amtin=113872.12474169489, tknout='LINK', amtout=-10891.133853090403, error=None),\n", - " CPCArbOptimizer.TradeInstruction(cid='c12', tknin='LINK', amtin=10891.133853090374, tknout='USDC', amtout=-124740.66278413543, error=None))" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ti = r.trade_instructions(O.TIF_OBJECTS)\n", - "assert len(ti) == 2\n", - "assert isinstance(ti[0], O.TradeInstruction)\n", - "assert set(tin.cid for tin in ti) == {\"c10\", \"c12\"}\n", - "assert set(tin.tknin for tin in ti) == {\"USDC\", \"LINK\"}\n", - "assert set(tin.tknout for tin in ti) == {\"USDC\", \"LINK\"}\n", - "ti" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "2c8dda8a-ce06-41af-854d-f2c51a550992", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "CPCArbOptimizer.TradeInstruction(cid='c10', tknin='USDC', amtin=113872.12474169489, tknout='LINK', amtout=-10891.133853090403, error=None)" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ti0 = [tin for tin in ti if tin.cid==\"c10\"][0]\n", - "assert ti0.cid == \"c10\"\n", - "assert ti0.tknin == \"USDC\"\n", - "assert iseq(ti0.amtin, 113872.12474169489)\n", - "assert ti0.tknout == \"LINK\"\n", - "assert iseq(ti0.amtout, -10891.133853090403)\n", - "assert ti0.error is None\n", - "ti0" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "f829f99e-acbb-4c62-b813-34923783178f", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pairpairptknintknoutUSDCLINK
cid
c10LINK/USDCLINK/USDCUSDCLINK113872.124742-10891.133853
c12LINK/USDCLINK/USDCLINKUSDC-124740.66278410891.133853
\n", - "
" - ], - "text/plain": [ - " pair pairp tknin tknout USDC LINK\n", - "cid \n", - "c10 LINK/USDC LINK/USDC USDC LINK 113872.124742 -10891.133853\n", - "c12 LINK/USDC LINK/USDC LINK USDC -124740.662784 10891.133853" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ti = r.trade_instructions(O.TIF_DFRAW)\n", - "assert len(ti) == 2\n", - "assert set(ti.index) == {'c10', 'c12'}\n", - "assert set(ti.pair) == {'LINK/USDC'}\n", - "assert set(ti.pairp) == {'LINK/USDC'}\n", - "assert set(ti.tknin) == {'LINK', 'USDC'}\n", - "assert set(ti.tknout) == {'LINK', 'USDC'}\n", - "ti" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "db5e270b-1d77-450a-bb9e-1331ca3ed208", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "pair LINK/USDC\n", - "pairp LINK/USDC\n", - "tknin USDC\n", - "tknout LINK\n", - "USDC 113872.124742\n", - "LINK -10891.133853\n", - "Name: c10, dtype: object" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ti0 = ti.loc[\"c10\"]\n", - "assert ti0[\"pair\"] == \"LINK/USDC\"\n", - "assert ti0[\"pairp\"] == \"LINK/USDC\"\n", - "assert ti0[\"tknin\"] == \"USDC\"\n", - "assert iseq(ti0[\"USDC\"], 113872.124742)\n", - "assert ti0[\"tknout\"] == \"LINK\"\n", - "assert iseq(ti0[\"LINK\"], -10891.133853)\n", - "ti0" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "c6e56e39-1cef-45c1-8cf2-91bcd86a4561", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pairpairptknintknoutUSDCLINK
cid
c10LINK/USDCLINK/USDCUSDCLINK113872.124742-10891.133853
c12LINK/USDCLINK/USDCLINKUSDC-124740.66278410891.133853
\n", - "
" - ], - "text/plain": [ - " pair pairp tknin tknout USDC LINK\n", - "cid \n", - "c10 LINK/USDC LINK/USDC USDC LINK 113872.124742 -10891.133853\n", - "c12 LINK/USDC LINK/USDC LINK USDC -124740.662784 10891.133853" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r.trade_instructions(O.TIF_DF8)" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "52212fd5-fe6d-4f05-b4cd-f5f8501b9666", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
USDCLINK
c10113872.124742-1.089113e+04
c12-124740.6627841.089113e+04
PRICE1.0000001.093172e+01
AMMIn113872.1247421.089113e+04
AMMOut-124740.662784-1.089113e+04
TOTAL NET-10868.538042-2.910383e-11
\n", - "
" - ], - "text/plain": [ - " USDC LINK\n", - "c10 113872.124742 -1.089113e+04\n", - "c12 -124740.662784 1.089113e+04\n", - "PRICE 1.000000 1.093172e+01\n", - "AMMIn 113872.124742 1.089113e+04\n", - "AMMOut -124740.662784 -1.089113e+04\n", - "TOTAL NET -10868.538042 -2.910383e-11" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r.trade_instructions(O.TIF_DFAGGR)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "18809816-75c7-4af0-820f-26d692234e0e", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
feepairamt_tknqtknqmargp0effpmargpgain_rgain_tknqgain_ttkn
exchcid
NaNc12NoneLINK/USDC-124740.662784USDC12.011.45341410.9317240.0477235952.9434535952.943453
c10NoneLINK/USDC113872.124742USDC10.010.45548810.9317240.0435654960.7862114960.786211
\n", - "
" - ], - "text/plain": [ - " fee pair amt_tknq tknq margp0 effp margp \\\n", - "exch cid \n", - "NaN c12 None LINK/USDC -124740.662784 USDC 12.0 11.453414 10.931724 \n", - " c10 None LINK/USDC 113872.124742 USDC 10.0 10.455488 10.931724 \n", - "\n", - " gain_r gain_tknq gain_ttkn \n", - "exch cid \n", - "NaN c12 0.047723 5952.943453 5952.943453 \n", - " c10 0.043565 4960.786211 4960.786211 " - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r.trade_instructions(O.TIF_DFPG)" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "5de61457-828c-48fc-a5dc-25fc2c2914e0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1" - ] - } - ], - "metadata": { - "jupytext": { - "encoding": "# -*- coding: utf-8 -*-", - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/NBTest_012_APIBasics.py b/resources/NBTest/NBTest_012_APIBasics.py deleted file mode 100644 index e19e58007..000000000 --- a/resources/NBTest/NBTest_012_APIBasics.py +++ /dev/null @@ -1,402 +0,0 @@ -# -*- coding: utf-8 -*- -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -try: - from tools import CurveBase, ConstantProductCurve as CPC, CurveContainer - from tools import MargPOptimizer - from tools.testing import * - -except: - from fastlane_bot.tools.curves import CurveBase, ConstantProductCurve as CPC, CurveContainer - from fastlane_bot.tools.optimizer import MargPOptimizer - from fastlane_bot.testing import * - -ConstantProductCurve = CPC - -#from io import StringIO -import types -import math as m - -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CurveBase)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CurveContainer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) - -#plt.style.use('seaborn-dark') -#plt.rcParams['figure.figsize'] = [12,6] -# from fastlane_bot import __VERSION__ -# require("3.0", __VERSION__) -# - - -# # API Basics [NBTest012, ex 102] -# -# This notebook describes API features of the Optimizer library. Everything contained in this notebook's tests here should be considered stable, and breaking changes will only ever happen a major version number increases - -# ## CurveBase ConstantProductCurve CPC CurveContainer -# -# The `CurveBase` object is the base class of all curve objects fed into the optimizer. Currently only the `ConstantProductCurve` object -- typically imported as `CPC` -- is providing an actual implementation for that class, and it can only describe (or approximate) constant product curves. - -# ### CurveBase - -# assert that certain functions exist on `CurveBase` - -assert isinstance(CurveBase.dxvecfrompvec_f, types.FunctionType) -assert isinstance(CurveBase.xvecfrompvec_f, types.FunctionType) -assert isinstance(CurveBase.invariant, types.FunctionType) - -# assert that CurveBase cannot be instantiated with one of the functions missing - -assert raises(CurveBase) - - -class Curve(CurveBase): - def dxvecfrompvec_f(self, pvec, *, ignorebounds=False): - ... - def xvecfrompvec_f(self, pvec, *, ignorebounds=False): - ... - # def invariant(self, include_target=False): - # ... -assert raises(Curve) - - -class Curve(CurveBase): - def dxvecfrompvec_f(self, pvec, *, ignorebounds=False): - ... - # def xvecfrompvec_f(self, pvec, *, ignorebounds=False): - # ... - def invariant(self, include_target=False): - ... -assert raises(Curve) - - -class Curve(CurveBase): - # def dxvecfrompvec_f(self, pvec, *, ignorebounds=False): - # ... - def xvecfrompvec_f(self, pvec, *, ignorebounds=False): - ... - def invariant(self, include_target=False): - ... -assert raises(Curve) - -# ### ConstantProductCurve - -p = dict(foo=1, bar=2, baz=3) -kwargs = dict(pair="TKNB/TKNQ", cid="c_cid", descr="des", fee=0.005, params=p) - -# #### unlevered generic constructors - -# the `from_pk` constructor takes a price `p` and a constant `k` - -c = CPC.from_pk(10, 10*1*25**2, **kwargs) -assert raises(CPC.from_pk, 10, 10*1*10**2, 10) -assert iseq(c.p, 10) -assert iseq(c.x, 25) -assert iseq(c.x, c.x_act) -assert iseq(c.y, 250) -assert iseq(c.y, c.y_act) -assert iseq(c.k, 6250) -assert c.pair == "TKNB/TKNQ" -assert c.cid == "c_cid" -assert c.descr == "des" -assert c.fee == 0.005 -assert c.params == p - -raises(CPC.from_pk, 10, 10*1*10**2, 10) - -c1 = CPC.from_kx(c.k, c.x, **kwargs) -assert CPC.from_kx(k=c.k, x=c.x, **kwargs) == c1 -assert raises(CPC.from_kx, 10, 10*1*10**2, 10) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) -assert c1.pair == c1.pair -assert c1.cid == c1.cid -assert c1.descr == c1.descr -assert c.fee == c1.fee -assert c1.params == c1.params - -c1 = CPC.from_ky(c.k, c.y, **kwargs) -assert CPC.from_ky(k=c.k, y=c.y, **kwargs) == c1 -assert raises(CPC.from_ky, 10, 10*1*10**2, 10) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) -assert c1.pair == c1.pair -assert c1.cid == c1.cid -assert c1.descr == c1.descr -assert c.fee == c1.fee -assert c1.params == c1.params - -c1 = CPC.from_xy(c.x, c.y, **kwargs) -assert CPC.from_xy(x=c.x, y=c.y, **kwargs) == c1 -assert raises(CPC.from_xy, 10, 10*1*10**2, 10) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) -assert c1.pair == c1.pair -assert c1.cid == c1.cid -assert c1.descr == c1.descr -assert c.fee == c1.fee -assert c1.params == c1.params - -# #### levered generic constructors - -c = CPC.from_pkpp(10, 10*1*25**2, 8, 12, **kwargs) -assert raises(CPC.from_pkpp, 10, 10*1*10**2, 8, 12, 10) -assert iseq(c.p, 10) -assert iseq(c.p_min, 8) -assert iseq(c.p_max, 12) -assert iseq(c.x, 25) -assert iseq(c.x_act, 2.1782267706180782) -assert iseq(c.y, 250) -assert iseq(c.y_act, 26.393202250021034) -assert iseq(c.k, 6250) -assert c.pair == "TKNB/TKNQ" -assert c.cid == "c_cid" -assert c.descr == "des" -assert c.fee == c1.fee -assert c.params == p - -c1 = CPC.from_kx(c.k, c.x, x_act=c.x_act, y_act = c.y_act, **kwargs) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) - -c1 = CPC.from_ky(c.k, c.y, x_act=c.x_act, y_act = c.y_act, **kwargs) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) - -c1 = CPC.from_xy(c.x, c.y, x_act=c.x_act, y_act = c.y_act, **kwargs) -assert iseq(c1.p, c.p) -assert iseq(c1.x, c.x) -assert iseq(c1.x_act, c.x_act) -assert iseq(c1.y, c.y) -assert iseq(c1.y_act, c.y_act) -assert iseq(c1.k, c.k) - -# #### Carbon constructor -# -# note: the Carbon constructor takes _only_ keyword arguments - -assert raises(CPC.from_carbon, 1) - -pa, pb = 12, 8 # USDC per LINK -yint = y = 25 # LINK - -# with prices, `tkny` is the quote token (USDC) -# -# _note: isdydx does not matter because dy per dx is same as tknq per tknb_ - -c = CPC.from_carbon(pair="LINK/USDC", tkny="USDC", yint=yint, y=y, pa=pa, pb=pb, isdydx=False) -c2 = CPC.from_carbon(pair="LINK/USDC", tkny="USDC", yint=yint, y=y, pa=pa, pb=pb, isdydx=True) -assert c.pair == "LINK/USDC" -assert c2 == c -assert iseq(c.p_max, pa) -assert iseq(c.p_min, pb) -assert iseq(c.p, c.p_max) -assert iseq(c.x_act, 0) -assert iseq(c.y_act, yint) -assert iseq(c.x, 11.353103630798294) -assert iseq(c.y, 136.23724356957953) -assert iseq(c.y/c.x, pa) - -dx, dy, p_ = c.dxdyfromp_f(p=c.p_min) -dxvec = c.dxvecfrompvec_f(pvec=dict(LINK=p_, USDC=1)) -assert iseq(dx, yint/m.sqrt(pa*pb)) -assert iseq(dy, -yint) -assert iseq(p_, c.p_min) -assert iseq(dxvec["USDC"], dy) -assert iseq(dxvec["LINK"], dx) - -# same, but with A,B (A = sqrt(pa)-sqrt(pb), B = sqrt(pb), pa > pb in dy/dx) - -A = m.sqrt(pa)-m.sqrt(pb) -B = m.sqrt(pb) -c1 = CPC.from_carbon(pair="LINK/USDC", tkny="LINK", yint=yint, y=y, A=A, B=B) -assert iseq(c1.p_max, c.p_max) -assert iseq(c1.p_min, c.p_min) -assert iseq(c1.p, c.p) - -# with prices, `tkny` is the base token (LINK) - -pa_ = 1/pb -pb_ = 1/pa -yint_ = y_ = yint / pa_ -pa_, pb_, yint_ - -c = CPC.from_carbon(pair="LINK/USDC", tkny="LINK", yint=yint_, y=y_, pa=pa_, pb=pb_, isdydx=True) -c2 = CPC.from_carbon(pair="LINK/USDC", tkny="LINK", yint=yint_, y=y_, pa=pb, pb=pa, isdydx=False) -assert c.pair == "USDC/LINK" -assert c2.pair == c.pair -assert iseq(c.p_max, pa_) -assert iseq(c2.p_max, c.p_max) -assert iseq(c.p_min, pb_) -assert iseq(c2.p_min, c.p_min) -assert iseq(c.p, c.p_max) -assert iseq(c2.p, c2.p_max) -assert iseq(c.x_act, 0) -assert iseq(c2.x_act, c.x_act) -assert iseq(c.y_act, yint_) -assert iseq(c2.y_act, c.y_act) -assert iseq(c.x, 8719.18358845308) -assert iseq(c2.x, c.x) -assert iseq(c.y, 1089.897948556635) -assert iseq(c2.y, c.y) -assert iseq(c.y/c.x, pa_) -assert iseq(c2.y/c2.x, pa_) - -# #### Uniswap v2 constructor - -kwargs = dict(pair="LINK/USDC", descr="des", cid="cid", fee=0.005, params=p) - -c = CPC.from_univ2(liq_tknb=10, liq_tknq=20, **kwargs) -assert iseq(c.x, 10) -assert iseq(c.y, 20) -assert iseq(c.k, c.x*c.y) -assert c.pair == kwargs["pair"] -assert c.descr == kwargs["descr"] -assert c.cid == kwargs["cid"] -assert c.fee == kwargs["fee"] -assert c.params == kwargs["params"] - -c1 = CPC.from_univ2(liq_tknb=c.x, k=c.k, **kwargs) -assert iseq(c1.x, c.x) -assert iseq(c1.y, c.y) -assert iseq(c1.k, c.k) - -c2 = CPC.from_univ2(liq_tknq=c.y, k=c.k, **kwargs) -assert iseq(c2.x, c.x) -assert iseq(c2.y, c.y) -assert iseq(c2.k, c.k) - -# #### Uniswap v3 constructor - -# + -# TODO -# - - -# ### CurveContainer -# -# A `CurveContainer` (legacy name: `CPCContainer`) is a container object for curve objects (`CurveBase` derivatives) - -# + -# TODO -# - - -# ## MargPOptimizer - -CC = CurveContainer([ - CPC.from_pk(pair="LINK/USDC", p=10, k = 10*250_000**2, cid="c10"), - CPC.from_pk(pair="LINK/USDC", p=12, k = 10*250_000**2, cid="c12"), -]) -pstart = dict(LINK=10.3, USDC=1) - -# ### Running the optimizer - -O = MargPOptimizer(CC) -r = O.optimize("USDC") -assert not r.is_error -assert r.errormsg is None -assert iseq(r.result, -10868.538042440545) -assert iseq(r.p_optimal_t[0], 10.931723975214778) -assert r.method == 'margp' -assert r.targettkn == "USDC" -assert r.time > 0 -r - -# #### pstart - -# pstart must be a kwarg if provided - -assert raises(O.optimize, "USDC", pstart) -assert not raises(O.optimize, "USDC") -assert not raises(O.optimize, "USDC", pstart=pstart) -raises(O.optimize, "USDC", pstart) - -r1 = O.optimize("USDC", pstart=pstart) -assert iseq(r.result, r1.result, eps=1e-3) -assert iseq(r.p_optimal_t[0], r1.p_optimal_t[0], eps=1e-3) -r1 - -assert raises(O.optimize, "USDC", pstart=pstart, params=dict(pstart=pstart)) -raises(O.optimize, "USDC", pstart=pstart, params=dict(pstart=pstart)) - -# ### Trade instructions - -O = MargPOptimizer(CC) -r = O.optimize("USDC") -assert len(r.trade_instructions()) == 2 -assert r.trade_instructions() == r.trade_instructions(O.TIF_OBJECTS) - -ti = r.trade_instructions(O.TIF_OBJECTS) -assert len(ti) == 2 -assert isinstance(ti[0], O.TradeInstruction) -assert set(tin.cid for tin in ti) == {"c10", "c12"} -assert set(tin.tknin for tin in ti) == {"USDC", "LINK"} -assert set(tin.tknout for tin in ti) == {"USDC", "LINK"} -ti - -ti0 = [tin for tin in ti if tin.cid=="c10"][0] -assert ti0.cid == "c10" -assert ti0.tknin == "USDC" -assert iseq(ti0.amtin, 113872.12474169489) -assert ti0.tknout == "LINK" -assert iseq(ti0.amtout, -10891.133853090403) -assert ti0.error is None -ti0 - -ti = r.trade_instructions(O.TIF_DFRAW) -assert len(ti) == 2 -assert set(ti.index) == {'c10', 'c12'} -assert set(ti.pair) == {'LINK/USDC'} -assert set(ti.pairp) == {'LINK/USDC'} -assert set(ti.tknin) == {'LINK', 'USDC'} -assert set(ti.tknout) == {'LINK', 'USDC'} -ti - -ti0 = ti.loc["c10"] -assert ti0["pair"] == "LINK/USDC" -assert ti0["pairp"] == "LINK/USDC" -assert ti0["tknin"] == "USDC" -assert iseq(ti0["USDC"], 113872.124742) -assert ti0["tknout"] == "LINK" -assert iseq(ti0["LINK"], -10891.133853) -ti0 - -r.trade_instructions(O.TIF_DF8) - -r.trade_instructions(O.TIF_DFAGGR) - -r.trade_instructions(O.TIF_DFPG) - -1 diff --git a/resources/NBTest/Optimizer_2312_THOR.ipynb b/resources/NBTest/Optimizer_2312_THOR.ipynb deleted file mode 100644 index 7fa8d2551..000000000 --- a/resources/NBTest/Optimizer_2312_THOR.ipynb +++ /dev/null @@ -1,1140 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "dce7f14d-b45a-40fb-9caa-cc82a4ec28be", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n" - ] - } - ], - "source": [ - "from tools.curves import ConstantProductCurve as CPC, CurveContainer, T, CPCInverter, Pair\n", - "from tools.optimizer import CPCArbOptimizer, F, MargPOptimizer, PairOptimizer\n", - "from tools.analyzer import CPCAnalyzer\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(Pair))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPCArbOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "\n", - "plt.style.use('seaborn-v0_8-dark')\n", - "plt.rcParams['figure.figsize'] = [12,6]" - ] - }, - { - "cell_type": "markdown", - "id": "4c19328a-c4b5-453e-9555-465ef6a34a60", - "metadata": {}, - "source": [ - "# Optimizer Testing (Thor, Dec 2023)\n", - "_202312a-THOR-8044 Triangle_\n", - "\n", - "**IMPORTANT NOTE** \n", - "\n", - "For the above imports to work, you must create a symlink to the `tools` module here, running\n", - "\n", - " ln -s ../../fastlane_bot/tools tools\n", - " \n", - "Don't forget to add a local `.gitignore` file in this case!" - ] - }, - { - "cell_type": "markdown", - "id": "84978bf3-85d1-4455-adc8-0d894b425139", - "metadata": {}, - "source": [ - "## Reading input data\n", - "\n", - "Set `curves_as_dicts` to the output of `CPCContainer.as_dicts`. The use `CPCContainer.from_dicts` to recreate a container." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "bb524ba1-5481-4a6d-b551-48f778b7e427", - "metadata": {}, - "outputs": [], - "source": [ - "curves_as_dicts = [{'k': 4.3078885616238194e+24,\n", - " 'x': 1250505254484.4102,\n", - " 'x_act': 0,\n", - " 'y_act': 344491.8061533139,\n", - " 'alpha': 0.5,\n", - " 'pair': 'USDC-eB48/THOR-8044',\n", - " 'cid': '74181555988764585035015664420125470098056-1',\n", - " 'fee': 2000.0,\n", - " 'descr': 'carbon_v1 THOR-8044/USDC-eB48 2000',\n", - " 'constr': 'carb',\n", - " 'params': {'exchange': 'carbon_v1',\n", - " 'tknx_dec': 18,\n", - " 'tkny_dec': 6,\n", - " 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044',\n", - " 'tkny_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n", - " 'blocklud': 18758319,\n", - " 'y': 344491.8061533139,\n", - " 'yint': 344491.8061533139,\n", - " 'A': 0,\n", - " 'B': 1.659765242784964,\n", - " 'pa': 2.754820936639097,\n", - " 'pb': 2.754820936639097}},\n", - " {'k': 1106096356.8039548,\n", - " 'x': 2619874.8519412754,\n", - " 'x_act': 2619874.8519412754,\n", - " 'y_act': 422.1943487049999,\n", - " 'alpha': 0.5,\n", - " 'pair': 'THOR-8044/WETH-6Cc2',\n", - " 'cid': '0xbf1875da0431343b56ec6295f706e257dbe85696e5270a5bdad005d37cc2fd9c',\n", - " 'fee': 0.003,\n", - " 'descr': 'sushiswap_v2 THOR-8044/WETH-6Cc2 0.003',\n", - " 'constr': 'uv2',\n", - " 'params': {'exchange': 'sushiswap_v2',\n", - " 'tknx_dec': 18,\n", - " 'tkny_dec': 18,\n", - " 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044',\n", - " 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n", - " 'blocklud': 18758340}},\n", - " {'k': 1233376864385.0625,\n", - " 'x': 54102579.539405,\n", - " 'x_act': 54102579.539405,\n", - " 'y_act': 22797.00662861641,\n", - " 'alpha': 0.5,\n", - " 'pair': 'USDC-eB48/WETH-6Cc2',\n", - " 'cid': '0x68bd2250b4b44996e193e9e001f74a5e5a31b31fbd0bb7df34c66eb8da7e6be2',\n", - " 'fee': 3000.0,\n", - " 'descr': 'uniswap_v2 USDC-eB48/WETH-6Cc2 0.003',\n", - " 'constr': 'uv2',\n", - " 'params': {'exchange': 'uniswap_v2',\n", - " 'tknx_dec': 6,\n", - " 'tkny_dec': 18,\n", - " 'tknx_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n", - " 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n", - " 'blocklud': 18758413}}]" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "45121819-184f-469c-a51d-6e25616591d8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(3, 3)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC = CurveContainer.from_dicts(curves_as_dicts)\n", - "len(CC), len(curves_as_dicts)" - ] - }, - { - "cell_type": "markdown", - "id": "ede152d2-ae66-4536-8a54-5c97133b45f1", - "metadata": {}, - "source": [ - "## Analyzis and visualization\n", - "\n", - "Note: THOR-8044 ~ 30c" - ] - }, - { - "cell_type": "markdown", - "id": "b013b9d7-8db6-43f4-93e3-8a88e5b42b3b", - "metadata": {}, - "source": [ - "### Visualization" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "9a3825f0-d915-4b69-be6a-def70078e3e0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = USDC/THOR\n" - ] - }, - { - "data": { - "image/png": "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Ln9hWZXPPvtMxx57rL+gbt++vX788Uft2rWrwuXXrFmjs88+W8uWLZNUWlCfffbZQb3Xgbrgggv03Xff6d9//93nMu+++67q1asXcC/uvUVHR+vRRx9VYWGhRo4cGdQEZgAAhFvEFNSLFy/WkCFDNGjQoHLPffbZZ+rRo4dat26tLl266K233gp4vlu3btq1a1e567FM05RhGBo4cKCSk5PlcDh0yy23KD09XVu2bDmUmwMAiABt27bVtm3b9O2335Z77r333pPX69UZZ5yh1NRU2Ww2LVy4UCUlJeWW/eOPPxQVFeW/lrgyH374ob799tuAY9a1114ru92uRx55pNzQ76KiIk2ePFmJiYk6//zzlZ+fr40bN+rcc88NYYv3X+/evRUXF6cRI0ZUuO0LFy7UF198oTvuuEMWS+WnHaeeeqquvPJKbdy4UYsXLz5UIQMAcNBEzDXU7du316WXXiqbzRZQVP/888/q06ePnnzySXXo0EHffPON+vbtq+TkZP+v8/Pnz1daWpqmTJmiTZs2+dc1DEPTpk0LeJ8VK1YoJiZGjRo1qp4NAwDUWJdccoleeOEF3Xbbbbrjjjt0yimnyOfzacOGDZo9e7a6dOmiVq1aSZIefPBB9evXT1dccYWuvfZaHXfccSoqKtKnn36qBQsWaODAgUpMTPS/tsvl0tdffy2p9Afe3NxcrV+/XvPmzVO7du103XXX+Zc96qij9OCDD2rUqFG69tprddVVV6levXraunWr5s6dqz///FOzZs1STEyMVq5cqbS0tGo7jtWpU0eTJk3SgAED9H//93+6/vrr1bhxY+Xk5Gj58uVatmyZrr322qAnGbv77ru1fPlyPfXUU+rYsaPi4+MP8RYAABC6iCmoa9euXWH7yy+/rA4dOqhTp06SpFatWunKK6/UggUL/AV1WlpaUO+xevVqPfLII3rwwQcP6LozAMDhwW6368UXX9Qzzzyj1157TZMnT5bFYtGxxx6rQYMGBRS95513nl599VU999xzeuaZZ5SZmSmHw6GmTZvq6aef9h+nyuzatUu9evWSVPoDb3Jyso4++mgNHTpUPXv2lN1uD1i+e/fuOvbYY/XCCy9o4sSJysjIUO3atdWyZUtNmjRJxx9/vCTp448/PqDbZYXijDPO0JIlSzR37lzNmTNH//77rxISEnTqqadq1qxZ+zX8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WlrAullZWbrzzps0bNh9atWqtb99/PjHtGzZW7LZdn9U+vcfpG7d/k+SdO21PbR9+7+yWHb/NjNr1jw1bNhImZkZuuyyixQdHe1/LjExSYsWvS1J+vPPLZo0abx+/PF7xcTEqlu3/1Pv3jf5X+u9997V88/P0q5du1SrVoquuuoaXX55D0mSz+fTrFkztGLFMhUWFujYYxupT5+71LLl6dq+fbt69+4ZsH1er08uV4meeWaOmjU7Tbm5OZo06SmtXfupfD6fWrZspUcffUQWS3TAevva55Vtd1X7fPXqlXr44fvlcDj8655zznm6//4xkqQffvheEyc+qS1b/lBSUrJuuOFmde16uSSppKRE06dP0gcfrFZRUZEaNWqsO+7op9NPbyNJVe7zrKxMPfHEWG3c+JWsVqs6dbpE/foNDMivJH3//bcaMOBOvf/+ZwHtlW23z+fTCy88p7ffXqK8vDw1bNhIAwcOVrNmp0lShft88OARSk1NDWqfl/nyy881ePAAvfLKEtWrV1+SlJOTralTJ+rLLz9XSUmJTjyxifr3v1snnHDSAW+3aZp64YXntGzZW8rJyVG9evV044236vzzLwxqn5fxer0aOLCP6tWrr1GjHpQkPfnko1q5cnnAciUlJWrduq0mTJgqSVq+fKnmzp2tjIx0HXtsIw0adK9/n3q9Xj3zzFStWLFMxcXFOv301hoyZKR/nx7I31hV713Vdgeb74pMnDheBQX5/v10qP377zb17HmZXnvtLf9nqqap6Du6S5cOKigoULNmpwV87x8q//67TVOmPK1vv90o0zR12mktdNdd96h+/QYVLl/V5ysYXq9X998/XMcdd7xuueWOgOfWrftcr7/+ih5//OmQt6nM2rWfaMaMKdq27R/VrZumvn0H6qyzzq5yvZkzp2vlyuXl/t735Z133tacOTODXn5fKvqerOr4UNn3xcqVy/3nIoZhyDTNcucioR6TparPRao6Lv7++2+aMmWCfvzxBzmdTnXqdLH69BlQ7ju8ovOgqo5Nv/32q6ZNm6hffvlZdrtdbdq001133aOkpCRJ0uuvv6rXXntJGRnpSklJVc+eV+mKK3oFtd1l9vU5ruo7urJ872nP42L9+ruPi1OmTNQXX6yVy+XSSScFHhfL7Ov8b+3aTzRz5nT9/fffql+/gW6++Xade+75kqo+Lm7f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+1z16nWN//Wq2u49bd78h6699gb/Y5vNpqOOOlq///4rBTWqzWE1KZlhGJp1VXN9POCsoP/Nuqri3uVgX2fWVc0PypASn8+nuXOf0/XX36yYmFh/e1ZWph599CGNHv2IYmJiKly3sl/vfD6fLrvs/7Rs2Wq99dZKNWzYUKNHj/A/n5KSWu4apDIFBflq2fJ09ehxlRYvfkejRz+sRYte0csvvyipdH+ffHJTDRt2n5YsWaFeva7RffcN1ffffydJiouLV/PmLTVlyky9+uqbOvroYzVoUD/l5+fr1FObKyrKqWeemari4mJt3/6vXnppniTJ5SqR2+1SvXr19fTT07R69ad64omJmjPnWa1b97kkyeNxq2XL07Vw4SKtXPmRrr32et133zBlZAT2gM2bN0dnnHGWmjU71d+Wm5ujTZt+099/b9Xzzy/Q888v1K5dOzVs2LCg9nlV213ZPs/OztKJJ56k887roAULFmnGjDn6+++tGjPmfkmlvXR7H8RKexsCf9m++OIu+uCDtRo16kE9/PD9/12nVPk+L31tZ7nXluR//co+S5Vtd25ujiRp0aKX9eijT+qNN5bppJNO1j333KX8/Px97vNHHnkgqH2+ceNXWrlyuYYOrfxkU5LWrPlIEyc+qXvuGSan03nA272nrVv/1L33DlSnTp39wwor2+dlvQe9el2jE044cZ+vu23bP3r33Xd05539Ator+zwUFhYEbMvezx/o31hVn8XKtruqfFfEZrMFdX11mRUrlumcc87X//7XXhaLRWeccaZmzHhOtWvX0aWXdtekSTOUkpKi9PR0lZSUKCYmVrt27fSvf8YZZ6p27TqKj989Z0b//ncrKSnpv57YO7Vq1Qr5fD4tW/aWzj77PHXo0FE2m00nndRE1113o9588w3/ui1btlabNmfIZrOpa9du8nq9FV5Gs7fmzVuqbt00fy/ne++9q2OPPVYnnVR6wl7Zd3QounS5TK1atZbdbtf119+s6Ohoffpp5YV0RZYsWfTf0NlRFT5f1eerKjExsf5ewIp8/HHgcG/DMDR48DDFxMTq6KOP0TXXXK93330nqPcqLCwMmAtA0n/fHUUVLj9v3hzFxcXq8suvCOr19+Z2uzV06D3KzMzUuHFP7XN01d6COR+QKj4+VPV9Ucbn82nGjBm64YbAc5EDPSYfyHExNzdH77zztk4++RS98cYyjR37pN588w29/PICf3z7+g6v6ti0J9M0NXPmdH366RoNHDgk4Ln69Y/S6tWfavbseVq9eqVefHFuUNtd2ee4qu/og3lc/OSTwOOiVPl3yznnnKcvv/xcH364Wh6PR99++7VWr16pkpKScstWdFwsM3z4fVq58mNdcMGFuuuuO/zHRYcjSoMGDdWqVWs0b94r2rx5s5577llJwX/OyxQV7evvt/zIFuBQOawKaqn0oBpttwb9z2kr3QVlJXHZf502S1DrH6zrMzZsWK+MjHR17drN31Y2BLxHj15q0qTyIaUVychI19ixD+qaa3orISFBycnJGjx4uL75ZqM2bfq9yvXbtDlDkyc/o5YtT5fNZlPTps105ZVXa/XqVZKka665Xo888oSOPvoY2e12derUWa1bt9WHH66WJD344Fj16zdQSUlJiomJ1V13DVJhYaG++Waj4uPjNX78JP344/f6v//rovvvH66LL+4iqfRE/bnnSnuU27RpJ5vNpjPPbK8LL7xIb775uqTSYZJnnHGmjjmmoaKinLrxxlsVFxcXMPSusLBQ7733brlhl3Z7aW/ugAGDFRMTq1q1UnTHHX310UcfqaCgoMp9Xtl2V7XPa9VK0bRps9S1azc5nU6lpaWpb98B+vzzz1RYWCCnM1olJcUB71dcXFzuoBIVFSWbzaYLL7xIp5/eRu+//16V+3xfry0p4MRpXyrb7rIe8ptuuk1pafUUFeXUHXf0U0FBgb777usK9/ntt/fV2rWfqrCw8n2elZX13zXuY/zDbytimqamT5+uhx66TyNGjPZfg3ug213mk08+1h133KRzzjlfw4ff72+vbJ/Pn/+8HA6HevSofOjvsmVv6dRTm5ebLKayz0NZsbuv5w/0b6yqz2Jl2115vgs1ePAAdex4tv9fVVauXB6w/MqVy5Wenl7u8oOTTz5FcXFxKi4u0pNPPqrOnS/QPff00/LlS2Wapn94oaQKr3stm8xHkurWTZPL5VJOTo6ysjLLTbxVr159bd/+r/9xSkqK///LTlL3vqZxX7p2vVwrVpQWf++887Z/EsJD4eijj/b/v2EYql27jjIy0vXNN1/r4ovPq/DfypUr/Ou43W499dTjmjlzhp58cpLatGlX4ftU9fk6UB9//JF/iLYkJSQk+HurpdL8lRU1Q4feXeF23XBD6d9l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4sVq3bq1LrzwQtlsNl1yySVq06aNXnnllTBEjjL7k8MdO3botttuU4sWLWQYhlq2bKl27drpyy+/DEPkKLM/OSzz0EMP6cILL6zGKLEv+5O/hQsXqkOHDurevbsMw1CTJk308ssv6/TTTw9D5CizPzn8448/ZJqm/5/VapXdbpfNVu1368ReFi9erCFDhmjQoEFVLsf5TM0TbP44l6m5gs1hGc5laj4K6iD89ttvSkpKUt26df1txx13nLZt26bc3NyAZX///XedeOKJAW3HH3+8fv7552qJFRXbnxxee+21uv322/2PMzIy9OWXX6pZs2bVFi/K258cStKSJUv0559/qn///tUZJvZhf/L37bff6qijjtI999yjdu3aqXPnzlq3bp1q165d3WFjD/uTwy5duig1NVWXXHKJTjnlFA0cOFDjxo1TWlpadYeNvbRv316rVq3SJZdcUulynM/UTMHmj3OZmivYHEqcy0QKCuogFBQUKDo6OqCt7HFhYWGVyzqdznLLoXrtTw73tGvXLt12221q1qyZunbtekhjROX2J4ebNm3S008/raeeeqrGz89wpNif/OXk5GjevHm67LLL9Omnn+rhhx/W448/rhUrVlRbvChvf3LodrvVpEkTvfbaa/r666/18MMPa9SoUfrll1+qLV5UrHbt2kGNFOB8pmYKNn974lymZgk2h5zLRA4K6iDExMSoqKgooK3scWxsbEB7dHS0iouLA9qKi4vLLYfqtT85LPP111+rR48eatSokWbMmMFQxTALNoclJSUaNGiQRo4cqfr161drjNi3/fkbdDgc6tChg8477zzZbDa1adNG3bp10/Lly6stXpS3PzkcM2aMTjjhBJ122mlyOBy64oor1KJFCy1evLja4sWB4Xzm8MC5TGTiXCayUFAH4YQTTlB2drbS09P9bZs2bVJaWpri4+MDlj3xxBP122+/BbT9/vvvOuGEE6olVlRsf3IoSYsWLdKNN96oG264QU899ZQcDkd1hosKBJvD7777Tlu2bNGoUaPUunVrtW7dWpJ055136sEHH6zusPGf/fkbPO644+RyuQLavF6vzOq/yyP2sD853LZtW7kc2mw22e32aokVB47zmcjHuUzk4lwmwoR3TrTIcfXVV5uDBg0y8/Ly/DObTp48udxyv//+u3nqqaeay5Yt88+Keeqpp5p//PFHGKLGnoLN4YoVK8xTTjnF/Pjjj8MQJSoTbA73xsyYNUOw+fvss8/Mpk2bmkuWLDF9Pp+5bt06s0WLFuZ7770Xhqixp2Bz+PTTT5vt2rUzv//+e9Pr9ZrLly83Tz31VPPHH38MQ9TYl8q+Gzmfqfkqyx/nMpFhf85POJepueihDtLkyZPl8XjUoUMHXXnllTr77LPVt29fSVLLli311ltvSSrtWZk2bZqeffZZtWnTRtOnT9eUKVPUqFGjcIYPBZ/DqVOnyuv1asCAAWrZsqX/3+jRo8MZPhR8DlEzBZu///3vf5o+fbrmzZun008/XSNGjNCwYcPUoUOHcIYPBZ/D/v3769prr9Vdd92lNm3aaObMmZo2bZpOPvnkcIaPKnA+E9k4l4l8nMtEJsM0GUMHAAAAAMD+oocaAAAAAIAQUFADAAAAABACCmoAAAAAAEJAQQ0AAAAAQAgoqAEAAAAACAEFNQAAAAAAIaCgBgAAAADUeJmZmerYsaO++OKL/V73+eefV+/evQPasrKyNHz4cJ111llq06aNbrjhBv3000/79boU1AAAAACAGu2rr75Sr169tHXr1v1ar7CwUOPGjdO4cePKPTdq1ChlZWVp6dKl+vTTT9WqVSvdeuutKiwsDPr1KagBAKhhLrjgAr3xxhvl2t944w1dcMEFkqScnBw9+OCDOvfcc9WiRQu1b99ew4YN0/bt2/3LDx8+XKeccopatmypli1b6rTTTlOHDh00fvx4FRcXB7y2y+XSs88+q0svvVSnn366zjzzTPXp00c//PDDod1YAACqsHjxYg0ZMkSDBg0q99xnn32mHj16qHXr1urSpYveeuutgOe7deumXbt26eqrrw5oN01ThmFo4MCBSk5OlsPh0C233KL09HRt2bIl6NgoqAEAiECDBg1SVlaWFi1apK+//lpLliyRy+XSTTfdJI/H41/u0ksv1caNG7Vx40Z98803evrpp/XRRx/prrvu8i9TUlKi6667TmvWrNHjjz+uL7/8UqtWrdJpp52m6667Tt9++204NhEAAElS+/bttWrVKl1yySUB7T///LP69Omj22+/XV988YXGjBmjRx99VGvWrPEvM3/+fD311FNKSUkJWNcwDE2bNk1Nmzb1t61YsUIxMTFq1KhR0LFRUAMAEIG++uordezYUbVr15YkpaamauTIkWrevLlyc3MrXMcwDJ122mmaNGmS1qxZo08++URS6cnG33//rWeeeUZNmzaVxWJRbGys+vTpo6uuukq//vprtW0XAAB7q127tmw2W7n2l19+WR06dFCnTp1ktVrVqlUrXXnllVqwYIF/mbS0tKDeY/Xq1XrkkUf0wAMPKDo6OujYykcFAABqvC5duuiBBx7Q+vXr1bZtWzVv3lwNGjSo8BqxvTVu3FjHHnusPv/8c7Vv317vv/++zjvvPMXFxZVbdtiwYYcifAAADtg///yjzz//XK1bt/a3eb1eHXPMMUG/hmmamjFjhmbNmqVHH320XC94VSioAQCIQI888ojatWund955R6NHj1ZeXp6OOeYY3XXXXbrsssuqXD85OVnZ2dmSSmdNbdOmzSGOGACAgystLU3du3fXww8/7G/buXOnTNMMav2ioiINGjRIv/32mxYsWBAw/DtYDPkGAKCGcTgc8nq95dq9Xq8cDockyWKxqFu3bnr22Wf15ZdfatmyZbr44os1dOhQrV27tsr3yMzM9F9PVrt2be3cubPC5XJycuRyuQ5gawAAODR69OihpUuX6pNPPpHP59OWLVt03XXXac6cOUGtP2jQIG3fvl2vv/56SMW0REENAECNU69ePf3zzz/l2v/88081aNBAa9asUcuWLf09zIZh6Pjjj9fgwYPVtGlT/fjjj5W+/qZNm/Tnn3/qf//7n6TSWcU//vhj5efnl1t21KhR6tOnz4FvFAAAB1nz5s01YcIETZgwQW3atNF1112nCy64QIMHD65y3R9++EEffPCBNm3apPPPP99/R4yWLVtq/fr1QcfAkG8AAGqYbt266bHHHlObNm30v//9Tx6PR59//rlee+01jR49Wm3atFFKSopGjBihu+++W40bN1ZJSYnef/99bdmyReedd16Fr+vz+fT111/rgQceUMeOHXXGGWdIkq655hotWbJEffr00ahRo3TSSScpOztbc+bM0aeffqq5c+dW38YDAFCJX375JeDxeeedt8/j3p72vLuFJJ1yyinlXisUhhnsAHMAAFBtXnvtNS1cuFBbt26Vz+dTo0aNdMMNN6hbt26SSq8Rmzp1qj755BNlZGTIbrerRYsWuuuuu9S8eXNJpfehfvvtt/3DxG02m9LS0tSlSxfdeuutATOm5ufna9q0aVq9erXS09PldDrVokUL9evXT6ecckr17wAAACIABTUAAAAAACHgGmoAAAAAAEJAQQ0AAAAAQAgoqAEAAAAACAEFNQAAAAAAIaCgBgAAAAAgBBTUAAAAAACEgIIaAAAAAIAQUFADAAAAABACCmoAAAAAAEJAQQ0AAAAAQAgoqAEAAAAACMH/A90URmQcjyJyAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = USDC/WETH\n" - ] - }, - { - "data": { - "image/png": "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9rIcHBw1bNgDF0yPjY3RuHHPq3v3nmratLkkqXJlFzVp0kyffvql5sxZrBo1auqFF8bozJkzV9wmkuTm5qannhoje3t71a1bT/36DTSH+YiInVqzZqVeeeVfl9zul1rv0iP6w4Y9cNE3nlOnTurdd/+tN95454LQLkmdO3fRrFmzdOTIYRUWFmrRonmKi4vR2bNn5ezsrFat2urLLz//65vxbE2b9olsbGx09uxZZWae1tGjkTpxIlbffjtb3377o1JTU/TOO29KKjltokOHTurUqYtsbGzUqFET9e07QPPnnxuK+feRAqWutOzz/fzzAi1atFJGo1ETJ75armV36tRF8+b9rMjIC9f71KmT+u239Ro79mW5u3vI2dlZzz//kg4e3K/Dhw9d8fUume50wfTzv3W+1Hpfzvfff6O2bdubv6WXdMXX/4472mnGjO9Vo0aATp06pYyMDLm6uio1tWQonMFgUL169TV+/ERt2rRJw4Y9oIkTX9G+fXuvuB0yMk4pNLSOOnfuqtmz52n69G904kSsJk16vVzLLtWjR29t2LBVEya8pbffft18qoCzc6VLHkkp9cwzY+Xm5iYPj6p6/PGntXbtqjJHVf39q2v9+i366qvvtX79Gv3ww0zztKt9Da5131OefmjX7k516tRFtra26tmzj+rUqaf169dccdmliouLNXPm13rooUfNX3JJJR90O3XqopYtW8vW1lYDBgxWaGidK67rpV6T77//RpUrV1L//oMueM6WLZvk4OCgRx55Qvb29qpWrbqmTPlc7dp1UFZWprZu3SIHBwf99NMCffrp/2nXrh36/POSLxOysjI1b94vuueeXlq8eLXGjfuXPv/8E23YsE4mk0mLFs3TU089I3//anJwcNDIkY+rsLBAW7duNi//8cefkq+vnypVqqzRo5/Xzp3hSktLVX5+vlxdXTVp0vtav36Lpk//WuvWrdGyZYvM26hv3/6qU6eu7O3t9fjjT5c5AvjqqxP10kvjZWtrq+TkpL8+AJ81f2lV6ptvvtSAAYPKjHJZvXqFataspUGDhsrW1la1atXW/feP0IIFc6643qX69Omnpk2by9bWVg899KgcHBy0desWHTp0QIcPH9RLL42Xs3Mlubq66Zlnxmr9+jUXnE5VWFio9957WwkJ8XryyQsD0dUYPvxhubi4yMOjqtq1u1Nx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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = THOR/WETH\n" - ] - }, - { - "data": { - "image/png": "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JBUUFGjgwN4ymUwyGAzmZS5ZslpGo1H79u3V22+/rtTUVN177wOaM+eHIrXl5eUpNzdXixatkLu7h86cOa0PP5ymw4cPqVq1aho58g498MDD5vnDwvZo+vTPdOrUCdWoUVO33z5K99//UJm2w7lzZ/X55x9r//4wmUwmtW7dVk899bzq1/eSJP3882zNnDmjyPszatRdeuyxJ/TCC09r//6wIq+XmZmpYcNu18SJrxW7rNGjh2nevCWqV6/+3/r9KM7cub9o3rxflJycrHr16umhh/6jPn36SSr9PSjt/T948IC+/PJjHT9+XG5utXX33fcV+T3/N9v80KGDevzxh8y9JEn+/gHmz69r9V5ZtvmcOT8oOPg3paamKCCghSZOfFWNGjUpU23Xer+//fZrhYXtKfKZei1/fb//rilT3pIkvfZa4X+3b9+iGTM+19mzsapb11Pjxz+jHj1uMs9/rfUubZtfa9kFBQX6/vuZWrZsiVJTU1SvXn09+OCj6tcvSJIUFHRTkecWFBQoOztbb775joKCbvnb633ZtfrAZDLpv/+dpC1bNsnV1U1z5y4u0udS0c/enJwczZr1ldasWanMzEy1a9dBzz77ourW9fzH9ZW3nj076vPPv9KAATdfNS08PEwvvvi01qzZbIXKyldk5DF9+eUnOno0Qvb29urUqYueeup5ubi4aPDgfkpPT1dgYOsy/579G5mZmfr44/e0Zcvvys/PU8+evfXCCy+rWrVqxc5/6NBBffLJ+zp16oRcXFz14IMPa8iQ4X9rmSXth0jSrl07NH/+b3r33Y//6SqZXeszOjs7W1999YU2blynjIx0NWrUROPGPWX+Liptu1zrc/JaQkN36IUXntZvvy0q02fiv/0MvezixYt6/PGH9NJLk676vj14cL+efvpxrV+/rcjjK1Ys1ezZs5SYmKDGjZvquecmKDCwtaTCz7gffvhWISGLlJqaqiZNmuqZZ14wTy9tf3b79i365pvpiomJUf36Xnr44bHq3fvP3/uNG9fp22+/1rlzZ1W7trvuv/8hDRlymyTp/Plz+uij97R//z5JJrVr10Fvvvm6jEYXSeW7T5mdnaXPPvtImzdvUk5Ojpo1C9BTTz0vX1+/f/xeVGaE8SuYTCZl5RWUad7zKVlKzsqTJK2KiJckrY6IV/9mHpKkWk528qzpVOLzL3Oy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mzf97ToSExM0Zcpbmj9/qWrWrClJeuGFl3X77YN0/HiU+Sjo3r27lZiYcFUdnTp1VadOXc0/t2gRqDvuuFvr1q3RPfc8oPj4C0VuhlOjRg3zcqTCm7a8/PLzSkpKVOPGTeXi4mI+Wl/aNnrjjZc1atSd5uHXJXF0dJQk9e8/UCtXLtP69WvNw4zKwtHRSY6OTho37imNHTtGKSkpmjz5jTIv22Qqftn16/954xEnJyfVquWi+Ph4tWrVpsgNlDw9PTV+/NMaO3aMMjLS5eDgoObNW5rfCz8/f40adac2bFije+65X+fOndWXX36ir7763PwaeXl5CghoroSEhD9e889gW7u2u2rXdtfp0yeVn5+vJ5541jyC4sknn9fQoUE6c+a0mjb1llR4w7o333xF6enpmjHjW/OR3v79B+rSpYt6990pSktLUdeuPdS//0Dze3bliApJuuee+7V8ecgfR2vvLHb7xcbGKCxsj15++fUijxuNRvPrXpaVlSWjsfDAiL29vW66qbd5B75t2/YaOHCQ1q9fq7Zt2yszM1Ovv/6ybGz+PDCUm5urc+fOFfn5s88+0rp1q/X++3/e68HX16/I+9OkSVONGfMfffjh1CLXFC5ZMl99+waZzzpIhV96OTk5qlfvz+1f3E5EvXpe5v+//PsTH39B586d09GjR3TLLX3M0wsKTLKxKfw8++ij99SqVRvzjvzgwcO0Zs1KLV8eoqeeeu6a74GbW+1S3//33ivsq1mzvpafn7+GDLlN8+b9+q+3ua2trT79dHqR2p59dqKGDg3S6dMnzWd3S+q9a21zqfD3q7h+qVbNWba2ttq7d7defPFp880WbW3tZDIVju4py/t95ft1+T07cSLK/H5f+Rl45fv912X7+/vJZDKYlx0fH686dYreTMzLq4H5HhVGY0nrVa1M632tbV7asi+7PIqlY8fOGjhwkNasWWk+42QymRQSskiPPvp4kYOwiYkJcnFxKbJzevlGTOvXr1WdOnWLzP/XG+2V1geXxcfHF9n2tra2qlv3z9+9J598TjNmfKYnnviPbG1tNXTocHl7+6hGjZrXrPHHH7/TTz99b378gw8+07PPTtCPP36nX375SVOmvCVfXz89++yEa569lQq/X2bM+FY//PCt/vvfSUpPT9fNN/fVM89MMH9X1qpVyzy/vb39VQeoJCkwsLXe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Ly8vXLp0CfHx8eL95Pb29hVeOSciInrVDRw4EDExMThz5gyUSiXu3buHoUOHYs2aNQCATz/9FJs3b8a5c+egVCoRGxsLiURSrYlLeWWciIiI1Hh4eCA4OBgZGRnlrmwfO3YM2dnZcHd31/jZHj16YPHixRg/fjwaNGiAgQMH6qLKREREf6sOHTogMDAQgYGBmDZtGszMzODl5YUZM2YAAAYMGABDQ0P89NNPSE1NxVtvvYWlS5eibdu2Wq+DyTgRERGpGTJkCI4ePYpRo0bhu+++g5OTE2QyGQ4fPoxFixZhwoQJcHBwqPDzPXr0wJdffol58+bByckJdnZ2Oqw9ERHR/+b5SUd79uyJnj17Vljez88Pfn5+//P6mIwTERGRGiMjI4SHhyMyMhILFixASkoKjIyM0KZNG8yfPx+9evWq8jumT5+O8+fPY9asWdi6davac8iJiIgIMBCqc4c5EREREREREb0wTuBGREREREREpGNMxomIiIiIiIh0jMk4ERERERERkY4xGSciIiIiIiLSMSbjRERERERERDrGZJyIiIiIiIhIx5iMExEREREREekYk3EiIiIiIiIiHWMyTkRERERERKRjTMaJiIiIiIiIdIzJOBEREREREZGO/T9jlWusc2oedAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CC.plot()" - ] - }, - { - "cell_type": "markdown", - "id": "046386ca-d86b-43c2-b977-c79d3a11dbbd", - "metadata": {}, - "source": [ - "### Analysis" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "39eefaa8-3b75-492c-9742-60ebbb2805a2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "USDC-eB48/THOR-8044 1 2.754821212121191 THOR-8044 per USDC-eB48\n", - "THOR-8044/WETH-6Cc2 -1 6205.376410123059 THOR-8044 per WETH-6Cc2\n", - "USDC-eB48/WETH-6Cc2 -1 2373.231732603509 USDC-eB48 per WETH-6Cc2\n" - ] - } - ], - "source": [ - "sgn = [1,-1,-1]\n", - "price = dict()\n", - "quote = dict()\n", - "for c,s in zip(CC, sgn):\n", - " price[c.pair] = c.p\n", - " quotep = f\"{c.tkny} per {c.tknx}\" if s > 0 else f\"{c.tknx} per {c.tkny}\"\n", - " print(f\"{c.pair} {s} {(c.p)**s} {quotep}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "27482e36-f30b-4d16-af62-6f5f058d625a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'USDC-eB48/THOR-8044': 2.754821212121191,\n", - " 'THOR-8044/WETH-6Cc2': 0.0001611505787737007,\n", - " 'USDC-eB48/WETH-6Cc2': 0.00042136635300378734}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "price" - ] - }, - { - "cell_type": "markdown", - "id": "c3aca871-25be-49f5-8bc4-95b06adb3651", - "metadata": {}, - "source": [ - "### Carbon curve\n", - "\n", - "Below is the Carbon curve. It **sells THOR** and **buys USDC** at a rate of **0.36 USDC per THOR** (ignoring fees)." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "9cfb7903-dad1-40e0-b243-c625d24cf5ea", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.3629999637000064" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p0 = 1/(price[\"USDC-eB48/THOR-8044\"])\n", - "p0" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "0ae2849d-3da9-4b55-b4d6-ea5bccc2d3e2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cid = 098056-1 [74181555988764585035015664420125470098056-1]\n", - "primary = THOR/USDC [THOR-8044/USDC-eB48]\n", - "pp = 0.363000 USDC per THOR\n", - "pair = USDC/THOR [USDC-eB48/THOR-8044]\n", - "tknx = 0.000000 USDC-eB48 [virtual: 1,250,505,254,484.410]\n", - "tkny = 344,491.806153 THOR-8044 [virtual: 3,444,918,400,922.661]\n", - "p = 2.754821212121191 [min=2.7548206611570305, max=2.754821212121191] THOR-8044 per USDC-eB48\n", - "fee = 2000.0\n", - "descr = carbon_v1 THOR-8044/USDC-eB48 2000\n", - "\n" - ] - } - ], - "source": [ - "print(CC[0].description())" - ] - }, - { - "cell_type": "markdown", - "id": "4f6823e5-1428-4003-b4f4-fd5b33c7626d", - "metadata": {}, - "source": [ - "Ignoring slippage and fees, it is possible to buy and sell THOR AT 0.38 USDC per THOR via the two provided curves." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "07973179-852d-47b4-a58d-4045e364c694", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.3824476672731679" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p1 = 1/(price[\"USDC-eB48/WETH-6Cc2\"] / price[\"THOR-8044/WETH-6Cc2\"])\n", - "p1" - ] - }, - { - "cell_type": "markdown", - "id": "97da9475-11a9-4c44-a374-bec8470cc125", - "metadata": {}, - "source": [ - "That's an arbitrage opportunity (Buy THOR against USDC on Carbon, sell into the arb) of about 5% meaning that at least in small size (ie before slippage) it should work" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "9f916699-6d10-4d96-a1ea-362da210157f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.05357494633039028" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p1/p0-1" - ] - }, - { - "cell_type": "markdown", - "id": "b0f5520b-e0cb-4e96-ac6a-c8bd3db7a3fb", - "metadata": {}, - "source": [ - "### Triangle curves\n", - "\n", - "The triangle curves are the following\n", - "\n", - "- **THOR/WETH** has 422 ETH and 2.6m THOR at a price of 6205 THOR per ETH\n", - "- **WETH/USDC** has 23k ETH and 50m USDC at a price of 2373 USDC per ETH\n", - "\n", - "The implied **THOR** price is 0.382 USDC (memo: on Carbon it is 0.362, and the THOR loading is 344k, ie ~15% of the THOR-8044 available on the arb curve)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "59548034-715e-4bc8-a13f-920d97531fae", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.3824476672731679,\n", - " 0.3629999637000064,\n", - " 0.05357494633039028,\n", - " 0.13230769230769232)" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p1, p0, p1/p0-1, 344/2600" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "0b9e2429-67ee-4942-b35a-fd7286717de6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cid = 7cc2fd9c [0xbf1875da0431343b56ec6295f706e257dbe85696e5270a5bdad005d37cc2fd9c]\n", - "primary = THOR/WETH [THOR-8044/WETH-6Cc2]\n", - "pp = 0.000161 WETH per THOR\n", - "pair = THOR/WETH [THOR-8044/WETH-6Cc2]\n", - "tknx = 2,619,874.851941 THOR-8044 [virtual: 2,619,874.852]\n", - "tkny = 422.194349 WETH-6Cc2 [virtual: 422.194]\n", - "p = 0.0001611505787737007 [min=0, max=None] WETH-6Cc2 per THOR-8044\n", - "fee = 0.003\n", - "descr = sushiswap_v2 THOR-8044/WETH-6Cc2 0.003\n", - "\n" - ] - } - ], - "source": [ - "print(CC[1].description())" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "d52852dd-e4ad-4ab5-9cec-64420c088a15", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6205.376410123059" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1/0.0001611505787737007" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "56044ea4-e898-4839-b999-219d646ae81d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cid = da7e6be2 [0x68bd2250b4b44996e193e9e001f74a5e5a31b31fbd0bb7df34c66eb8da7e6be2]\n", - "primary = WETH/USDC [WETH-6Cc2/USDC-eB48]\n", - "pp = 2,373.231733 USDC per WETH\n", - "pair = USDC/WETH [USDC-eB48/WETH-6Cc2]\n", - "tknx = 54,102,579.539405 USDC-eB48 [virtual: 54,102,579.539]\n", - "tkny = 22,797.006629 WETH-6Cc2 [virtual: 22,797.007]\n", - "p = 0.00042136635300378734 [min=0, max=None] WETH-6Cc2 per USDC-eB48\n", - "fee = 3000.0\n", - "descr = uniswap_v2 USDC-eB48/WETH-6Cc2 0.003\n", - "\n" - ] - } - ], - "source": [ - "print(CC[2].description())" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "06017b09-f6db-41a3-a9c3-a8e388b74411", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2373.231732603509" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1/0.00042136635300378734" - ] - }, - { - "cell_type": "markdown", - "id": "e065903b-a3ca-45f1-9463-959b0f2f5447", - "metadata": {}, - "source": [ - "## Optimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "35596d19-ef1f-46f8-b4fc-648066dbdb7c", - "metadata": {}, - "outputs": [], - "source": [ - "#help(MargPOptimizer.optimize)" - ] - }, - { - "cell_type": "markdown", - "id": "9c5ddea0-da97-411f-9709-ed96cb9d9c2c", - "metadata": {}, - "source": [ - "### Raw run\n", - "\n", - "This is the actual run, using USDC as the arbitrage token. This run does not converge; rather the THOR-8044/USDC-eB48 price oscillates between 0.38ish and 0.29ish. Note that this is way out of the (imputed) price range for the Carbon range which is very tightly centered around `p0~0.36`\n", - "\n", - "(uncomment the below code to see the debug run)" - ] - }, - { - "cell_type": "markdown", - "id": "4f1457f6-13e6-4102-9ac3-3a3ff177e084", - "metadata": { - "tags": [] - }, - "source": [ - "Note: this section of the code no longer runs as the price estimates cannnot be found; this could be related to the fact that we moved from `ticker-shortaddr` to `address`. It does not really matter though, the code in the following sections is enough." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "acccd8c2-b239-4aeb-ab97-2d338f05c365", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[price_estimates] tknqs [1] = ['USDC-eB48'] , tknbs [2] = ('WETH-6Cc2', 'THOR-8044') \n", - "[price_estimate] USDC-eB48/WETH-6Cc2 1 curves\n", - "[price_estimate] USDC-eB48/THOR-8044 0 curves\n", - "[price_estimates] pair estimates: 1 found, 1 missing\n", - "[price_estimates] triangulation tokens ['0xdAC17F958D2ee523a2206206994597C13D831ec7', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599']\n", - "[price_estimates] after triangulation 1 missing {'THOR-8044/USDC-eB48'}\n" - ] - }, - { - "data": { - "text/plain": [ - "{'tokens_t': ('WETH-6Cc2', 'THOR-8044'),\n", - " 'tokens_ix': {'WETH-6Cc2': 0, 'THOR-8044': 1},\n", - " 'price_estimates_t': None,\n", - " 'pairs': {'THOR-8044/WETH-6Cc2',\n", - " 'USDC-eB48/THOR-8044',\n", - " 'USDC-eB48/WETH-6Cc2'},\n", - " 'sfc': CPCArbOptimizer.SelfFinancingConstraints(data={'USDC-eB48': 'OptimizationVar'}, tokens={'USDC-eB48'}),\n", - " 'targettkn': 'USDC-eB48',\n", - " 'pairs_t': (('USDC-eB48', 'WETH-6Cc2'),\n", - " ('USDC-eB48', 'THOR-8044'),\n", - " ('THOR-8044', 'WETH-6Cc2')),\n", - " 'crit': {'crit': 'rel',\n", - " 'epsr': 1e-06,\n", - " 'epsa': 1,\n", - " 'epsaunit': 'USD',\n", - " 'pstart': None},\n", - " 'dtknfromp_f': .dtknfromp_f(p, *, islog10=True, asdct=False, quiet=False)>,\n", - " 'optimizer': }" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(\"USDC-eB48\", result=O.MO_DEBUG, params=dict(debug_pe=True))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "dad2cc21-c760-47b5-ac6b-7f9c539f1ce3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "('no price found for 1 pairs', {'THOR-8044/USDC-eB48'}, array([[2373.231732603509, None]], dtype=object))\n" - ] - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "try:\n", - " r = O.optimize(\"USDC-eB48\", params=dict(verbose=False, debug=False))\n", - "except Exception as e:\n", - " print(e)\n", - " r = None\n", - "#O.optimize(\"USDC\", params=dict(verbose=True, debug=True))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "443fad22-9bc7-4b87-aefc-e56cbcffa3ca", - "metadata": {}, - "outputs": [], - "source": [ - "#r = O.optimize(\"USDC\", params=dict(verbose=True, debug=True))\n", - "#r" - ] - }, - { - "cell_type": "markdown", - "id": "68c2d8b2-35e6-4271-90da-071a0aa2c570", - "metadata": {}, - "source": [ - "### Better prices estimates\n", - "\n", - "We set the initial price for THOR/USD squat into the Carbon range to see whether this works better. \n", - "\n", - "TLDR -- it does not." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "b17f69b0-0712-45e6-a56a-ccf9d9890ab4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'USDC-eB48': 1, 'WETH-6Cc2': 2373.2, 'THOR-8044': 0.3629999637000064}" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "price_est = {\n", - " \"USDC-eB48\": 1,\n", - " \"WETH-6Cc2\": 2373.2,\n", - " \"THOR-8044\": p0,\n", - "}\n", - "price_est" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "3b9cc2be-f2f4-4934-8f70-c5408c30e2a5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=None, time=0.007066249847412109, method='margp', targettkn='USDC-eB48', p_optimal_t=None, dtokens_t=None, tokens_t=('WETH-6Cc2', 'THOR-8044'), errormsg=ConvergenceError('maximum number of iterations reached [49]'))" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(\"USDC-eB48\", params=dict(pstart=price_est, verbose=False, debug=False))\n", - "#O.optimize(\"USDC\", params=dict(pstart=price_est, verbose=True, debug=True))\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "ec494344-52ec-4e61-b75c-024351cea58d", - "metadata": {}, - "source": [ - "#### Tighter Jacobian\n", - "\n", - "Currently the jacobian h is set to 1e-5 and `minrw` in the data provided is set to 1e-7 meaning that the Jacobian calculation goes outside the concentrated liquidity area and is therefore much too steep.\n", - "\n", - "We'll try 1e-8 as `jach` here. Turns out this works and it even converges. " - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "3658f1b8-5a10-4a44-94d0-485a29181d6c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2.0000001033082526e-07" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC[0].p_max/CC[0].p_min-1" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "fdbb8fc1-2735-4269-b7fe-57e9ccbb310e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-652.6409813463688, time=0.0009760856628417969, method='margp', targettkn='USDC-eB48', p_optimal_t=(2371.00929814847, 0.36299997803167783), dtokens_t=(7.815970093361102e-11, 0.0003078095614910126), tokens_t=('WETH-6Cc2', 'THOR-8044'), errormsg=None)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(\"USDC-eB48\", params=dict(pstart=price_est, verbose=False, debug=False, jach=1e-8))\n", - "#O.optimize(\"USDC\", params=dict(pstart=price_est, verbose=True, debug=True))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "323dc5cd-80e3-4b49-a2d3-59d71510dec5", - "metadata": {}, - "outputs": [], - "source": [ - "# CCr.plot()" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "a08ded9c-7760-4f1d-b4a8-d084215ecb4c", - "metadata": {}, - "outputs": [], - "source": [ - "# O = MargPOptimizer(CCr)\n", - "# r = O.optimize(\"USDC-eB48\", params=dict(verbose=False, debug=False))\n", - "# O.optimize(\"USDC-eB48\", params=dict(verbose=True, debug=True))\n", - "# r" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "87867c5a-9065-46ad-9434-18c3010d7924", - "metadata": {}, - "outputs": [], - "source": [ - "# p2 = r.p_optimal[\"THOR-8044\"]\n", - "# p2" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "4b0fa4ff-f7cc-403b-bf26-2ae1ec0aa1a9", - "metadata": {}, - "outputs": [], - "source": [ - "# p2/p0-1" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "8cd59754-1a92-45ce-a7cc-984159574aba", - "metadata": {}, - "outputs": [], - "source": [ - "# r.dtokens" - ] - }, - { - "cell_type": "markdown", - "id": "c0c19fa3-ea5b-4c44-983d-c603a7894cf0", - "metadata": {}, - "source": [ - "#### Absolute convergence criteria" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "0533150c-87d1-4b82-818c-1f7f305b1b75", - "metadata": {}, - "outputs": [], - "source": [ - "#O.optimize(\"USDC-eB48\", result=O.MO_PSTART)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "c30651f5-1d74-4074-b6d4-1259f0d2d3a8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=None, time=0.006891965866088867, method='margp', targettkn='USDC-eB48', p_optimal_t=None, dtokens_t=None, tokens_t=('WETH-6Cc2', 'THOR-8044'), errormsg=ConvergenceError('maximum number of iterations reached [49]'))" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pstart = {'WETH-6Cc2': 2373.231732603511, 'THOR-8044': 0.36299996370000637, 'USDC-eB48': 1, \"USD\": 1}\n", - "params = dict(norm=O.MO_NORMLINF, epsa=10, epsaunit=\"USD\", pstart=pstart)\n", - "r = O.optimize(\"USDC-eB48\", mode=O.MO_MODE_ABS, params=dict(verbose=False, debug=False, **params))\n", - "#r = O.optimize(\"USDC-eB48\", params=dict(verbose=True, debug=True, **params))\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "9aca4565-2371-42dc-96a0-f9811976b663", - "metadata": {}, - "source": [ - "### Removing the Carbon curve\n", - "\n", - "Here we check how it converges if we remove the Carbon curve and replace it with a constant product curve of the same (virtual) capacity. Unsurprisingly it does and all dtokens are zero." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "b62f2618-0db7-46ed-9aa1-46a858b24b37", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "ConstantProductCurve(k=4.3078885616238194e+24, x=1250505254484.4102, x_act=1250505254484.4102, y_act=3444918400922.661, alpha=0.5, pair='USDC-eB48/THOR-8044', cid='None', fee=None, descr=None, constr='xy', params={})" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c0 = CC[0]\n", - "c0b = CPC.from_xy(x=c0.x, y=c0.y, pair=c0.pair)\n", - "c0b" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "51e7eb4b-1fc7-4aed-b8c1-1e2d174c92c4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = USDC/THOR\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9QAAAIYCAYAAACMiaT/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB05klEQVR4nO3dd3gU9fr+8XvTEwgESE8IgRB6CRBAJfTepaOg2D3YEAuKnKMeK34VCxZEFAuiSO8dlN57J6T3HggkpO7vDw75EUMJK2Sz8H5dVy7N7MzOM/vshrl3Zj5jMBqNRgEAAAAAgJtiZe4CAAAAAACwRARqAAAAAABMQKAGAAAAAMAEBGoAAAAAAExAoAYAAAAAwAQEagAAAAAATECgBgAAAADABARqAAAAAABMQKAGAAAAAMAENuYuAACAiuqhhx6SJM2aNeuqj3fp0kVt2rTR5MmTJUmnT5/WtGnTtHv3bp09e1YuLi4KDg7WU089pUaNGhUv9/rrr2vRokXFvxsMBjk4OMjX11e9e/fWE088IXt7+1Lri4iI0M8//6ytW7cqOTlZ1atXV4sWLfT000+rQYMGpeb/6aeftHnzZuXn52v37t3X3dY2bdpo1qxZ+vLLL/XVV1/p1KlTV53v9ddf1+7du7Vx48YS02NjYzVjxozi2qpWraomTZpo9OjRCgkJKfUcV27/5dfA0dFRfn5+GjJkiB5++OHr1gsAQEVAoAYA4BYIDQ3ViBEj1KxZM02aNEmurq5KTEzUr7/+qhEjRmjWrFkKCgoqnt/NzU1fffWVJKmoqEhZWVnas2ePpk2bpm3btunHH38sEarXrVunV199VYGBgRo7dqx8fX2VmJioWbNmadiwYfr666/VoUOHEjVt2rRJHTt2VEhIiM6fP188/b///a8k6a233iqeVrlyZZO3fceOHXr22Wfl4eGhxx9/XHXr1lV6erqWL1+uxx9/XGPGjNEbb7xRYpkrt1+SjEajUlNTNWfOHL3//vuys7PTyJEjTa4JAIDyQKAGAOAW+PHHH+Xi4qLvv/9etra2xdO7deum3r1765tvvtF3331XPN3Ozq5EwJakjh07qnnz5nruuec0c+ZMjR07VpIUHR2tCRMmqH379vr8889lbW1dvEzPnj314IMP6vXXX9fGjRvl4OAgScrOztbevXv173//WwEBASXWczk8/339pkhKStILL7ygFi1a6JtvvinxJUCvXr30008/6cMPP1RgYKCGDRt23e2XpE6dOql79+6aP38+gRoAUOFxDTUAALdAamqqpEtHWq/k5OSkiRMnqnfv3mV6nu7du6tZs2aaM2dO8bRZs2YpLy9P//73v0uEaUlycHDQa6+9pqFDh+rcuXPF03fs2CF3d/dSYfpW++mnn3ThwgW99957Vz1N/ZFHHlFQUJCmTZtW6rW5Gltb2+IvBQAAqOgI1AAA3AKdOnVSfHy8Ro4cqdmzZyssLKw4QPbq1UuDBg0q83OFhIQoMTFRcXFxkqQtW7aoUaNG8vDwuOr8bdu21UsvvSR3d/fiaZs2bSp1CvjNKCgouOrP30Px1q1b1bBhQ3l5eV3zuXr37q24uDidOHHimuvIy8tTfHy8/u///k8RERG6//77Ta4dAIDywinfAADcAg8++KBSUlL0ww8/6J133pEkVatWTSEhIXrooYfUvHnzMj+Xq6urpEtHvX18fJSUlKSGDRveVD1btmzRm2++eVPLXKlx48bXfMzHx6f4/2NjY28Y3GvVqiVJiouLKx6cLS4u7qrr8Pf311tvvaUHHnjAlLIBAChXBGoAAP4Bg8FQ/P/jxo3TI488oi1btmjHjh3atWuXli1bpuXLl2vixIkaM2aMSc9tMBhUWFhY5uVCQ0OVmpqqe+6556bWd6X58+dfdfrXX3+t06dPF/9uNBplY3P93YnLp6lfeXTbzc1N06ZNkyRlZGRo+vTpio6O1gcffKBWrVqZXDcAAOXJ4k75Tk9PV/fu3bVr166bXvbHH38svgXKZRkZGXr99dfVrl07tW7dWmPGjCl1ShoA4O7k5OSkvLy8az6el5cnR0fHEtOqVq2qfv366f3339f69eu1aNEi1a1bV5988okyMjLKtN7k5GRJKj7F28fHR/Hx8decv6CgoHgZ6dLp3m3atClV281o2rTpVX9cXFxKzOfj41N8avq1xMTESJK8vb2Lp9nZ2RU/Z4cOHfT999/LxcVFTz31lMLDw02uGwCA8mRRgXrfvn0aMWKEoqOjb2q57OxsTZ48ufg+oVeaNGmSMjIytHz5cm3btk0tW7bUE088oezs7FtVNgDAQrm6upYIqlfKy8tTenq6XF1dlZSUpJCQEM2bN6/UfI0aNdKLL76ovLy84mB5I9u3b1etWrWKA3VISIiOHz+ulJSUq86/ZcsWtW/fXitWrJB0KVC3b9++TOv6p7p06aIjR44oISHhmvOsWbNGXl5eJe7F/XeOjo764IMPlJ2drTfeeKNMA5gBAGBuFhOoFy1apFdeeUXjx48v9dj27ds1dOhQBQcHq2/fvlq6dGmJxwcOHKiUlJRS12MZjUYZDAaNGzdO1apVk52dnR5//HGlpqYqMjLydm4OAMACtGnTRvHx8Tp8+HCpx9avX6/CwkLdc889cnV1lY2NjX777Tfl5uaWmjc8PFz29vbF1xJfz19//aXDhw+X+Ddr1KhRsrW11XvvvVfq1O+cnBxNnTpVVatWVefOnXX+/HkdOHBAHTt2NGGLb95DDz2kypUra+LEiVfd9t9++027du3S008/LSur6+92NG3aVMOHD9eBAwe0aNGi21UyAAC3jMVcQx0SEqL+/fvLxsamRKg+efKkxo4dq48//lhdu3bVoUOH9Mwzz6hatWrF387PmjVLnp6e+vLLLxUWFla8rMFg0Ndff11iPatXr5aTk5Nq165dPhsGAKiw+vTpo59//llPPvmknn76aTVu3FhFRUXav3+/vv/+e/Xt21ctW7aUJL399tt69tlnNWTIEI0aNUoBAQHKycnRtm3bNHv2bI0bN05Vq1Ytfu68vDwdPHhQ0qUveM+dO6e9e/fql19+Udu2bTV69OjieX19ffX2229r0qRJGjVqlEaOHCkvLy9FR0frp59+UlRUlGbMmCEnJyetXbtWnp6e5fbvmLu7u7744gu98MILGjx4sB5++GHVqVNHZ8+e1apVq7RixQqNGjWqzIOMvfjii1q1apWmTJmi7t27y9nZ+TZvAQAAprOYQO3m5nbV6XPmzFHXrl3Vo0cPSVLLli01fPhwzZ49uzhQe3p6lmkdGzZs0Hvvvae33377H113BgC4M9ja2urXX3/Vt99+q3nz5mnq1KmysrJSrVq1NH78+BKht1OnTpo7d65++OEHffvtt0pPT5ednZ0aNWqkzz77rPjfqctSUlI0YsQISZe+4K1WrZpq1qypCRMmaNiwYbK1tS0x/6BBg1SrVi39/PPP+vzzz5WWliY3Nze1aNFCX3zxherWrStJ2rx58z+6XZYp7rnnHi1evFg//fSTZs6cqYSEBFWpUkVNmzbVjBkzbur082rVqmncuHF65513NHXqVE2aNOk2Vg4AwD9jMFrgRUr169cv/gb/ySef1M6dO2Vvb1/8eGFhofz8/LRkyZISy3355ZfavXu3Zs2aVWK60WjUtGnTNGPGDL3//vvq06dPuWwHAAAAAMByWcwR6mvx9PTUoEGDiu/5KV0aHbWs3xPk5ORo/PjxCg0N1ezZs687YAoAAAAAAJdZzKBk1zJ06FAtX75cW7duVVFRkSIjIzV69GjNnDmzTMuPHz9eiYmJWrBgAWEaAAAAAFBmFn+Eunnz5vr000/16aefaty4cXJ0dFS/fv300ksv3XDZY8eO6c8//5SdnZ06d+5c4rEZM2YoODj4dpUNAAAAALBwFnkNNQAAAAAA5mbxp3wDAAAAAGAOBGoAAAAAAExAoAYAAAAAwAQVflCylJQsc5dQJtWrV1J6+gVzl4F/gB5aPnpo2UzpX35+vubPn62MjHS5u7tr0KAHZG1tfZsqxI3wGbR89NDy0UPLRv8qDjc35zLNxxHqW8BgkKytrWQwmLsSmIoeWj56aNlM7Z+tra26d+8tGxsbJScna+fOLbenQNwQn0HLRw8tHz20bPTPMhGoAQAWzdXVQ+3bd5IkHTq0XxERYeYtCAAA3DUI1AAAi9ewYTM1bdpCkrRhw2qdPZtp3oIAAMBdgUANALgj3HdfB3l4eCkvL1crVy5Wfn6+uUsCAAB3OAI1AOCOYG1trR49+sre3l4ZGen688/V5i4JAADc4QjUAIA7hrNzFXXu3EMGg0FnzoTq2LHD5i4JAADcwQjUAIA7Sp06gWrT5j5J0pYtG5WQEGfmigAAwJ2KQA0AuOO0bNlGAQH1VFRUpNWrl+ncuUxzlwQAAO5ABGoAwB3HYDCoS5ceqlatunJysrVq1RIVFDBIGQAAuLUI1ACAO5KtrZ169uwnW1tbpaWlacuWP81dEgAAuMMQqAEAd6zq1V3VrVtvGQwGnThxlEHKAADALUWgBgDc0WrXrqu2bdtJujRIWVxcrJkrAgAAdwoCNQDgjteiRWsFBASqqKhIa9YsZZCyf+h4YpbGzj2k44lZ5i4FAACzIlADAO54BoNBnTt3V9WqVXXx4kWtXr2MQcr+gZXHk7Q35qxWHk+67esKCQlWly7tNHHiK8W/v/rqOBmNxpI1rVymoUP73/Z6riYhIV4hIcH65JMPSz32ww/T9dxzT932Gr74Yoq6dQtRSEiwEhLib/v6jEajfvrpew0bNkA9enTUmDEj9eef6685f1xcrF555QX17t1F/fp117vvvqmsrJv/QuavvzZo2LCBV61nyJB+ysjIuOnn/LuMjHRNnPiyevXqpL59u+qLL6aooKDghsuFh59R167ttH//3jKvKyQk+Kbmv5Z33/1PqffZxo3r9fDDI9S9ewcNHtxXP/wwXUVFRcWP79ixVQ8/PELduoVo1Kih2rZtS/Fj3bu3L/HTtWs7hYQEa9261ZJu3M89e3bpscdGq0ePjhoypJ9+/HFGic/s3Lm/l3jv/PXXhuLHioqK1L17e3XrFlKihpycHElSbm6uPv/8Ew0Y0FM9e3bUuHFjFRUVWeo1iY2NUZ8+XUt9Hg4c2Kcnnxyj7t3ba/Dgvpo168fix3Jzc/XFF1M0aFAf9ezZUU8+OaZEf0JDT+mFF/6lnj07qm/frnr33f/o7NnMMm/3ZVd7H+fl5embb6aqQ4cO6tWrsyZOfEVJSYmllpWu3u/LcnJyNGrUUP3ww/QS0xcvnq8HHhis7t07aOTIwVq4cN5Vl//880/0/vtvl5iWmpqif//7NfXp01UDB/bUl19+qtzc3OLH9+/fq6efflS9enXSoEF99PnnH+vixYuSLvXzhx+ma/Dgvurevb0efniENmxYV7xsbu5FffzxBxowoKd69eqscePG6syZ0Jve7suOHTta3N9hwwZo+fLF153/ViBQAwDuCnZ2Durde6Ds7e2VmpqiP/9cd9UdnbuJ0WhUTn5hmX4i0i7oYNxZHYw7qzUnUyRJa0+mFE+LSL2g7LwC5eRd/3lMec0/+eQLffjhJ8W/79ixTb/99sstex1ulcWLF5TYUSxP48a9rFmz5pbb+ubN+10rVizTxx9/oTVr/tKTTz6jd999S8ePH73q/G+/PUm1awdo2bK1+u23+UpKStRXX31W5vUVFBRo9uyf9dZbb8hoLCr1+LFjR+Xl5a1q1aqZvE2XvfnmRDk6Omnx4tX67ruftXfvLs2d+9t1l7l48aLefntSiZBRXpYvX6J169aUmHbmTOj/wsd4rVu3WV98MU1Lly7UqlXLJUkxMdGaNOk1PfHEWK1e/Zcee+xpvfnm60pJSZYkrVu3pcRPp05d1abNvercuZuk6/fz7NlMTZz4sh555AmtXbtJU6Z8qQUL5mrNmpWSLn1+Z836UVOmTNXatZv06KNP6s03JxYH38jIcBUUFGjVqj9L1ODo6ChJmjJlsk6dOqGZM2dr2bJ1qlXLX//+94QS27916yaNHfu4zp07W2J6VFSkXn11nAYPHqa1azfr//7vc82Z82vxl0HffvuVjhw5pG+/namVKzeqf//7NWHCi0pMTFR+fr5eeWWcWrYM1ooVGzRnzmKlpqbpyy/Ltt3S9d/H06d/pb/+2qgffvhBy5atVc2aNTV+/LPKzy/55e/V+n2lKVMmKyYmusS0zZv/0rfffq1Jk/6rtWs36d//flvfffdNiS8yzp7N1Dvv/Efz588psWxRUZFef/1l5eXl6fffF+jnn//QmTOhmjJlsiQpJSVZr732kvr2HaAVKzbo229n6ujRI5o2baokaeHCuVq9eqW+/HK61q3boqeffk7//e+k4suvfvjhO8XEROvXX+dq2bK1qls3UG+88Uqp7brRdkvSuXPn9Oqr49SrV1+tWvWnXn/9P5o69bNr/l26VWxu67MDAFCBVK/uql69+mvZsoUKDT2p6tVd1apVG3OXZRZGo1FPzDmkw/HnTH6OjJx8PTnn0E0t09y7imaMbC6DwWDyeocOHaEZM6apWbMgNW3a/KrzhIWd0bRpU3Xs2FE5ODioXbsO+te/nlPlypW1cuUyLVu2WPXrN9T69aslGRQS0kGvvDJRNjY2MhqNmj//Dy1cOFcZGemqU6euXnjhZTVo0PCGdf3f/72n+vUbyNe35lXnOXTogL777huFhYXK2bmKevTorTFjHpednZ1++GG6IiLCZGdnr+3bt8jR0Uk9e/bRv/71nCQpPz9fP//8g9asWaXz57PUuHETvfjiq9dc18svvyBPT0+9+uobpR5buXKZFi9eoLp1A7V+/Vo5Ojpo8OBhevnlFyVJo0cPV1JSQqnlmjVroSlTpiorK0uPPvqE/P1rS5JCQjrI399fR44cUqNGTUotFxUVqWbNglRUVCSj0SiDwSAHB4frvp5XGj/+WdnZ2Wv06EdKBJTLNm/eqA4dOkuShg7trz59+mvdutVKTU1RvXoN9MorE1W7dh2tXbtKH3/8wVXX8cknU1WjhqsOHNinxYtXycHBQT4+vnrkkSf0zTdT9eCDD1+zvilTJqtDh84KDw8r8zb93cqVyzR16qeaPHmKDAaDXnnlhavO9+qrb6hHj96SpIiIcP388w/q3//+Ekdp69YN1IoV6+XkVElFRUU6ezZTBQUFqlrVRZK0atVyNW8epA4dOkmSunbtrpUrl2np0kV6/PGnS9W1d+8u/fLLH7KxuRQdrtfPxMREXbx4UUZjUfEXaFc+HhUVIaPRqKIio4xGo6ysrGVjYytra2tJ0okTxxUQEChbW9tS256Rka41a1bq11/nydXVVZI0duwLio6OKq5j5szvtHHjej399DOaPPm9EssvXDhX7dt3Uu/e/Ypfp2nTZqpSpUqSLh0tffzxp+Xh4SlJGjBgkKZN+1KnTp1Qx46dNWfOItnb28vKykpZWed08WKOXFyqlWm7peu/j9etW6NnnnlegYGBSk3N0tNPP6dFi+Zr797duvfedtft95W9SkpKLPV3MTU1RaNHj1GTJk0lSU2aNFPLlsE6ePCAOnXqquzsbD344BB17dpDnTp1KbFsTEy0Tp48rvnzlxe/f5566lk9++wTeuGFlxUfH6eQkA4aMGCQJMnDw1M9e/bR8uVLJEmDBw9X374D5ejoqLy8PGVmZsjBwVH29v///XD5fXT5/fD3vw032u7LNm3aqCpVqmrIkOGSpFatWqtHj15auHDeVf8u3SoEagDAXcXHx0/t23fRpk3rtWvXVlWuXEn16zc2d1lmYXqkNa8OHTrLaDTqrbfe0E8//aYqVaqWePzs2Uw9//zT6tOnv95///90/vx5vfPOf/Tee29q8uRPJUlHjhzSPffcp8WLVxefxhkc3EbduvXUwoXzNGfOr/roo8/k719bq1ev0IsvPqPffpuv6tVrXLOuESNGKSEhXm+++bq+/fZH2dnZlXg8OjpS48c/q3/963l9/vk3SkpK1KRJE3ThwgW9+OKlIzKbNv2pN954S5Mmva3du3dowoTxCgnpqCZNmuq7777Rvn279cUX36hGDVf99tsvGj/+Of3661zZ29uXqmfKlKnXfR2PHz+qpk2badmytYqICNPLLz+vWrV81blzL/366/WPdv89dEVGRigiIlz161/9S4fHHntS3377lebPn6PCwkI1btxUY8dePTBezX/+847c3T20cuWyqz6+efMmff75N8W/L126SB9//Ln8/Gpp6tRP9dpr4/XbbwvUo0fv4jB6NVu2/KUqVarK1dWteJq/fx0lJSUqKytLzs7OpZZZtWq5YmNj9Prr/9FPP31f5m260rJlizV9+tf6/POv1aBBI0mXjhJf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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = USDC/WETH\n" - ] - }, - { - "data": { - "image/png": "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9rIcHBw1bNgDF0yPjY3RuHHPq3v3nmratLkkqXJlFzVp0kyffvql5sxZrBo1auqFF8bozJkzV9wmkuTm5qannhoje3t71a1bT/36DTSH+YiInVqzZqVeeeVfl9zul1rv0iP6w4Y9cNE3nlOnTurdd/+tN95454LQLkmdO3fRrFmzdOTIYRUWFmrRonmKi4vR2bNn5ezsrFat2urLLz//65vxbE2b9olsbGx09uxZZWae1tGjkTpxIlbffjtb3377o1JTU/TOO29KKjltokOHTurUqYtsbGzUqFET9e07QPPnnxuK+feRAqWutOzz/fzzAi1atFJGo1ETJ75armV36tRF8+b9rMjIC9f71KmT+u239Ro79mW5u3vI2dlZzz//kg4e3K/Dhw9d8fUume50wfTzv3W+1Hpfzvfff6O2bdubv6WXdMXX/4472mnGjO9Vo0aATp06pYyMDLm6uio1tWQonMFgUL169TV+/ERt2rRJw4Y9oIkTX9G+fXuvuB0yMk4pNLSOOnfuqtmz52n69G904kSsJk16vVzLLtWjR29t2LBVEya8pbffft18qoCzc6VLHkkp9cwzY+Xm5iYPj6p6/PGntXbtqjJHVf39q2v9+i366qvvtX79Gv3ww0zztKt9Da5131OefmjX7k516tRFtra26tmzj+rUqaf169dccdmliouLNXPm13rooUfNX3JJJR90O3XqopYtW8vW1lYDBgxWaGidK67rpV6T77//RpUrV1L//oMueM6WLZvk4OCgRx55Qvb29qpWrbqmTPlc7dp1UFZWprZu3SIHBwf99NMCffrp/2nXrh36/POSLxOysjI1b94vuueeXlq8eLXGjfuXPv/8E23YsE4mk0mLFs3TU089I3//anJwcNDIkY+rsLBAW7duNi//8cefkq+vnypVqqzRo5/Xzp3hSktLVX5+vlxdXTVp0vtav36Lpk//WuvWrdGyZYvM26hv3/6qU6eu7O3t9fjjT5c5AvjqqxP10kvjZWtrq+TkpL8+AJ81f2lV6ptvvtSAAYPKjHJZvXqFataspUGDhsrW1la1atXW/feP0IIFc6643qX69Omnpk2by9bWVg899KgcHBy0desWHTp0QIcPH9RLL42Xs3Mlubq66Zlnxmr9+jUXnE5VWFio9957WwkJ8XryyQsD0dUYPvxhubi4yMOjqtq1u1Nx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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pair = THOR/WETH\n" - ] - }, - { - "data": { - "image/png": "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JBUUFGjgwN4ymUwyGAzmZS5ZslpGo1H79u3V22+/rtTUVN177wOaM+eHIrXl5eUpNzdXixatkLu7h86cOa0PP5ymw4cPqVq1aho58g498MDD5vnDwvZo+vTPdOrUCdWoUVO33z5K99//UJm2w7lzZ/X55x9r//4wmUwmtW7dVk899bzq1/eSJP3882zNnDmjyPszatRdeuyxJ/TCC09r//6wIq+XmZmpYcNu18SJrxW7rNGjh2nevCWqV6/+3/r9KM7cub9o3rxflJycrHr16umhh/6jPn36SSr9PSjt/T948IC+/PJjHT9+XG5utXX33fcV+T3/N9v80KGDevzxh8y9JEn+/gHmz69r9V5ZtvmcOT8oOPg3paamKCCghSZOfFWNGjUpU23Xer+//fZrhYXtKfKZei1/fb//rilT3pIkvfZa4X+3b9+iGTM+19mzsapb11Pjxz+jHj1uMs9/rfUubZtfa9kFBQX6/vuZWrZsiVJTU1SvXn09+OCj6tcvSJIUFHRTkecWFBQoOztbb775joKCbvnb633ZtfrAZDLpv/+dpC1bNsnV1U1z5y4u0udS0c/enJwczZr1ldasWanMzEy1a9dBzz77ourW9fzH9ZW3nj076vPPv9KAATdfNS08PEwvvvi01qzZbIXKyldk5DF9+eUnOno0Qvb29urUqYueeup5ubi4aPDgfkpPT1dgYOsy/579G5mZmfr44/e0Zcvvys/PU8+evfXCCy+rWrVqxc5/6NBBffLJ+zp16oRcXFz14IMPa8iQ4X9rmSXth0jSrl07NH/+b3r33Y//6SqZXeszOjs7W1999YU2blynjIx0NWrUROPGPWX+Liptu1zrc/JaQkN36IUXntZvvy0q02fiv/0MvezixYt6/PGH9NJLk676vj14cL+efvpxrV+/rcjjK1Ys1ezZs5SYmKDGjZvquecmKDCwtaTCz7gffvhWISGLlJqaqiZNmuqZZ14wTy9tf3b79i365pvpiomJUf36Xnr44bHq3fvP3/uNG9fp22+/1rlzZ1W7trvuv/8hDRlymyTp/Plz+uij97R//z5JJrVr10Fvvvm6jEYXSeW7T5mdnaXPPvtImzdvUk5Ojpo1C9BTTz0vX1+/f/xeVGaE8SuYTCZl5RWUad7zKVlKzsqTJK2KiJckrY6IV/9mHpKkWk528qzpVOLzL3Oy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mzf97ToSExM0Zcpbmj9/qWrWrClJeuGFl3X77YN0/HiU+Sjo3r27lZiYcFUdnTp1VadOXc0/t2gRqDvuuFvr1q3RPfc8oPj4C0VuhlOjRg3zcqTCm7a8/PLzSkpKVOPGTeXi4mI+Wl/aNnrjjZc1atSd5uHXJXF0dJQk9e8/UCtXLtP69WvNw4zKwtHRSY6OTho37imNHTtGKSkpmjz5jTIv22Qqftn16/954xEnJyfVquWi+Ph4tWrVpsgNlDw9PTV+/NMaO3aMMjLS5eDgoObNW5rfCz8/f40adac2bFije+65X+fOndWXX36ir7763PwaeXl5CghoroSEhD9e889gW7u2u2rXdtfp0yeVn5+vJ5541jyC4sknn9fQoUE6c+a0mjb1llR4w7o333xF6enpmjHjW/OR3v79B+rSpYt6990pSktLUdeuPdS//0Dze3bliApJuuee+7V8ecgfR2vvLHb7xcbGKCxsj15++fUijxuNRvPrXpaVlSWjsfDAiL29vW66qbd5B75t2/YaOHCQ1q9fq7Zt2yszM1Ovv/6ybGz+PDCUm5urc+fOFfn5s88+0rp1q/X++3/e68HX16/I+9OkSVONGfMfffjh1CLXFC5ZMl99+waZzzpIhV96OTk5qlfvz+1f3E5EvXpe5v+//PsTH39B586d09GjR3TLLX3M0wsKTLKxKfw8++ij99SqVRvzjvzgwcO0Zs1KLV8eoqeeeu6a74GbW+1S3//33ivsq1mzvpafn7+GDLlN8+b9+q+3ua2trT79dHqR2p59dqKGDg3S6dMnzWd3S+q9a21zqfD3q7h+qVbNWba2ttq7d7defPFp880WbW3tZDIVju4py/t95ft1+T07cSLK/H5f+Rl45fv912X7+/vJZDKYlx0fH686dYreTMzLq4H5HhVGY0nrVa1M632tbV7asi+7PIqlY8fOGjhwkNasWWk+42QymRQSskiPPvp4kYOwiYkJcnFxKbJzevlGTOvXr1WdOnWLzP/XG+2V1geXxcfHF9n2tra2qlv3z9+9J598TjNmfKYnnviPbG1tNXTocHl7+6hGjZrXrPHHH7/TTz99b378gw8+07PPTtCPP36nX375SVOmvCVfXz89++yEa569lQq/X2bM+FY//PCt/vvfSUpPT9fNN/fVM89MMH9X1qpVyzy/vb39VQeoJCkwsLXeeec9BQf/qv/7vx/l5OSkUaPu0gMPPKyOHTsrLS1NJ04c186d23TLLYOVmpqq3bt3ymQyqUuX7nJ0dFJubq7mzftFq1evlNFYTb6+vsrISDd/J0tSw4YNiyy3bl1PRUYeveY6XjZkyHCtXLlcQ4YM1/LlIVfd5Cw9PU3/+99/dfRohL78cmax10+X1ZV1GgwGeXjUUWJigsLD9+mll54t9jnPP/+ymjRpIqno79Hl/ZDiDrw7ORmVllb0r/Fc+dx/6/ffN2n69D8/f2rWrGk+Sy5J9erVU2Ji4ff6xInPFjngf1ndup7m+yCU9Bl95RDmkJBF+uyzD/XII4/prrvuk1T4WfPXdbtyu5T1e1EqvFRuypS39N//TpWzc3XzGdq/68SJwrPNa9as1H33jZEkrV69Uh99VPxZ2nff/URt2rT9R8uSSt4nrVXLxfw5+NBD/zHvXz322BNasGCeDhzYV+r+bKtWbTRp0tv67rtv9N57/1ObNm01aNBQ80gqBwcHDR58m/lmcL1791WHDp20adM6tWz55+UQlw+QPPnks1q6dLH27AlVr143/6t9yivl5eXp9ddf1vvvf2oeqfvccxN1yy19FBq6Uz179vrH27eyIoz/C67VHFS7mr3q1nDUba08tfjAecWlZsu12tXXgl0P3t4+Sk5OVlJSotzcakuSTp06oTp16pqPkq5bt0aHDh1Ur1599M47b+iLL2aaA3hiYkKROyKfPRtbZAe/rBITE8x3qb7s8hFDe/s/W2zjxvXq1avPVWdZfv99o5KSEotcB5mTk2MOwHXq1C1y5jMzM1NpaYXD1BIS4vXGGy9rypT3zb/AGzeu06ZNG0rdRmlpadq3b68OHz5ovtYoPT1dH344TRs3rtN7732iN954RS1bBurOO+81Lz83N7fIwYCSHDgQrqlT3y5yI5/c3FzZ29srIyOj1GW//vor6tKlo4YM+XO7/HXZCQnx5v/PyEhXcvIl1atXT1FRkVqzZqUef/xJ8/ubk5MrGxsb2dnZq0mTptq7t+iNbPLzC3R5f8nDo64effQx9e8/0Dw9NrZwOFNWVuGR/bi48+br00+ePKG1a1eZ57/ypiUFBYU7fZd3xo4cOaSXX35eHTp01sSJrxXZUU1MTFCXLt01atRd5sfGjh2jPn36SpK+/vpL3XxzvyLDv3Jz/+yV4mzcuE6tWrW56o6p3t4+5mFzl/v11KkT5ms/mzTxvurmKwUF+TKZTH98cTrqo/9v777DorjWP4B/QUBQIVgQYi5GJYIlKiCRGCuJGJQi2GISjRp7FxVNu7m/aDR6jQiCqEEsKLZgx4K962LBmmAQUSkqdUFAdll2fn9smLiywHKNi2a/n+fxedzZsztnZ17OnHfmzJnAUPG+XEA1fLNRI9XBRSqVYs4cf5SUyLF6daQ4izqgOqN/8+Z1tVnCVb/jr22hGhlwCj/99LNaHcrWnZKSgrZtVQnEs1edymRlZYozk5b9/djYNEHjxo3h7PweAgP/OtGSlycVr1o8fvyo3AkiIyMjMYYr2wfNmqlOtlS0/4uKilCvnjnCwyPF98PClonre5Ft/vjxI2zbtgmjRo0XO3olJarvKtuulcVeZdscUMVLcnKSOJ+BQqFAamoKWrSwE2dCXrFijfhbNm/eKA6/12Z/P/u3DKj2mY1NE/F3p6WliQnls/v72XW3bt0ajRqZIyRkhTg00drautzVvMzMxzAxUf3NNG9uhz/+UE+E7t1LFn9HZb+7qm1e1bpDQlQzOz97gqekRC4OmwRU+0zTpG2NG1tDKpWiuLhY3I/XrsXj9u3fYW1tjYyMx2rHt9OnT6CwsBAeHp5VxsGzrK3Vjz+CIKjtq8zMDAwfPgozZqiShfz8fERGrkWrVq1RUlJSYR2/+OJLtSc3AKorif36DcCoUeOQm5uLdevC8e23AYiJOQJDQ0O1q0ZSqVT8f2FhAbKyMsXh94mJt/F///ctNmxYi0mTyo+aqcijR4/QoEEDBAaGoqSkBJcuSfDtt7Nhb98KH3zQFa6unXHmzElcv34N3303FwUFT3Dy5HEUFxejf/9BAICtW6MQFydBZOQW8Zg7e7b6CbyyURtlHj5M13r2+T59vLB69QpcvChBUtIdtVn109JSMWvWVFhb22D16g3l5meprmfrqVQq8fjxI1hb26BDB0ccPHiiws8VFxfDyMgIycl3xSQnOTkZxsbGaNq0abnyLVrY4eLFC2rL7t1LFo9FLyIh4XfUr19fTHoA1W0fz8ZkamqquP3/+9+gSr+vsjYaUF3xXLJkIU6dOo4FC37Ge++5iuWaNm1W6XbRpp0sExd3Hrm5OZg5c/KfdVCtf/jwTzFs2EgMGzZCm82DH374CSkpD/Dvf89B585dYWf3Dnr39kDv3v/70xoqo2pP1edcuncvGZ07d4GtbVPUqlVLrS+tuqda1Terqs+fn5+H5s1biJPEAqo5Fcrm9GjWrLnadwN/9ftksmKMGPEZ/v3vueI8BUqlEkqlEhYWFi/cp3xWUVERnjzJF48VgOqWJQMDw9di0suXgcPUX4C1eW3sGeOKdZ87oX+HJlj3uRP2jHGFtXnFicHfyda2Kdq3d0Rw8BIUFRUiPT0N69atFu+defToIRYvXgB//9n4+uvvkZmZibVr/zqzlZ2djfXrIyCXy3Hz5nXs2bML/fqVnwiqKs2b26FJk7cQHPwziooKUVhYgGXLAtG6dVv8619/HXhu3LhabhZ2QNXYhIQE/vlYNAE3b15HdPQWcUIXb29fbNoUiXv3kiGTyRAaulQ8q19UVIjS0r/u2UtOvive+1RSUlLpNrKxscGxY+dw8OAJ8Z+1tQ1mzvxKPCC9+257REVFIinpDhQKBfbu3SXOKFkVO7uWKC4uxsqVISgpKcGjRw8RGhoET89+Wq27Xbv2CA8Pr3TdZR3+4uJiBAX9jJYtHeDg0BoWFhbYsWMbNm2KhEKhwKNHjxAWFow+fbzEs6N3795BVNR6lJaWIinpDnbs2CZ+t4+PH9avjxA79BLJeQwbNhjXrl2BlVVjvPeeK8LCgvHkyRMUFhZgxYplSEtLRfPmLeDo6IzFixdAKlUleKGhQbC3b4UWLeyQlpYKf/9J8Pb2w/ffzyvXCb569QqmTBmHR48eQiaTYdu2TXjw4L44WUxychKCg5cgOzsLcrkca9eGo7CwsNJZYq9fv6rxypKTkwveeMMSK1eGQiaTITHxD0RHbxXP7Pr6DsDp0ycQG7sfgiDg6tUrOHToIDw8+sLQ0BBeXj5YuTIEGRmPoVQqceBADIYN+wSpqaoEf8aMyahbtx5WrIhQS8QB1VX5iIhVOHToIJRKJe7eTcLatavFSaUAICnpDmSyYvEsdhljY2P06dMXwcHByMh4jIKCAvH+4GdFRKxCVlYm8vPzERoahB493FC/fn307t0Ht25dx6FDB6BQKJCVlYXZs/3FxKhr1+7YsWMbbt9OgFKpxPHjR3DlymXxcVOV7YOq9n9BwROMHz8SFy9egFKpxMWLEuzZswODBn36wtvc0tISR47E4pdfwiCTySCVShEYuAgdO3bCW2/9q8rYq2ybA6oRAtu3b0Ni4h/i49saNGgAR0dnFBYW/Dlppartv3nzBn79dbPY8dFmf//++y3s27cHCoUCZ8+extmzp+Dt3Q/Gxsbw8OiL1atXatzfz6/76tWraut2d/fA3bt3sGfPTigUCsTFXcCpUyfEz3t4eCI+/jKOHj0MhUKBo0cPIz7+stgWVPa7q9rmVa3b0dEJu3dvx9WrV6BUKnHmzCkcPXpIbRj39etX4eDQqtz+atPmXdjavo3Q0CAUFxcjJycbISFLkZubi86du0KhUCAycg1KSkqQlpaKZcsCIZPJtIqDZ3l59cOePTtx8+Z1KBQKrF8fIV5FBIBt2zZh/vwfUFRUhPz8fCxZshAODq3QunXbSuuoSWTkGixdugiFhQUwNzeHqamZeAXz7beb4/r1q8jMzIBMVoy1a38RO8VPnz5FQMA0HDp0EIIgoFEjKxgYGKpdDddGQsItzJw5BYmJf8DY2Bj166s6/GV16N69J7Zt2wRb26awtLREp06dce3aVfzxR4J4pbSwsBBGRkYwMjKGQqGa0FMiOaeWBNy6dQOxsftRWlqK8+fP4syZk1rf81u/fn188EE3LFr0I3r2/FA8OZ2fn4+pU8ejXbsOCAwMfeFEHABiYnYhIeF3lJSUYO3acAiCoPE2i+eZmprio4/csXJlCHJzc5Gbm4uVK0PQq9fHGhPLHj3ckJ2djW3bNkGhUODKlUs4dOggPD37afj26jl58pjao62AvybvlclkuH//HiIiIuDtrd26KmujASAkJBAXLpzD6tUb1BJxoOrtok07Webjj/vi6NGzYv9p/frNAID16zdrnYgDquNply7d8OGHqvlNnk9W/26enj44dOggrly5BIVCgW3bNiEnJwfdu7uhbt16cHf3QEhIIB4+TIdcLsfKlaEwN7dAx44uVfb5U1JSMG7cCCQm/vFnW34IZ8+egp/fQACAr+9A7Nz5Ky5elECpVOLEiaOIj78kbv9mzVogLGyZeOxesmQRmjVrhnffbf/CfcpnWVhYoH17R6xYEYLc3BzxuGJpaVmtEaf/JAaCoOm8xT9HZuaTqgvVMAMDoFEjc2RlPdF4FulZzz8/OCcnG4GB/0V8/CUYGBjCw8MTEyZMAaCaDbRhw0b48cdFAFTDxP39JyE4eAXS09OwdesmtGrVGseOHUHDhg3x+efDxU7Q8zOsPkvTM3FTU1OwfHkQbty4BgMDQzg7u2DKlBlqE/G4u3fD3LkL1Sb3KLNr13Zs3RqFzMwMNGjQEEOGDBXPtCuVSkRErMLu3TugUCjg4+OHfft2Y968RXB2dsGmTRuwdetGFBcXw8rKGj4+fggLC8bKlaqrExVto2eH6Jd5/tndgiBg48b12L17OwoKCvDOOy0xadI0tXvxykyePBZOTh3VHluWnHwXy5Ytwe+//4Z69eqhd+8+GDFitMaZdMs/N1zAzp1bEBW1SeO6Bw70hptbL5w+fQJSqRROTs6YMWOOeAY8Pv4yVq1ajrt3k2BiYoJevXpjwoSpYqf91q2bCAsLRlLSHZiamsLXdwCGDx/150Rbpdi6NQp79uxCdnYWrKys8Omnw8T4yM3NRWjoUly8KEFpqQJdunTHtGkzUbduPRQUqJLzc+fOoLCwEM7OHTFjxhw0bmyNoKDFiI7eWm50RNlMrYDq/u7du3f8OeTWAVOnzhCvwubn5yE0NAjnz59FcfFTtG7dFlOnzhSvAGuacXjYsMHo33+weEB6VmpqCgIDF+G3327CzEz1nPGyoWqAahK0iIhVePDgPiwtLfHZZ1+IIzhkMhnWrPkFx44dRl5eHpo0eQujRo1Ft249cfLkMXz77WyYmNRGrVrq5zw3bPgVNjY2OHnyGNauXY20tBTUq2cOb29fjBgxWhwufvz4EQQG/hd796rfPwsAcrkM4eGhiImJQa1aRhg0aAjCw1eoPWd85Mgx2LdvD2SyYnzwQTdMnToT5ubmAFTPP12xIgR37yahVq1a+OCDruL+K0s4Dh7ch/z8PPzrX00xduxEuLp21mofVLb/AVXn8JdfwpCR8Rg2Nm9ixIjRapPg/K/bHFA95zQ0dCkSEn4HAHTp0hXTps2ChcUbWsVeZdtcEARs2RKFHTt+hVSai9at22DWrK/RtOnbEAQBoaFBOHgwBqWlSjRp0gS9enlg1apQ7Ny5Hw0aNKx0f0dErMLNm9dhamqKS5fi8OabTTB27CRxtI9MJkNIyFIcORILIyP1/W1j86a4bqVSCVtbW7i5uWPlyr/WffnyRYSELEVKyn04OLSGlZUVTExqi38nEsl5rFgRgrS0VHH4YefOXav83VVtcwBVrjsmZjc2blyP3Nxs2Nq+jTFjJoixBqgmK5RKpeKs3c9KT0/DsmVLcOPGNdSqZQR3dw9MmDAFRkZGSEy8jZAQ1RMDzMzM4Oc3CMOGjagyDjQ9f1g1bHsDnjx5Aje3j3D7dgI++eQz9O3rjcLCAixe/BPi4lRXNl1dO2P69FliAltZHZ+XlZWFJUsW4tq1eJSUlKBVq9bw9w9Aixaqod4LF/6Iy5fjYGxsgsGDP8WOHb/im2/+A2dnF5w5cwrh4apje+3atfHRR+6YPNkfxsbGas8Zz8p6gn379mLNml8QHb233LF+w4a12LVrO/LypKhfvyE+/3wYfH1VbWdhYQG8vNwxZMhQ8bnPQ4b4wda2KRYvVp0gys/Pw48//h+uXr0CExMT2Nu3wttvN8Ply3GIjNyKiIhVOHPmJN56yxaXLsWhYcOGGD16fLUeVxcXdwEzZkxW6wtt2bIRoaFBMDU1LTcPT9mj257tu2gzm7qlZX1kZDzGvXvJsLd3gL//bK2HvRcVFSIkJAhnz55CSUkJunXrAX//2WLcDR06GL17e4ijIxISfkNw8M9ISkqCpaUlRowYLfYFymZvLzt2VOb5fsjQoYOwcGGg+MSJsv09bNhI7N+/BwDw2WefYfDgYTAw0O76XEVttFQqhY9Pbxgalr/CGRDwDXr37lPldqmsnaxsn2n6u42MXINDhw6K7Xtl5Z88eYJhwwbDw8MT48dP1mo7lHm+X16mon50bOx+rF8fgczMDDRr1gLTpweIIwXkcjnWrPkFR48eglQq/bMNmC2OkqiqP7trVzSioiIhlUrx9tvNMH78ZLi4dBLXfeBADDZv3oCHDx/CxsYGo0dPEE/WPHnyBKGhS3H27GkYGBjAxeU9fP/9dzA0NIMgvFif8vkYzsnJxvLlwbh4UQKFQoG2bd/FlCkzxOPKP4mVlXmVZZiMvwJeJBmnf67qxAXpF8YGacK4oIq8KrGh6WT+q7huTSfXa9J//vMNpk8P0Pg0m+p4PkF8VeLiZRAEAf7+kxAUFFZ1YSrnnxwbuqRNMs5h6kREREREryDVPfXWL5yI65tTp46XmzCY6FXECdxeQ7NmTYOra2eNkwwRERERvW48PT8qNznYs7QZpl3ZdxcWFmqcD+JV9+abTTQ+vpIq16PHhzVdBSKtcJj6K4BDQUgTxgVVhLFBmjAuqCKMDdKEcUEVYWz8PThMnYiIiIiIiOgVxGSciIiIiIiISMeYjBMRERERERHpGJNxIiIiIiIiIh1jMk5ERERERESkY0zGiYiIiIiIiHSMyTgRERERERGRjr2WyXh2djYmTpwIFxcXuLq6Yv78+VAoFDVdLSIiIiIiIiKtvJbJ+PTp01GnTh2cPn0a0dHROH/+PNatW1fT1SIiIiIiIiLSymuXjN+/fx9xcXEICAiAmZkZbG1tMXHiRERFRdV01YiIiIiIiIi0YlTTFaiuxMREWFpawtraWlxmZ2eH9PR05Ofnw8LCotxnDAx0WcPqK6vfq15P0i3GBVWEsUGaMC6oIowN0oRxQRVhbOjOa5eMFxYWwszMTG1Z2euioqJyybiVlbnO6vaiGjZ8fepKusO4oIowNkgTxgVVhLFBmjAuqCKMjZfvtRumXqdOHTx9+lRtWdnrunXr1kSViIiIiIiIiKrltUvGW7ZsCalUiqysLHFZUlISbGxsYG7OszdERERERET06nvtkvFmzZqhY8eOWLBgAQoKCpCSkoKwsDAMHDiwpqtGREREREREpBUDQRCEmq5EdWVlZWHu3LmQSCQwNDSEr68vZs2ahVq1atV01YiIiIiIiIiq9NpdGQeARo0aYdmyZZBIJDh//jzmzJnzyifi2dnZmDhxIlxcXODq6or58+dDoVBoLHvy5El4e3vD0dERffr0wfHjx3VcW9KV6sTF6NGj0a5dOzg5OYn/Tp06peMak67l5OTA3d0dEomkwjJsM/SPNnHBNkO/JCQkYOTIkejUqRO6dOmC2bNnIycnR2NZthn6ozpxwTZDv5w/fx6DBg2Cs7MzunTpgnnz5qG4uFhjWbYZL5FAOjF06FBh5syZQlFRkfDgwQPB09NTCA8PL1cuOTlZaNeunXD48GGhpKRE2Ldvn9C+fXvh0aNHNVBretm0jQtBEARXV1dBIpHouIZUky5duiT06tVLsLe3Fy5cuKCxDNsM/aNNXAgC2wx98vTpU6FLly5CcHCwIJPJhJycHGHMmDHCuHHjypVlm6E/qhMXgsA2Q59kZ2cL7dq1E7Zv3y6UlpYKjx8/Fry8vITg4OByZdlmvFyv5ZXx1839+/cRFxeHgIAAmJmZwdbWFhMnTkRUVFS5sjt37oSLiwt69eoFIyMj9O3bF++99x62bt1aAzWnl6k6cZGSkoK8vDy0adOmBmpKNWHnzp2YNWsW/P39qyzHNkN/aBsXbDP0S3p6Olq1aoVJkybBxMQE9evXxyeffIKLFy+WK8s2Q39UJy7YZuiXBg0a4Ny5c+jfvz8MDAwglUohk8nQoEGDcmXZZrxcTMZ1IDExEZaWlrC2thaX2dnZIT09Hfn5+Wpl79y5A3t7e7Vl77zzDhISEnRSV9Kd6sTFjRs3ULduXfj7++P999+Hl5cXoqOjdV1l0qGuXbvi8OHD6Nu3b6Xl2GboF23jgm2GfmnRogVWr16tdstebGws2rZtW64s2wz9UZ24YJuhf+rVqwcA6NGjB7y9vWFlZYX+/fuXK8c24+UyqukK6IPCwkKYmZmpLSt7XVRUBAsLi0rLmpqaoqio6OVXlHSqOnEhl8vh6OgIf39/tGzZEhKJBFOmTEHdunXRp08fndabdMPKykqrcmwz9Iu2ccE2Q38JgoCgoCAcP34cGzduLPc+2wz9VFVcsM3QX4cOHUJeXh5mzZqFqVOnYvXq1Wrvs814uZiM60CdOnXw9OlTtWVlr+vWrau23MzMrNzkCcXFxeXK0euvOnHh6+sLX19f8XXXrl3h6+uLAwcO8CCp59hmkCZsM/RTQUEBvv76a9y6dQsbN26Eg4NDuTJsM/SPNnHBNkN/mZqawtTUFAEBARg0aBDy8vLwxhtviO+zzXi5OExdB1q2bAmpVIqsrCxxWVJSEmxsbGBubq5W1t7eHomJiWrL7ty5g5YtW+qkrqQ71YmL6OhoHDhwQG2ZXC5H7dq1dVJXenWxzSBN2GbonwcPHmDAgAEoKChAdHS0xoQLYJuhb7SNC7YZ+uXKlSvw8PCAXC4Xl8nlchgbG5e7Cs424+ViMq4DzZo1Q8eOHbFgwQIUFBQgJSUFYWFhGDhwYLmyPj4+iIuLw/79+6FQKLB//37ExcWhX79+NVBzepmqExcFBQWYN28efvvtNyiVSpw4cQIxMTH45JNPaqDm9Cphm0GasM3QL3l5eRg+fDicnZ0RERGhcRKmMmwz9Ed14oJthn5xcHBAcXExlixZArlcjrS0NCxatAgDBw6EiYmJWlm2GS9ZTU/nri8yMzOFKVOmCJ06dRLef/99YeHChYJCoRAEQRAcHR2F3bt3i2VPnTol+Pj4CI6OjoKnp6dw4sSJmqo2vWTaxoVSqRSWL18uuLm5Ce3btxc8PT2FAwcO1GTVSYeef4QV2wwShMrjgm2GflmzZo1gb28vdOjQQXB0dFT7JwhsM/RVdeKCbYb+SUxMFEaOHCm4uLgIbm5uQmBgoCCTyQRBYJuhSwaCIAg1fUKAiIiIiIiISJ9wmDoRERERERGRjjEZJyIiIiIiItIxJuNEREREREREOsZknIiIiIiIiEjHmIwTERERERER6RiTcSIiIiIiIiIdYzJOREREREREei0nJwfu7u6QSCRafyY2NhZeXl5wdHSEu7s7oqOjq7VOo+pWkoiIiIiIiOif4vLly/jqq6/w4MEDrT9z4cIFfPXVVwgKCkL37t0hkUgwZswY2Nvbo3379lp9B5NxIiKif4jvv/8ee/fuBQAoFAqUlJTAzMxMfH/06NHYvn07jh07Vu6zH374ISZPnoz+/fsDAORyOdatW4e9e/ciJSUFtWvXRps2bfDFF1/Azc1N/NxXX32FvXv3wsTERFymVCpha2uL8ePHw8vL62X9XCIiohe2c+dOLFu2DAEBAfD391d779y5cwgMDMS9e/dgbW2NcePGwcfHBwCwbt06fPHFF+jRowcA4P3338f27dvRuHFjrdfNYepERET/EHPnzkV8fDzi4+Pxww8/oEmTJuLr+Ph4vPnmm1p9j1wux6hRoxATE4NvvvkGcXFxOHnyJHx8fDBnzhwsX75crby3t7faeiQSCT7++GMEBAQgOTn5ZfxUIiKiv0XXrl1x+PBh9O3bV215QkICJkyYgLFjx0IikWDevHlYsGABTp8+DQC4fv06LC0tMXbsWLi6uqJfv3548OABLC0ttV43k3EiIiJSs3nzZiQmJmLjxo3o3LkzTExMYGpqCj8/PyxZsgQhISFITEys8POmpqb48ssvoVQqcfv2bR3WnIiIqHqsrKxgZFR+wPiWLVvw0UcfoXfv3qhVqxacnZ0xePBgREVFAQDy8vIQERGBCRMm4OzZs5g0aRL8/f1x7do1rdfNYepERER6JD09HS4uLuWWFxQUiP8/cuQI3NzcYGFhUa5ct27dYGNjg9jYWLRs2VLjOgoKCrBy5UqYm5vD2dn576s8ERGRjqSlpeHChQtqx8zS0lI0bdoUAGBiYoIBAwbAyckJANC7d2907twZsbGx6NChg1brYDJORESkR5o0aVLhPeNlMjIyxM6FJo0bN0ZGRob4OiYmBkeOHEFpaSlKSkpQp04ddO/eHZs3b67WvXNERESvChsbG/j5+WHu3LnisoyMDAiCAACws7ODXC5X+0xpaan4vjY4TJ2IiIjUWFlZIS0trcL3U1NT1ZJsLy8vXLp0CfHx8eL95Pb29hVeOSciInrVDRw4EDExMThz5gyUSiXu3buHoUOHYs2aNQCATz/9FJs3b8a5c+egVCoRGxsLiURSrYlLeWWciIiI1Hh4eCA4OBgZGRnlrmwfO3YM2dnZcHd31/jZHj16YPHixRg/fjwaNGiAgQMH6qLKREREf6sOHTogMDAQgYGBmDZtGszMzODl5YUZM2YAAAYMGABDQ0P89NNPSE1NxVtvvYWlS5eibdu2Wq+DyTgRERGpGTJkCI4ePYpRo0bhu+++g5OTE2QyGQ4fPoxFixZhwoQJcHBwqPDzPXr0wJdffol58+bByckJdnZ2Oqw9ERHR/+b5SUd79uyJnj17Vljez88Pfn5+//P6mIwTERGRGiMjI4SHhyMyMhILFixASkoKjIyM0KZNG8yfPx+9evWq8jumT5+O8+fPY9asWdi6davac8iJiIgIMBCqc4c5EREREREREb0wTuBGREREREREpGNMxomIiIiIiIh0jMk4ERERERERkY4xGSciIiIiIiLSMSbjRERERERERDrGZJyIiIiIiIhIx5iMExEREREREekYk3EiIiIiIiIiHWMyTkRERERERKRjTMaJiIiIiIiIdIzJOBEREREREZGO/T9jlWusc2oedAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CCb = CurveContainer.from_dicts(curves_as_dicts[1:])\n", - "CCb += c0b\n", - "CCb.plot()" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "6af20d3c-31b9-4cd9-b0d2-3330db62f477", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-652.6406125426292, time=0.00032901763916015625, method='margp', targettkn='USDC-eB48', p_optimal_t=(2371.0092981594016, 0.36299997803167794), dtokens_t=(-5.344651299310499e-08, -0.000662557315081358), tokens_t=('WETH-6Cc2', 'THOR-8044'), errormsg=None)" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCb)\n", - "r = O.optimize(\"USDC-eB48\", params=dict(verbose=False, debug=False))\n", - "#O.optimize(\"USDC\", params=dict(verbose=True, debug=True))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "7d826afa-4a83-4cde-9a80-5ddab19e7079", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'WETH-6Cc2': -5.344651299310499e-08,\n", - " 'THOR-8044': -0.000662557315081358,\n", - " 'USDC-eB48': -652.6406125426292}" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r.dtokens" - ] - }, - { - "cell_type": "markdown", - "id": "683b1fb3", - "metadata": {}, - "source": [ - "#### Absolute convergence criteria" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "217039b4", - "metadata": {}, - "outputs": [], - "source": [ - "#O.optimize(\"USDC-eB48\", result=O.MO_PSTART)" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "8c899d9e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-652.6407370194793, time=0.0014028549194335938, method='margp', targettkn='USDC-eB48', p_optimal_t=(2371.009298148487, 0.36299997803167794), dtokens_t=(-3.240074875066057e-12, -0.0006687440909445286), tokens_t=('WETH-6Cc2', 'THOR-8044'), errormsg=None)" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pstart = {'WETH-6Cc2': 2373.231732603511, 'THOR-8044': 0.36299996370000637, 'USDC-eB48': 1, \"USD\": 1}\n", - "params = dict(norm=O.MO_NORMLINF, epsa=10, epsaunit=\"USD\")\n", - "r = O.optimize(\"USDC-eB48\", mode=O.MO_MODE_ABS, pstart=pstart, params=dict(verbose=False, debug=False))\n", - "#O.optimize(\"USDC-eB48\", params=dict(verbose=True, debug=True, **params))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "5e448a06-61fd-4096-8c28-0c822653c85c", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1" - ] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/Optimizer_2312_THOR.py b/resources/NBTest/Optimizer_2312_THOR.py deleted file mode 100644 index 0ed364531..000000000 --- a/resources/NBTest/Optimizer_2312_THOR.py +++ /dev/null @@ -1,291 +0,0 @@ -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -from tools.curves import ConstantProductCurve as CPC, CurveContainer, T, CPCInverter, Pair -from tools.optimizer import CPCArbOptimizer, F, MargPOptimizer, PairOptimizer -from tools.analyzer import CPCAnalyzer - -import numpy as np -import matplotlib.pyplot as plt - -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(Pair)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPCArbOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(PairOptimizer)) - -plt.style.use('seaborn-v0_8-dark') -plt.rcParams['figure.figsize'] = [12,6] -# - - -# # Optimizer Testing (Thor, Dec 2023) -# _202312a-THOR-8044 Triangle_ -# -# **IMPORTANT NOTE** -# -# For the above imports to work, you must create a symlink to the `tools` module here, running -# -# ln -s ../../fastlane_bot/tools tools -# -# Don't forget to add a local `.gitignore` file in this case! - -# ## Reading input data -# -# Set `curves_as_dicts` to the output of `CPCContainer.as_dicts`. The use `CPCContainer.from_dicts` to recreate a container. - -curves_as_dicts = [{'k': 4.3078885616238194e+24, - 'x': 1250505254484.4102, - 'x_act': 0, - 'y_act': 344491.8061533139, - 'alpha': 0.5, - 'pair': 'USDC-eB48/THOR-8044', - 'cid': '74181555988764585035015664420125470098056-1', - 'fee': 2000.0, - 'descr': 'carbon_v1 THOR-8044/USDC-eB48 2000', - 'constr': 'carb', - 'params': {'exchange': 'carbon_v1', - 'tknx_dec': 18, - 'tkny_dec': 6, - 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044', - 'tkny_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - 'blocklud': 18758319, - 'y': 344491.8061533139, - 'yint': 344491.8061533139, - 'A': 0, - 'B': 1.659765242784964, - 'pa': 2.754820936639097, - 'pb': 2.754820936639097}}, - {'k': 1106096356.8039548, - 'x': 2619874.8519412754, - 'x_act': 2619874.8519412754, - 'y_act': 422.1943487049999, - 'alpha': 0.5, - 'pair': 'THOR-8044/WETH-6Cc2', - 'cid': '0xbf1875da0431343b56ec6295f706e257dbe85696e5270a5bdad005d37cc2fd9c', - 'fee': 0.003, - 'descr': 'sushiswap_v2 THOR-8044/WETH-6Cc2 0.003', - 'constr': 'uv2', - 'params': {'exchange': 'sushiswap_v2', - 'tknx_dec': 18, - 'tkny_dec': 18, - 'tknx_addr': '0xa5f2211B9b8170F694421f2046281775E8468044', - 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - 'blocklud': 18758340}}, - {'k': 1233376864385.0625, - 'x': 54102579.539405, - 'x_act': 54102579.539405, - 'y_act': 22797.00662861641, - 'alpha': 0.5, - 'pair': 'USDC-eB48/WETH-6Cc2', - 'cid': '0x68bd2250b4b44996e193e9e001f74a5e5a31b31fbd0bb7df34c66eb8da7e6be2', - 'fee': 3000.0, - 'descr': 'uniswap_v2 USDC-eB48/WETH-6Cc2 0.003', - 'constr': 'uv2', - 'params': {'exchange': 'uniswap_v2', - 'tknx_dec': 6, - 'tkny_dec': 18, - 'tknx_addr': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - 'tkny_addr': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - 'blocklud': 18758413}}] - -CC = CurveContainer.from_dicts(curves_as_dicts) -len(CC), len(curves_as_dicts) - -# ## Analyzis and visualization -# -# Note: THOR-8044 ~ 30c - -# ### Visualization - -CC.plot() - -# ### Analysis - -sgn = [1,-1,-1] -price = dict() -quote = dict() -for c,s in zip(CC, sgn): - price[c.pair] = c.p - quotep = f"{c.tkny} per {c.tknx}" if s > 0 else f"{c.tknx} per {c.tkny}" - print(f"{c.pair} {s} {(c.p)**s} {quotep}") - -price - -# ### Carbon curve -# -# Below is the Carbon curve. It **sells THOR** and **buys USDC** at a rate of **0.36 USDC per THOR** (ignoring fees). - -p0 = 1/(price["USDC-eB48/THOR-8044"]) -p0 - -print(CC[0].description()) - -# Ignoring slippage and fees, it is possible to buy and sell THOR AT 0.38 USDC per THOR via the two provided curves. - -p1 = 1/(price["USDC-eB48/WETH-6Cc2"] / price["THOR-8044/WETH-6Cc2"]) -p1 - -# That's an arbitrage opportunity (Buy THOR against USDC on Carbon, sell into the arb) of about 5% meaning that at least in small size (ie before slippage) it should work - -p1/p0-1 - -# ### Triangle curves -# -# The triangle curves are the following -# -# - **THOR/WETH** has 422 ETH and 2.6m THOR at a price of 6205 THOR per ETH -# - **WETH/USDC** has 23k ETH and 50m USDC at a price of 2373 USDC per ETH -# -# The implied **THOR** price is 0.382 USDC (memo: on Carbon it is 0.362, and the THOR loading is 344k, ie ~15% of the THOR-8044 available on the arb curve) - -p1, p0, p1/p0-1, 344/2600 - -print(CC[1].description()) - -1/0.0001611505787737007 - -print(CC[2].description()) - -1/0.00042136635300378734 - -# ## Optimizer - -# + -#help(MargPOptimizer.optimize) -# - - -# ### Raw run -# -# This is the actual run, using USDC as the arbitrage token. This run does not converge; rather the THOR-8044/USDC-eB48 price oscillates between 0.38ish and 0.29ish. Note that this is way out of the (imputed) price range for the Carbon range which is very tightly centered around `p0~0.36` -# -# (uncomment the below code to see the debug run) - -# Note: this section of the code no longer runs as the price estimates cannnot be found; this could be related to the fact that we moved from `ticker-shortaddr` to `address`. It does not really matter though, the code in the following sections is enough. - -O = MargPOptimizer(CC) -r = O.optimize("USDC-eB48", result=O.MO_DEBUG, params=dict(debug_pe=True)) -r - -O = MargPOptimizer(CC) -try: - r = O.optimize("USDC-eB48", params=dict(verbose=False, debug=False)) -except Exception as e: - print(e) - r = None -#O.optimize("USDC", params=dict(verbose=True, debug=True)) -r - -# + -#r = O.optimize("USDC", params=dict(verbose=True, debug=True)) -#r -# - - -# ### Better prices estimates -# -# We set the initial price for THOR/USD squat into the Carbon range to see whether this works better. -# -# TLDR -- it does not. - -price_est = { - "USDC-eB48": 1, - "WETH-6Cc2": 2373.2, - "THOR-8044": p0, -} -price_est - -O = MargPOptimizer(CC) -r = O.optimize("USDC-eB48", params=dict(pstart=price_est, verbose=False, debug=False)) -#O.optimize("USDC", params=dict(pstart=price_est, verbose=True, debug=True)) -r - -# #### Tighter Jacobian -# -# Currently the jacobian h is set to 1e-5 and `minrw` in the data provided is set to 1e-7 meaning that the Jacobian calculation goes outside the concentrated liquidity area and is therefore much too steep. -# -# We'll try 1e-8 as `jach` here. Turns out this works and it even converges. - -CC[0].p_max/CC[0].p_min-1 - -O = MargPOptimizer(CC) -r = O.optimize("USDC-eB48", params=dict(pstart=price_est, verbose=False, debug=False, jach=1e-8)) -#O.optimize("USDC", params=dict(pstart=price_est, verbose=True, debug=True)) -r - -# + -# CCr.plot() - -# + -# O = MargPOptimizer(CCr) -# r = O.optimize("USDC-eB48", params=dict(verbose=False, debug=False)) -# O.optimize("USDC-eB48", params=dict(verbose=True, debug=True)) -# r - -# + -# p2 = r.p_optimal["THOR-8044"] -# p2 - -# + -# p2/p0-1 - -# + -# r.dtokens -# - - -# #### Absolute convergence criteria - -# + -#O.optimize("USDC-eB48", result=O.MO_PSTART) -# - - -pstart = {'WETH-6Cc2': 2373.231732603511, 'THOR-8044': 0.36299996370000637, 'USDC-eB48': 1, "USD": 1} -params = dict(norm=O.MO_NORMLINF, epsa=10, epsaunit="USD", pstart=pstart) -r = O.optimize("USDC-eB48", mode=O.MO_MODE_ABS, params=dict(verbose=False, debug=False, **params)) -#r = O.optimize("USDC-eB48", params=dict(verbose=True, debug=True, **params)) -r - -# ### Removing the Carbon curve -# -# Here we check how it converges if we remove the Carbon curve and replace it with a constant product curve of the same (virtual) capacity. Unsurprisingly it does and all dtokens are zero. - -c0 = CC[0] -c0b = CPC.from_xy(x=c0.x, y=c0.y, pair=c0.pair) -c0b - -CCb = CurveContainer.from_dicts(curves_as_dicts[1:]) -CCb += c0b -CCb.plot() - -O = MargPOptimizer(CCb) -r = O.optimize("USDC-eB48", params=dict(verbose=False, debug=False)) -#O.optimize("USDC", params=dict(verbose=True, debug=True)) -r - -r.dtokens - - -# #### Absolute convergence criteria - -# + -#O.optimize("USDC-eB48", result=O.MO_PSTART) -# - - -pstart = {'WETH-6Cc2': 2373.231732603511, 'THOR-8044': 0.36299996370000637, 'USDC-eB48': 1, "USD": 1} -params = dict(norm=O.MO_NORMLINF, epsa=10, epsaunit="USD") -r = O.optimize("USDC-eB48", mode=O.MO_MODE_ABS, pstart=pstart, params=dict(verbose=False, debug=False)) -#O.optimize("USDC-eB48", params=dict(verbose=True, debug=True, **params)) -r - -1 diff --git a/resources/NBTest/Optimizer_2405_SEI.ipynb b/resources/NBTest/Optimizer_2405_SEI.ipynb deleted file mode 100644 index 8444353c6..000000000 --- a/resources/NBTest/Optimizer_2405_SEI.ipynb +++ /dev/null @@ -1,1140 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "7c4e7ad0-9280-41ee-85b2-f4461058398b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SimplePair v2.2 (30/Apr/2024)\n", - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "CurveContainer v4.0-beta1 (04/May/2024)\n", - "CPCArbOptimizer v5.2 (03/May/2024)\n", - "PairOptimizer v6.0.2 (03/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n" - ] - } - ], - "source": [ - "from tools.curves import ConstantProductCurve, CurveContainer, SimplePair\n", - "from tools.optimizer import CPCArbOptimizer, PairOptimizer, MargPOptimizer\n", - "CPC = ConstantProductCurve\n", - "\n", - "import pandas as pd\n", - "\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(SimplePair))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveContainer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPCArbOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))" - ] - }, - { - "cell_type": "markdown", - "id": "7f38c5d2-6f6e-402c-b1a5-0fa00cf88f9a", - "metadata": { - "tags": [] - }, - "source": [ - "### >> Enter curves\n" - ] - }, - { - "cell_type": "markdown", - "id": "3dba2d86-b804-4d51-aa2b-7d53ebd49b7d", - "metadata": {}, - "source": [ - "`CurvesRaw1` is the original curve set exhibiting the convergence problem" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "5c244d95-da00-449f-a879-ace4b5523a22", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CurvesRaw1 = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - " ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n", - " ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}),\n", - " ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}),\n", - " ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}),\n", - " ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352})\n", - "]\n", - "CCRaw1 = CurveContainer(CurvesRaw1)" - ] - }, - { - "cell_type": "markdown", - "id": "2163489b-5228-457f-85ee-9813cc66d01f", - "metadata": {}, - "source": [ - "`CurvesRaw2` is a modified curve set designed to address the problem. On those the algo should converge without issue." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "ce07977c-37b2-4923-a669-68cd65d95b4d", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CurvesRaw2 = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6673a1e11aed37f08479f05b6f8e492eea344f4b21fa5cdfc2abb58d0a0339f6-0', fee=2000.0, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'tknx_dec': 18, 'tkny_dec': 18, 'tknx_addr': '0x514910771AF9Ca656af840dff83E8264EcF986CA', 'tkny_addr': '0x8E870D67F660D95d5be530380D0eC0bd388289E1', 'blocklud': 19764257, 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997, 'minrw': 1e-06}), \n", - " ConstantProductCurve(k=14269669.033092778, x=57121.7742265515, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', cid='0x4ffa6a02bd60761adfa89906bf3aa7dbcc862702c1f19385ac1663b0e7222432-0', fee=2000.0, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'tknx_dec': 18, 'tkny_dec': 18, 'tknx_addr': '0x514910771AF9Ca656af840dff83E8264EcF986CA', 'tkny_addr': '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', 'blocklud': 19764256, 'y': 5.0, 'yint': 8.529145462309762, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756, 'minrw': 1e-06}), \n", - " ConstantProductCurve(k=14203024.226426456, x=249.22733623585125, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x4ffa6a02bd60761adfa89906bf3aa7dbcc862702c1f19385ac1663b0e7222432-1', fee=2000.0, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'tknx_dec': 18, 'tkny_dec': 18, 'tknx_addr': '0x514910771AF9Ca656af840dff83E8264EcF986CA', 'tkny_addr': '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', 'blocklud': 19764256, 'y': 807.9145301701096, 'yint': 1957.3030953877023, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211, 'minrw': 1e-06}), \n", - " ConstantProductCurve(k=55713831.26523774, x=131.16846526787972, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0xd53681c4f9860ae4353eda47246af69840efbc971f62fa2e30a8426145345f0b-0', fee=2000.0, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'tknx_dec': 18, 'tkny_dec': 18, 'tknx_addr': '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', 'tkny_addr': '0x8E870D67F660D95d5be530380D0eC0bd388289E1', 'blocklud': 19764263, 'y': 15920.776548455418, 'yint': 32646.46821984497, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854, 'minrw': 1e-06}), \n", - " ConstantProductCurve(k=55692277.270269215, x=424668.0260493125, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', cid='0xd53681c4f9860ae4353eda47246af69840efbc971f62fa2e30a8426145345f0b-1', fee=2000.0, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'tknx_dec': 18, 'tkny_dec': 18, 'tknx_addr': '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', 'tkny_addr': '0x8E870D67F660D95d5be530380D0eC0bd388289E1', 'blocklud': 19764263, 'y': 5.0, 'yint': 10.072969792409115, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352, 'minrw': 1e-06})\n", - "]\n", - "CCRaw2 = CurveContainer(CurvesRaw2)" - ] - }, - { - "cell_type": "markdown", - "id": "961f17f5-6286-4f4c-8bc3-9721811b50b1", - "metadata": {}, - "source": [ - "### >> Enter prices" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "5fc55588-ec8b-4bdc-9482-4fc97d909c2e", - "metadata": {}, - "outputs": [], - "source": [ - "PRICES_RAW = {\n", - " '0x8E870D67F660D95d5be530380D0eC0bd388289E1': 0.0003087360213944532, \n", - " '0x514910771AF9Ca656af840dff83E8264EcF986CA': 0.004372219704179475,\n", - " '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2': 1,\n", - " #'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 1,\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "90127233-847b-4719-8f45-76638e5776d7", - "metadata": {}, - "source": [ - "### >> Enter tokens\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "747c1dbf-d821-4214-8aa6-c1412bffeb50", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "TOKENS = {\n", - " \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\": \"ETH\",\n", - " #\"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\": \"ETH\",\n", - " \"0x514910771AF9Ca656af840dff83E8264EcF986CA\": \"LINK\",\n", - " \"0x8E870D67F660D95d5be530380D0eC0bd388289E1\": \"USDP\",\n", - "}\n", - "\n", - "TARGET_TOKEN_RAW = list(TOKENS)[0]\n", - "TARGET_TOKEN_RAW" - ] - }, - { - "cell_type": "markdown", - "id": "8bba7e8a-dbf8-4a89-9ee8-686afbef9901", - "metadata": {}, - "source": [ - "### >>> Run optimizer\n", - "\n", - "this run diverges (see the excessive result, 8.69 ETH)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "a49a49f8-b3e4-49c4-b991-c3cd8a123658", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "8.693167770410668\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=8.693167770410668, time=0.0033130645751953125, method='margp', targettkn='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', p_optimal_t=(1.1199678720803443e+103, 9.79483400374927e+104), dtokens_t=(-14810.776548455411, -863.4145301701064), tokens_t=('0x8E870D67F660D95d5be530380D0eC0bd388289E1', '0x514910771AF9Ca656af840dff83E8264EcF986CA'), errormsg=None)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCRaw1)\n", - "r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW))\n", - "print(r.result)\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "ee874a6e-db07-440a-9acc-0223752214ad", - "metadata": {}, - "source": [ - "for reference, one the second curve set it converges (see result, 0.047 ETH)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "828c302d-1753-4104-a80d-4a1bc77bfcc3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "-0.047419352862874575\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-0.047419352862874575, time=0.0008058547973632812, method='margp', targettkn='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', p_optimal_t=(0.00030626007218662943, 0.004390730744944804), dtokens_t=(1.5752448234707117e-09, 8.185452315956354e-11), tokens_t=('0x8E870D67F660D95d5be530380D0eC0bd388289E1', '0x514910771AF9Ca656af840dff83E8264EcF986CA'), errormsg=None)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCRaw2)\n", - "r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW))\n", - "print(r.result)\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "2659688e-c3f0-40b0-a6f4-84e81ebe8f78", - "metadata": {}, - "source": [ - "This code runs with a wider Jacobian (`jach=...`). It converges." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "236e3890-7a87-4cec-a93a-f56a095f72c8", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "-0.047176345331450875\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-0.047176345331450875, time=0.0008869171142578125, method='margp', targettkn='0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', p_optimal_t=(0.00030619796931423594, 0.0043916331358292504), dtokens_t=(0.0004883671354036778, 9.577247283232282e-06), tokens_t=('0x8E870D67F660D95d5be530380D0eC0bd388289E1', '0x514910771AF9Ca656af840dff83E8264EcF986CA'), errormsg=None)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCRaw1)\n", - "r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW, jach=0.001))\n", - "print(r.result)\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "f4844ce6-dffa-4d79-b631-6b5fa8ff17a2", - "metadata": {}, - "source": [ - "### >>> Preprocessing" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "b1a6af0f-89b0-443d-81cb-fcfea6722441", - "metadata": {}, - "outputs": [], - "source": [ - "def replace_tokens(dct):\n", - " \"\"\"replaces the token address with the token name in dct\"\"\"\n", - " tkns = dct[\"pair\"].split(\"/\")\n", - " for i in range(len(tkns)):\n", - " #tkns[i] = TOKENS.get(tkns[i]) or tkns[i]\n", - " tkns[i] = TOKENS[tkns[i]]\n", - " dct[\"pair\"] = \"/\".join(tkns)\n", - " return dct" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "f7651ba3-2fb2-444f-9971-779326ae4758", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'USDP': 0.0003087360213944532, 'LINK': 0.004372219704179475, 'ETH': 1}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC1 = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw1.asdicts()])\n", - "CC2 = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw2.asdicts()])\n", - "PRICES = {TOKENS[addr]:price for addr, price in PRICES_RAW.items()}\n", - "TARGET_TOKEN = TOKENS[TARGET_TOKEN_RAW]\n", - "PRICES" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "c7ce8e24-8ee6-48c0-bccd-0d268873128c", - "metadata": {}, - "outputs": [], - "source": [ - "def p(pair=None, *, tknb=None, tknq=None, prices=None):\n", - " \"price of tknb in terms of tknq\"\n", - " if not pair is None:\n", - " tknb, tknq = pair.split(\"/\")\n", - " p = prices or PRICES\n", - " return p[tknb]/p[tknq]" - ] - }, - { - "cell_type": "markdown", - "id": "9906cde3-7c6b-47dd-b322-c342189281d9", - "metadata": {}, - "source": [ - "The code below ensures that in ETH/LINK, LINK is the quote token and ETH the base token (for better price displays)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "9366ca04-201c-448d-8db3-62b17946fdd9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "SimplePair.NUMERAIRE_TOKENS[\"LINK\"] = SimplePair.NUMERAIRE_TOKENS[\"ETH\"] - 1\n", - "#SimplePair.NUMERAIRE_TOKENS" - ] - }, - { - "cell_type": "markdown", - "id": "f8d51655-c7d6-4966-ad44-e002dc4aca62", - "metadata": {}, - "source": [ - "## Curves" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "85bf7a11-3c89-4daa-885f-b001796b6794", - "metadata": {}, - "outputs": [], - "source": [ - "CC = CC1" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "248d58be-fc70-4b24-a8c2-0cc3d59d54e9", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Num curves: 6\n", - "Pairs: {'LINK/USDP', 'ETH/LINK', 'ETH/USDP'}\n", - "Target token: ETH\n" - ] - } - ], - "source": [ - "print(\"Num curves: \", len(CC))\n", - "print(\"Pairs: \", set(c.pairo.primary_n for c in CC))\n", - "print(\"Target token: \", TARGET_TOKEN)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "4dd5ccb9-f1a8-4d1b-8965-fc08021dd9a9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "PRICE_DECIMALS = 2\n", - "curvedata = [dict(\n", - " cid0 = f\"{c.cid[2:6]}{c.cid[-2:]}\",\n", - " exch = c.params['exchange'],\n", - " pair = c.pairo.primary_n,\n", - " mktp = round(p(c.pairo.primary_n), PRICE_DECIMALS),\n", - " bs = c.buysell(),\n", - " tkn = c.pairo.primary_tknb,\n", - " p = round(c.primaryp(), PRICE_DECIMALS),\n", - " p_min = round(c.p_min_primary(), PRICE_DECIMALS),\n", - " p_max = round(c.p_max_primary(), PRICE_DECIMALS),\n", - " tknp = p(tknb=c.pairo.primary_tknb, tknq=TARGET_TOKEN),\n", - " wbp = max(int((c.p_max_primary()/c.p_min_primary() - 1)*10000), 1),\n", - " liq = round(c.tvl(tkn=c.pairo.primary_tknb), 2),\n", - " liqtt = round(c.x_act*p(tknb=c.tknx, tknq=TARGET_TOKEN) + c.y_act*p(tknb=c.tkny, tknq=TARGET_TOKEN), 2),\n", - ") for c in CC]\n", - "#curvedata" - ] - }, - { - "cell_type": "markdown", - "id": "907431f0-9bb0-467d-9230-154e92a0e259", - "metadata": { - "tags": [] - }, - "source": [ - "- `cid0`: shortened CID (same as in `debug_tkn2`)\n", - "- `exch`: the type of the curve / exchange in question\n", - "- `pair`: the normalized pair of the curve\n", - "- `mktp`: the current market price of that pair (according to `PRICES_RAW`)\n", - "- `bs`: whether curves buys (\"b\"), sells (\"s\") the primary tokenm, or both\n", - "- `tkn`: the primary token (base token of primary pair)\n", - "- `p`, `p_min`, `p_max`: the current / minimum / maximum price of the curve\n", - "- `tknp`: the price of `tkn` (as above) in terms of `TARGET_TOKEN`, as per the market price\n", - "- `wbp`: width of the range (p_max/p_min) in basis points \n", - "- `liq`: liquidity (in units of `tkn` as defined above; converted at curve price)\n", - "- `liqtt`: total curve liquidity (in `TARGET_TOKEN` units; converted at `mktp`)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "3deeac05-5364-413c-a93a-c9fe9f218c79", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid0exchpairmktpbstknpp_minp_maxtknpwbpliqliqtt
0425d-0carbon_v1LINK/USDP14.16bLINK17.0014.0017.000.0043722142117.710.62
1425d-1carbon_v1LINK/USDP14.16sLINK20.0020.0020.000.004372155.500.24
23fcc-0carbon_v1ETH/LINK228.72sETH228.72228.72238.101.0000004105.005.00
33fcc-1carbon_v1ETH/LINK228.72bETH228.60222.22228.601.0000002873.533.53
46cc4-0carbon_v1ETH/USDP3239.01bETH3237.393000.003237.391.0000007914.924.92
56cc4-1carbon_v1ETH/USDP3239.01sETH3239.013239.013500.001.0000008055.005.00
\n", - "
" - ], - "text/plain": [ - " cid0 exch pair mktp bs tkn p p_min p_max \\\n", - "0 425d-0 carbon_v1 LINK/USDP 14.16 b LINK 17.00 14.00 17.00 \n", - "1 425d-1 carbon_v1 LINK/USDP 14.16 s LINK 20.00 20.00 20.00 \n", - "2 3fcc-0 carbon_v1 ETH/LINK 228.72 s ETH 228.72 228.72 238.10 \n", - "3 3fcc-1 carbon_v1 ETH/LINK 228.72 b ETH 228.60 222.22 228.60 \n", - "4 6cc4-0 carbon_v1 ETH/USDP 3239.01 b ETH 3237.39 3000.00 3237.39 \n", - "5 6cc4-1 carbon_v1 ETH/USDP 3239.01 s ETH 3239.01 3239.01 3500.00 \n", - "\n", - " tknp wbp liq liqtt \n", - "0 0.004372 2142 117.71 0.62 \n", - "1 0.004372 1 55.50 0.24 \n", - "2 1.000000 410 5.00 5.00 \n", - "3 1.000000 287 3.53 3.53 \n", - "4 1.000000 791 4.92 4.92 \n", - "5 1.000000 805 5.00 5.00 " - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "curvedf = pd.DataFrame(curvedata)\n", - "curvedf" - ] - }, - { - "cell_type": "markdown", - "id": "963c1045-22e5-43f6-bb5a-3e3fce6cf92e", - "metadata": {}, - "source": [ - "Curves 2,3 and 4,5 are overlapping ranges with good liquidity that serve as a market for curve 1 which is the operational curve in this arbitrage. In fact, what we expect is\n", - "\n", - "- Curve 0 (`425d-0`) buys LINK for USDP from 17 down to 14\n", - "- Curves 2-5 (`3fcc` and `6cc4`) sell LINK for USDP (via ETH) at 14.16 and above\n", - "\n", - "The expected price is somewhat above 14, depending on the capacity of the overlapping curves 2-5" - ] - }, - { - "cell_type": "markdown", - "id": "c39b25e9-e9af-4767-a144-42493a9a83e6", - "metadata": {}, - "source": [ - "The approximate effective LINK/USDP price from the overlapping curves (buy and sell)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "e9ced448-0a1b-4baf-9ec9-5d6414679b79", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "14.161676661786817" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "3239.013043/228.716777" - ] - }, - { - "cell_type": "markdown", - "id": "f23ac41d-a71f-4d81-b9a7-5c7aee4c4fb3", - "metadata": {}, - "source": [ - "The width of the overlapping ranges (2,3 and 4,5) in basis points" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "89b33db2-15cc-473b-8099-17f262e40674", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(4.999989588914122, 5.000002556068139)" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(228.716777/228.602476-1)*10000, (3239.013043/3237.394345-1)*10000" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "34b47dce-a466-4a9a-9597-779b0942c647", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0.004321373782642578" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "np.log10(1.01)" - ] - }, - { - "cell_type": "markdown", - "id": "54d0478d-d748-4f9a-ae3a-753ab61cc8de", - "metadata": {}, - "source": [ - "For reference, the CID dataframe `ciddf` (separate because the field is too long; can be joined to `curvedf` via index)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "0cc8423f-726b-42f6-9144-2f1de1d98d12", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid
00x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...
10x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...
20x3fcccfe0063b71fc973fab8dea39b6be9da80125910c...
30x3fcccfe0063b71fc973fab8dea39b6be9da80125910c...
40x6cc4b198ec4cf17fdced081b5611279be73e20071123...
50x6cc4b198ec4cf17fdced081b5611279be73e20071123...
\n", - "
" - ], - "text/plain": [ - " cid\n", - "0 0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...\n", - "1 0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...\n", - "2 0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c...\n", - "3 0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c...\n", - "4 0x6cc4b198ec4cf17fdced081b5611279be73e20071123...\n", - "5 0x6cc4b198ec4cf17fdced081b5611279be73e20071123..." - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ciddf = pd.DataFrame([dict(cid=c.cid) for c in CC])\n", - "ciddf" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "16d86f58-0c20-4c38-9e62-25ad33fafe1b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#help(CC[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "4cdabeff-acae-49c2-b211-d37858a4910e", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#help(CC[0].pairo)" - ] - }, - { - "cell_type": "markdown", - "id": "94f35eba-137c-4adf-a167-2218e68410e6", - "metadata": {}, - "source": [ - "## MargPOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "d0200904-33d4-4dbe-951e-bd4ee834a59b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] targettkn = ETH\n", - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "[margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n", - "\n", - "[margp_optimizer] ETH <- LINK, USDP\n", - "[margp_optimizer] p 0.00, 0.00\n", - "[margp_optimizer] 1/p 228.72, 3,239.01\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "tknq ETH\n", - "dLINK/d%pLINK, dLINK/d%pUSDP\n", - "dUSDP/d%pLINK, dUSDP/d%pUSDP\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[ -6.93514851 6.93538284]\n", - " [ 98.21599834 -98.21267983]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 0 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn 121.680, -1,887.990\n", - "log p0 [-2.359298022862449, -3.51041269678875]\n", - "d logp [107.3502951 107.27085049]\n", - "log p [104.99099708 103.76043779]\n", - "p_t (9.794834002573646e+104, 5.760203059099629e+103) ETH\n", - "p 979,483,400,257,364,632,072,013,009,658,563,057,076,932,204,130,139,433,223,949,926,870,669,976,661,682,797,697,379,616,116,239,039,987,712.00, 57,602,030,590,996,293,939,643,999,320,085,471,707,376,759,418,691,149,014,414,432,703,310,698,609,203,183,028,808,525,037,431,055,974,400.00\n", - "1/p 0.00, 0.00\n", - "crit 1.52e+02 [1; L2], eps=1e-06, c/e=2e+08]\n", - "dtkn_d {'LINK': 121.67964276398834, 'ETH': -1.1368683772161603e-13, 'USDP': -1887.990147798253}\n", - "<<<========== cycle 0 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[ 0. 5.65960698]\n", - " [ 0. -96.1106635 ]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer] singular Jacobian, using lstsq instead\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 1 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn -807.915, -15,920.777\n", - "log p0 [104.99099708021056, 103.76043779347391]\n", - "d logp [ 0. -0.71123223]\n", - "log p [104.99099708 103.04920556]\n", - "p_t (9.794834002573646e+104, 1.1199678719708761e+103) ETH\n", - "p 979,483,400,257,364,632,072,013,009,658,563,057,076,932,204,130,139,433,223,949,926,870,669,976,661,682,797,697,379,616,116,239,039,987,712.00, 11,199,678,719,708,761,406,012,676,553,609,621,611,516,754,679,766,460,338,327,077,078,407,119,250,117,557,034,131,277,278,226,484,822,016.00\n", - "1/p 0.00, 0.00\n", - "crit 7.11e-01 [1; L2], eps=1e-06, c/e=7e+05]\n", - "dtkn_d {'LINK': -807.9145301701064, 'ETH': 8.693167770410668, 'USDP': -15920.776548455411}\n", - "<<<========== cycle 1 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[0. 0.]\n", - " [0. 0.]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer] singular Jacobian, using lstsq instead\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 2 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn -863.415, -14,810.777\n", - "log p0 [104.99099708021056, 103.04920556443277]\n", - "d logp [0. 0.]\n", - "log p [104.99099708 103.04920556]\n", - "p_t (9.794834002573646e+104, 1.1199678719708761e+103) ETH\n", - "p 979,483,400,257,364,632,072,013,009,658,563,057,076,932,204,130,139,433,223,949,926,870,669,976,661,682,797,697,379,616,116,239,039,987,712.00, 11,199,678,719,708,761,406,012,676,553,609,621,611,516,754,679,766,460,338,327,077,078,407,119,250,117,557,034,131,277,278,226,484,822,016.00\n", - "1/p 0.00, 0.00\n", - "crit 0.00e+00 [1; L2], eps=1e-06, c/e=0e+00]\n", - "dtkn_d {'LINK': -863.4145301701064, 'ETH': 8.693167770410668, 'USDP': -14810.776548455411}\n", - "<<<========== cycle 2 =======\n", - "8.693167770410668\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=8.693167770410668, time=0.0015621185302734375, method='margp', targettkn='ETH', p_optimal_t=(9.794834002573646e+104, 1.1199678719708761e+103), dtokens_t=(-863.4145301701064, -14810.776548455411), tokens_t=('LINK', 'USDP'), errormsg=None)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC1)\n", - "r = O.optimize(sfc=TARGET_TOKEN, params=dict(\n", - " pstart=PRICES,\n", - " dump_curves = O.DC_DEFAULT,\n", - " #jach = 0.001,\n", - " verbose=True,\n", - " debug=False,\n", - " debug_j=True,\n", - " debug_dtkn=False,\n", - " debug_dtkn2=False,\n", - " debug_dtknd=True,\n", - "))\n", - "print(r.result)\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "bdb71913-d35b-4396-b21d-1f67d9a6ad5d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] targettkn = ETH\n", - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "[margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n", - "\n", - "[margp_optimizer] ETH <- LINK, USDP\n", - "[margp_optimizer] p 0.00, 0.00\n", - "[margp_optimizer] 1/p 228.72, 3,239.01\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "tknq ETH\n", - "dLINK/d%pLINK, dLINK/d%pUSDP\n", - "dUSDP/d%pLINK, dUSDP/d%pUSDP\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[ -266.29970486 6.94927602]\n", - " [ 98.34817271 -2083.1502104 ]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 0 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn 121.680, -1,887.990\n", - "log p0 [-2.359298022862449, -3.51041269678875]\n", - "d logp [ 0.00187466 -0.00382802]\n", - "log p [-2.35742336 -3.51424072]\n", - "p_t (0.004391133456960796, 0.00030602667429245015) ETH\n", - "p 0.00, 0.00\n", - "1/p 227.73, 3,267.69\n", - "crit 4.26e-03 [1; L2], eps=1e-06, c/e=4e+03]\n", - "dtkn_d {'LINK': 121.67964276398834, 'ETH': -1.1368683772161603e-13, 'USDP': -1887.990147798253}\n", - "<<<========== cycle 0 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[ -291.95964863 6.90381555]\n", - " [ 98.99589044 -2223.73007325]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 1 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn 2.956, 124.163\n", - "log p0 [-2.3574233634556503, -3.5142407173317083]\n", - "d logp [4.95047165e-05 2.43489787e-04]\n", - "log p [-2.35737386 -3.51399723]\n", - "p_t (0.004391634025620717, 0.0003061982980757411) ETH\n", - "p 0.00, 0.00\n", - "1/p 227.71, 3,265.86\n", - "crit 2.48e-04 [1; L2], eps=1e-06, c/e=2e+02]\n", - "dtkn_d {'LINK': 2.955627468109242, 'ETH': -0.09816327417928505, 'USDP': 124.16301503770228}\n", - "<<<========== cycle 1 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[ -291.94494632 6.90535661]\n", - " [ 98.97378098 -2223.11272002]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 2 =======>>>\n", - "ETH <- LINK, USDP\n", - "dtkn -0.005, -0.238\n", - "log p0 [-2.357373858739174, -3.513997227544904]\n", - "d logp [-8.79926609e-08 -4.66297120e-07]\n", - "log p [-2.35737395 -3.51399769]\n", - "p_t (0.0043916331358292504, 0.00030619796931423594) ETH\n", - "p 0.00, 0.00\n", - "1/p 227.71, 3,265.86\n", - "crit 4.75e-07 [1; L2], eps=1e-06, c/e=5e-01]\n", - "dtkn_d {'LINK': -0.005199518922381685, 'ETH': -0.047080484221538654, 'USDP': -0.237869284923363}\n", - "<<<========== cycle 2 =======\n", - "-0.047176345331450875\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-0.047176345331450875, time=0.00133514404296875, method='margp', targettkn='ETH', p_optimal_t=(0.0043916331358292504, 0.00030619796931423594), dtokens_t=(9.577247283232282e-06, 0.0004883671354036778), tokens_t=('LINK', 'USDP'), errormsg=None)" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC1)\n", - "r = O.optimize(sfc=TARGET_TOKEN, params=dict(\n", - " pstart=PRICES,\n", - " dump_curves = O.DC_DEFAULT,\n", - " jach = 0.001,\n", - " verbose=True,\n", - " debug=False,\n", - " debug_j=True,\n", - " debug_dtkn=False,\n", - " debug_dtkn2=False,\n", - " debug_dtknd=True,\n", - "))\n", - "print(r.result)\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a588a324-9865-46c6-ac87-2600ffe19e33", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/Optimizer_2405_SEI2.ipynb b/resources/NBTest/Optimizer_2405_SEI2.ipynb deleted file mode 100644 index 4d976a4dc..000000000 --- a/resources/NBTest/Optimizer_2405_SEI2.ipynb +++ /dev/null @@ -1,909 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "7c4e7ad0-9280-41ee-85b2-f4461058398b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MargPOptimizer v6.0-beta01 (04/May/2024)\n" - ] - } - ], - "source": [ - "from tools.curves import ConstantProductCurve, CurveContainer, SimplePair\n", - "from tools.optimizer import CPCArbOptimizer, PairOptimizer, MargPOptimizer\n", - "CPC = ConstantProductCurve\n", - "\n", - "import pandas as pd\n", - "import math as m\n", - "\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(SimplePair))\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveContainer))\n", - "#print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))" - ] - }, - { - "cell_type": "markdown", - "id": "988c1f31-507c-4dd7-b8fc-14fa4aef8134", - "metadata": {}, - "source": [ - "# Optimizer Testing (SEI2, May 2024)" - ] - }, - { - "cell_type": "markdown", - "id": "8ebde928-6a4b-448c-b6c3-6941310fccae", - "metadata": {}, - "source": [ - "This is a light workbook allowing to look at issues that may arise when running the optimizer on a specific set of curves. \n", - "\n", - "Instructions:\n", - "\n", - "- locate the **exact** curve set to feed to the optimizer (it will be somewhere in the logging output, and it will be a list of ConstantProductCurve objects)\n", - "- assign it to the `CurvesRaw` variable as shown below\n", - "- add the missing token addresses to the `TOKENS` dict below\n", - "- provide consistent values for `PSTART`\n", - "- run the workbook" - ] - }, - { - "cell_type": "markdown", - "id": "7f38c5d2-6f6e-402c-b1a5-0fa00cf88f9a", - "metadata": { - "tags": [] - }, - "source": [ - "### >> Enter curves\n", - "\n", - "Place curves here in the form\n", - "\n", - " CurvesRaw = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, ...),\n", - " ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, ...),\n", - " ...\n", - " ]" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "5c244d95-da00-449f-a879-ace4b5523a22", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# CurvesRaw = [\n", - "# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - "# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n", - "# ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}),\n", - "# ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}),\n", - "# ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}),\n", - "# ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352})\n", - "# ]\n", - "# CCRaw = CurveContainer(CurvesRaw)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "25fdf902-90cc-4364-911e-c1f577b9b4e2", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CurvesRaw = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - " #ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n", - " CPC.from_pk(p= 230, k=1*230*(100**2), cid=\"ETH/LINK\", pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', ), \n", - " CPC.from_pk(p=3220, k=1*3220*(100**2), cid=\"ETH/USDP\", pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', ), \n", - "]\n", - "CCRaw = CurveContainer(CurvesRaw)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "a7057199-13bf-4f52-ac3a-c90bb7161523", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on method from_pk in module tools.curves.cpc:\n", - "\n", - "from_pk(p, k, *, x_act=None, y_act=None, pair=None, cid=None, fee=None, descr=None, params=None) method of abc.ABCMeta instance\n", - " constructor: from k,p (and x_act, y_act)\n", - "\n" - ] - } - ], - "source": [ - "help(ConstantProductCurve.from_pk)" - ] - }, - { - "cell_type": "markdown", - "id": "961f17f5-6286-4f4c-8bc3-9721811b50b1", - "metadata": {}, - "source": [ - "### >> Enter prices\n", - "\n", - "Provide current prices (`pstart`) here, in the format\n", - "\n", - " PRICES = {\n", - " '0x8E87...': 0.0003087360213944532, \n", - " '0x5149...': 0.004372219704179475, \n", - " '0xEeee...': 1\n", - " }\n", - " \n", - "The price numeraire does not matter as long as they are all in the same numeraire. All tokens must be present. Additional tokens can be added and will be ignored. " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "5fc55588-ec8b-4bdc-9482-4fc97d909c2e", - "metadata": {}, - "outputs": [], - "source": [ - "PRICES_RAW = {\n", - " '0x8E870D67F660D95d5be530380D0eC0bd388289E1': 0.0003087360213944532, \n", - " '0x514910771AF9Ca656af840dff83E8264EcF986CA': 0.004372219704179475, \n", - " '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 1\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "90127233-847b-4719-8f45-76638e5776d7", - "metadata": {}, - "source": [ - "### >> Enter tokens\n", - "\n", - "Provide token tickers here, in the format\n", - "\n", - " TOKENS = {\n", - " \"0x5149...\": \"LINK\",\n", - " \"0x8E87...\": \"USDP\",\n", - " \"0xEeee...\": \"ETH\",\n", - " }\n", - " \n", - "All tokens must be present. Additional tokens will be ignored. You must also provide the `TARGET_TOKEN` (default: first token of `TOKENS`)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "747c1dbf-d821-4214-8aa6-c1412bffeb50", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "TOKENS = {\n", - " \"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\": \"ETH\",\n", - " \"0x514910771AF9Ca656af840dff83E8264EcF986CA\": \"LINK\",\n", - " \"0x8E870D67F660D95d5be530380D0eC0bd388289E1\": \"USDP\",\n", - "}\n", - "\n", - "TARGET_TOKEN_RAW = list(TOKENS)[0]\n", - "TARGET_TOKEN_RAW" - ] - }, - { - "cell_type": "markdown", - "id": "8bba7e8a-dbf8-4a89-9ee8-686afbef9901", - "metadata": {}, - "source": [ - "### >>> Run optimizer\n", - "\n", - "please make sure that this line runs without errors (other than the error that needs to be addressed of course)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "a49a49f8-b3e4-49c4-b991-c3cd8a123658", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-0.05121777885030099, time=0.00048828125, method='margp', targettkn='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', p_optimal_t=(0.00030712990834734163, 0.004391622735940103), dtokens_t=(3.128661774098873e-10, 1.659827830735594e-11), tokens_t=('0x8E870D67F660D95d5be530380D0eC0bd388289E1', '0x514910771AF9Ca656af840dff83E8264EcF986CA'), errormsg=None)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCRaw)\n", - "r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW))\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "f18727c8-f2d9-4436-9022-a6f1d6f9a2f6", - "metadata": {}, - "source": [ - "**do not worry about the code below here; this is for the actual testing and will be adapted as need be**" - ] - }, - { - "cell_type": "markdown", - "id": "f4844ce6-dffa-4d79-b631-6b5fa8ff17a2", - "metadata": {}, - "source": [ - "### >>> Preprocessing\n", - "\n", - "Please ensure that this code runs without error. Errors here mean that the data provided above is not consistent." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "b1a6af0f-89b0-443d-81cb-fcfea6722441", - "metadata": {}, - "outputs": [], - "source": [ - "def replace_tokens(dct):\n", - " \"\"\"replaces the token address with the token name in dct\"\"\"\n", - " tkns = dct[\"pair\"].split(\"/\")\n", - " for i in range(len(tkns)):\n", - " #tkns[i] = TOKENS.get(tkns[i]) or tkns[i]\n", - " tkns[i] = TOKENS[tkns[i]]\n", - " dct[\"pair\"] = \"/\".join(tkns)\n", - " return dct\n", - "\n", - "def p(pair=None, *, tknb=None, tknq=None, prices=None):\n", - " \"price of tknb in terms of tknq\"\n", - " if not pair is None:\n", - " tknb, tknq = pair.split(\"/\")\n", - " p = prices or PRICES\n", - " return p[tknb]/p[tknq]\n", - "\n", - "def round_(x, *args):\n", - " \"forgiving round()\"\n", - " try:\n", - " return round(x, *args)\n", - " except:\n", - " return x\n", - "\n", - "def wbp(c):\n", - " \"width of the range in bp [0 means infty]\"\n", - " try:\n", - " return max(int((c.p_max_primary()/c.p_min_primary() - 1)*10000), 1)\n", - " except:\n", - " return 0\n", - " \n", - "def cid0(c):\n", - " \"shortened cid (for standard format ones)\"\n", - " if len(c.cid) < 20: return c.cid\n", - " return f\"{c.cid[2:6]}{c.cid[-2:]}\"" - ] - }, - { - "cell_type": "markdown", - "id": "265bd6ae-c5c4-439c-99bc-b289d44cab63", - "metadata": {}, - "source": [ - "If this fails this probably means that one of the tokens has not been defined above" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "f7651ba3-2fb2-444f-9971-779326ae4758", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'USDP': 0.0003087360213944532, 'LINK': 0.004372219704179475, 'ETH': 1}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw.asdicts()])\n", - "PRICES = {TOKENS[addr]:price for addr, price in PRICES_RAW.items()}\n", - "TARGET_TOKEN = TOKENS[TARGET_TOKEN_RAW]\n", - "PRICES" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "c7ce8e24-8ee6-48c0-bccd-0d268873128c", - "metadata": {}, - "outputs": [], - "source": [ - "def p(pair=None, *, tknb=None, tknq=None, prices=None):\n", - " \"price of tknb in terms of tknq\"\n", - " if not pair is None:\n", - " tknb, tknq = pair.split(\"/\")\n", - " p = prices or PRICES\n", - " return p[tknb]/p[tknq]" - ] - }, - { - "cell_type": "markdown", - "id": "9906cde3-7c6b-47dd-b322-c342189281d9", - "metadata": {}, - "source": [ - "The code below ensures that in ETH/LINK, LINK is the quote token and ETH the base token (for better price displays)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "9366ca04-201c-448d-8db3-62b17946fdd9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "SimplePair.NUMERAIRE_TOKENS[\"LINK\"] = SimplePair.NUMERAIRE_TOKENS[\"ETH\"] - 1\n", - "#SimplePair.NUMERAIRE_TOKENS" - ] - }, - { - "cell_type": "markdown", - "id": "f8d51655-c7d6-4966-ad44-e002dc4aca62", - "metadata": {}, - "source": [ - "## Curves" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "248d58be-fc70-4b24-a8c2-0cc3d59d54e9", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Num curves: 3\n", - "Pairs: {'LINK/USDP', 'ETH/USDP', 'ETH/LINK'}\n", - "Target token: ETH\n" - ] - } - ], - "source": [ - "print(\"Num curves: \", len(CC))\n", - "print(\"Pairs: \", set(c.pairo.primary_n for c in CC))\n", - "print(\"Target token: \", TARGET_TOKEN)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "4dd5ccb9-f1a8-4d1b-8965-fc08021dd9a9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "PRICE_DECIMALS = 2\n", - "curvedata = [dict(\n", - " cid0 = cid0(c),\n", - " exch = c.params.get('exchange', \"na\"),\n", - " pair = c.pairo.primary_n,\n", - " mktp = round(p(c.pairo.primary_n), PRICE_DECIMALS),\n", - " bs = c.buysell(),\n", - " tkn = c.pairo.primary_tknb,\n", - " p = round_(c.primaryp(), PRICE_DECIMALS),\n", - " p_min = round_(c.p_min_primary(), PRICE_DECIMALS),\n", - " p_max = round_(c.p_max_primary(), PRICE_DECIMALS),\n", - " tknp = p(tknb=c.pairo.primary_tknb, tknq=TARGET_TOKEN),\n", - " wbp = wbp(c),\n", - " liq = round(c.tvl(tkn=c.pairo.primary_tknb), 2),\n", - " liqtt = round(c.x_act*p(tknb=c.tknx, tknq=TARGET_TOKEN) + c.y_act*p(tknb=c.tkny, tknq=TARGET_TOKEN), 2),\n", - ") for c in CC]\n", - "#curvedata" - ] - }, - { - "cell_type": "markdown", - "id": "907431f0-9bb0-467d-9230-154e92a0e259", - "metadata": { - "tags": [] - }, - "source": [ - "- `cid0`: shortened CID (same as in `debug_tkn2`)\n", - "- `exch`: the type of the curve / exchange in question\n", - "- `pair`: the normalized pair of the curve\n", - "- `mktp`: the current market price of that pair (according to `PRICES_RAW`)\n", - "- `bs`: whether curves buys (\"b\"), sells (\"s\") the primary tokenm, or both\n", - "- `tkn`: the primary token (base token of primary pair)\n", - "- `p`, `p_min`, `p_max`: the current / minimum / maximum price of the curve\n", - "- `tknp`: the price of `tkn` (as above) in terms of `TARGET_TOKEN`, as per the market price\n", - "- `wbp`: width of the range (p_max/p_min) in basis points \n", - "- `liq`: liquidity (in units of `tkn` as defined above; converted at curve price)\n", - "- `liqtt`: total curve liquidity (in `TARGET_TOKEN` units; converted at `mktp`)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "3deeac05-5364-413c-a93a-c9fe9f218c79", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid0exchpairmktpbstknpp_minp_maxtknpwbpliqliqtt
0425d-0carbon_v1LINK/USDP14.16bLINK17.014.017.00.0043722142117.710.62
1ETH/LINKnaETH/LINK228.72bsETH230.00.0NaN1.0000000200.00200.56
2ETH/USDPnaETH/USDP3239.01bsETH3220.00.0NaN1.0000000200.00199.41
\n", - "
" - ], - "text/plain": [ - " cid0 exch pair mktp bs tkn p p_min p_max \\\n", - "0 425d-0 carbon_v1 LINK/USDP 14.16 b LINK 17.0 14.0 17.0 \n", - "1 ETH/LINK na ETH/LINK 228.72 bs ETH 230.0 0.0 NaN \n", - "2 ETH/USDP na ETH/USDP 3239.01 bs ETH 3220.0 0.0 NaN \n", - "\n", - " tknp wbp liq liqtt \n", - "0 0.004372 2142 117.71 0.62 \n", - "1 1.000000 0 200.00 200.56 \n", - "2 1.000000 0 200.00 199.41 " - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "curvedf = pd.DataFrame(curvedata)\n", - "curvedf" - ] - }, - { - "cell_type": "markdown", - "id": "71c9a7f7-afb4-4e91-a625-d85a8c750c7b", - "metadata": {}, - "source": [ - "- The arbitrageable curve is #0 that buys LINK against USDP on the way down from `17 to 14`, at an average price of `15.4 LINK/USDP`; liquidity is `0.6 ETH ~ 2000 USDP`\n", - "- The triangle is made up via two massive curves (20 ETH each) with price points at `230 ETH/LINK` and `3220 ETH/USDP` respectively, yielding an effective `ETH/LINK of 14`\n", - "- The average profit is `10%`, on a volume of `2000 USDP or 0.6 ETH`, ie `200 USD or 0.06 ETH`\n", - "- That is close enough to the actual `result 0.05 ETH` (see below), keeping in mind that there is still some slippage on the big curves" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "1849f948-f69b-400e-8d02-bd49fde91ca8", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(1932.0, 15.427248620541512, 14.0, 0.10000000000000009)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "0.6*3220, m.sqrt(17*14), 3220/230, 15.4/14-1" - ] - }, - { - "cell_type": "markdown", - "id": "54d0478d-d748-4f9a-ae3a-753ab61cc8de", - "metadata": {}, - "source": [ - "For reference, the CID dataframe `ciddf` (separate because the field is too long; can be joined to `curvedf` via index)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "0cc8423f-726b-42f6-9144-2f1de1d98d12", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid
00x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...
1ETH/LINK
2ETH/USDP
\n", - "
" - ], - "text/plain": [ - " cid\n", - "0 0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05b...\n", - "1 ETH/LINK\n", - "2 ETH/USDP" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ciddf = pd.DataFrame([dict(cid=c.cid) for c in CC])\n", - "ciddf" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "16d86f58-0c20-4c38-9e62-25ad33fafe1b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#help(CC[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "4cdabeff-acae-49c2-b211-d37858a4910e", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#help(CC[0].pairo)" - ] - }, - { - "cell_type": "markdown", - "id": "94f35eba-137c-4adf-a167-2218e68410e6", - "metadata": {}, - "source": [ - "## MargPOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "d0200904-33d4-4dbe-951e-bd4ee834a59b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] targettkn = ETH\n", - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "[margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n", - "\n", - "[margp_optimizer] ETH <- USDP, LINK\n", - "[margp_optimizer] p 0.00, 0.00\n", - "[margp_optimizer] 1/p 3,239.01, 228.72\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "tknq ETH\n", - "dUSDP/d%pUSDP, dUSDP/d%pLINK\n", - "dLINK/d%pUSDP, dLINK/d%pLINK\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-1704.90616999 98.21599834]\n", - " [ 6.93538284 -121.04274482]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 0 =======>>>\n", - "ETH <- USDP, LINK\n", - "dtkn -938.737, 57.429\n", - "log p0 [-3.51041269678875, -2.359298022862449]\n", - "d logp [-0.00226877 0.00192028]\n", - "log p [-3.51268146 -2.35737774]\n", - "p_t (0.000307127382149018, 0.004391594784368945) ETH\n", - "p 0.00, 0.00\n", - "1/p 3,255.98, 227.71\n", - "crit 2.97e-03 [1; L2], eps=1e-06, c/e=3e+03]\n", - "dtkn_d {'USDP': -938.7372148645118, 'LINK': 57.428760378646075, 'ETH': -0.013798315023322516}\n", - "<<<========== cycle 0 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-1709.58314294 98.69081945]\n", - " [ 6.90201535 -120.75738836]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 1 =======>>>\n", - "ETH <- USDP, LINK\n", - "dtkn 1.350, 0.072\n", - "log p0 [-3.5126814620131683, -2.3573777393756634]\n", - "d logp [3.57223418e-06 2.76422511e-06]\n", - "log p [-3.51267789 -2.35737498]\n", - "p_t (0.0003071299083967377, 0.00439162273635938) ETH\n", - "p 0.00, 0.00\n", - "1/p 3,255.95, 227.71\n", - "crit 4.52e-06 [1; L2], eps=1e-06, c/e=5e+00]\n", - "dtkn_d {'USDP': 1.35008633628604, 'LINK': 0.07153859061031653, 'ETH': -0.0519465985387626}\n", - "<<<========== cycle 1 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-1709.57642611 98.69072764]\n", - " [ 6.90202177 -120.75703245]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 2 =======>>>\n", - "ETH <- USDP, LINK\n", - "dtkn -0.000, -0.000\n", - "log p0 [-3.512677889778987, -2.357374975150554]\n", - "d logp [-6.98486252e-11 -4.14631051e-11]\n", - "log p [-3.51267789 -2.35737498]\n", - "p_t (0.00030712990834734163, 0.004391622735940103) ETH\n", - "p 0.00, 0.00\n", - "1/p 3,255.95, 227.71\n", - "crit 8.12e-11 [1; L2], eps=1e-06, c/e=8e-05]\n", - "dtkn_d {'USDP': -2.6685851480579004e-05, 'LINK': -1.0470894267200492e-06, 'ETH': -0.05121776605568584}\n", - "<<<========== cycle 2 =======\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-0.05121777885030099, time=0.0017211437225341797, method='margp', targettkn='ETH', p_optimal_t=(0.00030712990834734163, 0.004391622735940103), dtokens_t=(3.128661774098873e-10, 1.659827830735594e-11), tokens_t=('USDP', 'LINK'), errormsg=None)" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(sfc=TARGET_TOKEN, params=dict(\n", - " pstart=PRICES,\n", - " verbose=True,\n", - " debug=False,\n", - " debug_j=True,\n", - " debug_dtkn=False,\n", - " debug_dtkn2=False,\n", - " debug_dtknd=True,\n", - "))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "bdb71913-d35b-4396-b21d-1f67d9a6ad5d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-0.05121777885030099, 'ETH', 174.14044809102336)" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r.result, r.targettkn, -r.result*3400" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2742dde-6074-4494-a308-3229c50a176f", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c19b0b7f-011c-45c4-9de5-151304147660", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/Optimizer_2405_SEI2.py b/resources/NBTest/Optimizer_2405_SEI2.py deleted file mode 100644 index 630bf9b32..000000000 --- a/resources/NBTest/Optimizer_2405_SEI2.py +++ /dev/null @@ -1,269 +0,0 @@ -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -from tools.curves import ConstantProductCurve, CurveContainer, SimplePair -from tools.optimizer import CPCArbOptimizer, PairOptimizer, MargPOptimizer -CPC = ConstantProductCurve - -import pandas as pd -import math as m - -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(SimplePair)) -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CurveContainer)) -#print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(PairOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) -# - - -# # Optimizer Testing (SEI2, May 2024) - -# This is a light workbook allowing to look at issues that may arise when running the optimizer on a specific set of curves. -# -# Instructions: -# -# - locate the **exact** curve set to feed to the optimizer (it will be somewhere in the logging output, and it will be a list of ConstantProductCurve objects) -# - assign it to the `CurvesRaw` variable as shown below -# - add the missing token addresses to the `TOKENS` dict below -# - provide consistent values for `PSTART` -# - run the workbook - -# ### >> Enter curves -# -# Place curves here in the form -# -# CurvesRaw = [ -# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, ...), -# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, ...), -# ... -# ] - -# + -# CurvesRaw = [ -# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}), -# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}), -# ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}), -# ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}), -# ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}), -# ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352}) -# ] -# CCRaw = CurveContainer(CurvesRaw) -# - - -CurvesRaw = [ - ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}), - #ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}), - CPC.from_pk(p= 230, k=1*230*(100**2), cid="ETH/LINK", pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', ), - CPC.from_pk(p=3220, k=1*3220*(100**2), cid="ETH/USDP", pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', ), -] -CCRaw = CurveContainer(CurvesRaw) - -help(ConstantProductCurve.from_pk) - -# ### >> Enter prices -# -# Provide current prices (`pstart`) here, in the format -# -# PRICES = { -# '0x8E87...': 0.0003087360213944532, -# '0x5149...': 0.004372219704179475, -# '0xEeee...': 1 -# } -# -# The price numeraire does not matter as long as they are all in the same numeraire. All tokens must be present. Additional tokens can be added and will be ignored. - -PRICES_RAW = { - '0x8E870D67F660D95d5be530380D0eC0bd388289E1': 0.0003087360213944532, - '0x514910771AF9Ca656af840dff83E8264EcF986CA': 0.004372219704179475, - '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 1 -} - -# ### >> Enter tokens -# -# Provide token tickers here, in the format -# -# TOKENS = { -# "0x5149...": "LINK", -# "0x8E87...": "USDP", -# "0xEeee...": "ETH", -# } -# -# All tokens must be present. Additional tokens will be ignored. You must also provide the `TARGET_TOKEN` (default: first token of `TOKENS`) -# - -# + -TOKENS = { - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE": "ETH", - "0x514910771AF9Ca656af840dff83E8264EcF986CA": "LINK", - "0x8E870D67F660D95d5be530380D0eC0bd388289E1": "USDP", -} - -TARGET_TOKEN_RAW = list(TOKENS)[0] -TARGET_TOKEN_RAW -# - - -# ### >>> Run optimizer -# -# please make sure that this line runs without errors (other than the error that needs to be addressed of course) - -O = MargPOptimizer(CCRaw) -r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW)) -r - - -# **do not worry about the code below here; this is for the actual testing and will be adapted as need be** - -# ### >>> Preprocessing -# -# Please ensure that this code runs without error. Errors here mean that the data provided above is not consistent. - -# + -def replace_tokens(dct): - """replaces the token address with the token name in dct""" - tkns = dct["pair"].split("/") - for i in range(len(tkns)): - #tkns[i] = TOKENS.get(tkns[i]) or tkns[i] - tkns[i] = TOKENS[tkns[i]] - dct["pair"] = "/".join(tkns) - return dct - -def p(pair=None, *, tknb=None, tknq=None, prices=None): - "price of tknb in terms of tknq" - if not pair is None: - tknb, tknq = pair.split("/") - p = prices or PRICES - return p[tknb]/p[tknq] - -def round_(x, *args): - "forgiving round()" - try: - return round(x, *args) - except: - return x - -def wbp(c): - "width of the range in bp [0 means infty]" - try: - return max(int((c.p_max_primary()/c.p_min_primary() - 1)*10000), 1) - except: - return 0 - -def cid0(c): - "shortened cid (for standard format ones)" - if len(c.cid) < 20: return c.cid - return f"{c.cid[2:6]}{c.cid[-2:]}" - - -# - - -# If this fails this probably means that one of the tokens has not been defined above - -CC = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw.asdicts()]) -PRICES = {TOKENS[addr]:price for addr, price in PRICES_RAW.items()} -TARGET_TOKEN = TOKENS[TARGET_TOKEN_RAW] -PRICES - - -def p(pair=None, *, tknb=None, tknq=None, prices=None): - "price of tknb in terms of tknq" - if not pair is None: - tknb, tknq = pair.split("/") - p = prices or PRICES - return p[tknb]/p[tknq] - - -# The code below ensures that in ETH/LINK, LINK is the quote token and ETH the base token (for better price displays) - -SimplePair.NUMERAIRE_TOKENS["LINK"] = SimplePair.NUMERAIRE_TOKENS["ETH"] - 1 -#SimplePair.NUMERAIRE_TOKENS - -# ## Curves - -print("Num curves: ", len(CC)) -print("Pairs: ", set(c.pairo.primary_n for c in CC)) -print("Target token: ", TARGET_TOKEN) - -PRICE_DECIMALS = 2 -curvedata = [dict( - cid0 = cid0(c), - exch = c.params.get('exchange', "na"), - pair = c.pairo.primary_n, - mktp = round(p(c.pairo.primary_n), PRICE_DECIMALS), - bs = c.buysell(), - tkn = c.pairo.primary_tknb, - p = round_(c.primaryp(), PRICE_DECIMALS), - p_min = round_(c.p_min_primary(), PRICE_DECIMALS), - p_max = round_(c.p_max_primary(), PRICE_DECIMALS), - tknp = p(tknb=c.pairo.primary_tknb, tknq=TARGET_TOKEN), - wbp = wbp(c), - liq = round(c.tvl(tkn=c.pairo.primary_tknb), 2), - liqtt = round(c.x_act*p(tknb=c.tknx, tknq=TARGET_TOKEN) + c.y_act*p(tknb=c.tkny, tknq=TARGET_TOKEN), 2), -) for c in CC] -#curvedata - -# - `cid0`: shortened CID (same as in `debug_tkn2`) -# - `exch`: the type of the curve / exchange in question -# - `pair`: the normalized pair of the curve -# - `mktp`: the current market price of that pair (according to `PRICES_RAW`) -# - `bs`: whether curves buys ("b"), sells ("s") the primary tokenm, or both -# - `tkn`: the primary token (base token of primary pair) -# - `p`, `p_min`, `p_max`: the current / minimum / maximum price of the curve -# - `tknp`: the price of `tkn` (as above) in terms of `TARGET_TOKEN`, as per the market price -# - `wbp`: width of the range (p_max/p_min) in basis points -# - `liq`: liquidity (in units of `tkn` as defined above; converted at curve price) -# - `liqtt`: total curve liquidity (in `TARGET_TOKEN` units; converted at `mktp`) -# - -curvedf = pd.DataFrame(curvedata) -curvedf - -# - The arbitrageable curve is #0 that buys LINK against USDP on the way down from `17 to 14`, at an average price of `15.4 LINK/USDP`; liquidity is `0.6 ETH ~ 2000 USDP` -# - The triangle is made up via two massive curves (20 ETH each) with price points at `230 ETH/LINK` and `3220 ETH/USDP` respectively, yielding an effective `ETH/LINK of 14` -# - The average profit is `10%`, on a volume of `2000 USDP or 0.6 ETH`, ie `200 USD or 0.06 ETH` -# - That is close enough to the actual `result 0.05 ETH` (see below), keeping in mind that there is still some slippage on the big curves - -0.6*3220, m.sqrt(17*14), 3220/230, 15.4/14-1 - -# For reference, the CID dataframe `ciddf` (separate because the field is too long; can be joined to `curvedf` via index) - -ciddf = pd.DataFrame([dict(cid=c.cid) for c in CC]) -ciddf - -# + -#help(CC[0]) - -# + -#help(CC[0].pairo) -# - - -# ## MargPOptimizer - -O = MargPOptimizer(CC) -r = O.optimize(sfc=TARGET_TOKEN, params=dict( - pstart=PRICES, - verbose=True, - debug=False, - debug_j=True, - debug_dtkn=False, - debug_dtkn2=False, - debug_dtknd=True, -)) -r - -r.result, r.targettkn, -r.result*3400 - - - - diff --git a/resources/NBTest/Optimizer_9999_TEMPLATE.ipynb b/resources/NBTest/Optimizer_9999_TEMPLATE.ipynb deleted file mode 100644 index 6bf39a546..000000000 --- a/resources/NBTest/Optimizer_9999_TEMPLATE.ipynb +++ /dev/null @@ -1,923 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "7c4e7ad0-9280-41ee-85b2-f4461058398b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SimplePair v2.2 (30/Apr/2024)\n", - "ConstantProductCurve v4.0-beta1 (04/May/2024)\n", - "CurveContainer v4.0-beta1 (04/May/2024)\n", - "PairOptimizer v6.0.2 (03/May/2024)\n", - "MargPOptimizer v6.0-beta01 (04/May/2024)\n" - ] - } - ], - "source": [ - "from tools.curves import ConstantProductCurve, CurveContainer, SimplePair\n", - "from tools.optimizer import CPCArbOptimizer, PairOptimizer, MargPOptimizer\n", - "CPC = ConstantProductCurve\n", - "\n", - "import pandas as pd\n", - "\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(SimplePair))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CurveContainer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(PairOptimizer))\n", - "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(MargPOptimizer))" - ] - }, - { - "cell_type": "markdown", - "id": "988c1f31-507c-4dd7-b8fc-14fa4aef8134", - "metadata": {}, - "source": [ - "# Optimizer Testing (TEMPLATE)" - ] - }, - { - "cell_type": "markdown", - "id": "8ebde928-6a4b-448c-b6c3-6941310fccae", - "metadata": {}, - "source": [ - "This is a light workbook allowing to look at issues that may arise when running the optimizer on a specific set of curves. \n", - "\n", - "Instructions:\n", - "\n", - "- locate the **exact** curve set to feed to the optimizer (it will be somewhere in the logging output, and it will be a list of ConstantProductCurve objects)\n", - "- assign it to the `CurvesRaw` variable as shown below\n", - "- add the missing token addresses to the `TOKENS` dict below\n", - "- provide consistent values for `PSTART`\n", - "- run the workbook\n", - "- if the import statement fails, ensure `fastlane_bot` is on the path, or create symlink to `tools`" - ] - }, - { - "cell_type": "markdown", - "id": "7f38c5d2-6f6e-402c-b1a5-0fa00cf88f9a", - "metadata": { - "tags": [] - }, - "source": [ - "### >> Enter curves\n", - "\n", - "Place curves here in the form\n", - "\n", - " CurvesRaw = [\n", - " ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, ...),\n", - " ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, ...),\n", - " ...\n", - " ]" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c121e2d1-42c7-4d01-9711-ce0507be2bb3", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "CurvesRaw = [\n", - " CPC.from_pk(pair=\"ETH_/USDP_\", cid=\"ETH/USDP1\", p=2000, k=1), # 1E+$2000 @ 2000\n", - " # CPC.from_pk(pair=\"ETH_/USDP_\", cid=\"ETH/USDP1\", p=2000, k=1*2000*1), # 1E+$2000 @ 2000\n", - " # CPC.from_pk(pair=\"ETH_/USDP_\", cid=\"ETH/USDP1\", p=3000, k=1*3000*1), # 1E+$2000 @ 2000\n", - " CPC.from_pk(pair=\"LINK_/USDP_\", cid=\"LINK/USDP1\", p= 10, k=100*1000), # 200L+$2000 @ 10\n", - " CPC.from_pk(pair=\"LINK_/USDP_\", cid=\"LINK/USDP1\", p= 15, k=100*1500), # 200L+$2000 @ 10\n", - " # CPC.from_pk(pair=\"ETH_/LINK_\", cid=\"ETH/LINK1\", p= 210, k=1*210*0.0000000000001), # ~1E @ 210\n", - "]\n", - "CCRaw = CurveContainer(CurvesRaw)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "5c244d95-da00-449f-a879-ace4b5523a22", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# CurvesRaw = [\n", - "# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}),\n", - "# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}),\n", - "# ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}),\n", - "# ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}),\n", - "# ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}),\n", - "# ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352})\n", - "# ]\n", - "# CCRaw = CurveContainer(CurvesRaw)" - ] - }, - { - "cell_type": "markdown", - "id": "961f17f5-6286-4f4c-8bc3-9721811b50b1", - "metadata": {}, - "source": [ - "### >> Enter prices\n", - "\n", - "Provide current prices (`pstart`) here, in the format\n", - "\n", - " PRICES = {\n", - " '0x8E87...': 0.0003087360213944532, \n", - " '0x5149...': 0.004372219704179475, \n", - " '0xEeee...': 1\n", - " }\n", - " \n", - "The price numeraire does not matter as long as they are all in the same numeraire. All tokens must be present. Additional tokens can be added and will be ignored. The keys in the dict here must correspond exactly to the \n", - "keys that are used in the pairs in the curves above." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "2a4f3486-3db9-4721-8ca9-2f1e2b5fe8d2", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "PRICES_RAW = {\n", - " 'ETH_': 1950, \n", - " 'LINK_': 11, \n", - " 'USDP_': 1\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "5fc55588-ec8b-4bdc-9482-4fc97d909c2e", - "metadata": {}, - "outputs": [], - "source": [ - "# PRICES_RAW = {\n", - "# '0x8E870D67F660D95d5be530380D0eC0bd388289E1': 0.0003087360213944532, \n", - "# '0x514910771AF9Ca656af840dff83E8264EcF986CA': 0.004372219704179475, \n", - "# '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 1\n", - "# }" - ] - }, - { - "cell_type": "markdown", - "id": "90127233-847b-4719-8f45-76638e5776d7", - "metadata": {}, - "source": [ - "### >> Enter tokens\n", - "\n", - "Provide token tickers here, in the format\n", - "\n", - " TOKENS = {\n", - " \"0x5149...\": \"LINK\",\n", - " \"0x8E87...\": \"USDP\",\n", - " \"0xEeee...\": \"ETH\",\n", - " }\n", - " \n", - "All tokens must be present. Additional tokens will be ignored. You must also provide the `TARGET_TOKEN_RAW`,\n", - "for example by picking from the token list" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "747c1dbf-d821-4214-8aa6-c1412bffeb50", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# TOKENS = {\n", - "# \"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\": \"ETH\",\n", - "# \"0x514910771AF9Ca656af840dff83E8264EcF986CA\": \"LINK\",\n", - "# \"0x8E870D67F660D95d5be530380D0eC0bd388289E1\": \"USDP\",\n", - "# }\n", - "\n", - "# TARGET_TOKEN_RAW = list(TOKENS)[0]\n", - "# TARGET_TOKEN_RAW" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "18404999-6d36-40d6-8f44-3f3394aa9a40", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'USDP_'" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "TOKENS = {\n", - " \"ETH_\": \"ETH\",\n", - " \"LINK_\": \"LINK\",\n", - " \"USDP_\": \"USDP\",\n", - "}\n", - "\n", - "TARGET_TOKEN_RAW = list(TOKENS)[-1]\n", - "TARGET_TOKEN_RAW" - ] - }, - { - "cell_type": "markdown", - "id": "8bba7e8a-dbf8-4a89-9ee8-686afbef9901", - "metadata": {}, - "source": [ - "### >>> Run optimizer\n", - "\n", - "please make sure that this line runs without errors (other than the error that needs to be addressed of course)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "a49a49f8-b3e4-49c4-b991-c3cd8a123658", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-25.255128608410814, time=0.0013539791107177734, method='margp', targettkn='USDP_', p_optimal_t=(1999.9999999999998, 12.373724356957945), dtokens_t=(3.469446951953614e-18, 0.0), tokens_t=('ETH_', 'LINK_'), errormsg=None)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CCRaw)\n", - "r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW))\n", - "r" - ] - }, - { - "cell_type": "markdown", - "id": "f18727c8-f2d9-4436-9022-a6f1d6f9a2f6", - "metadata": {}, - "source": [ - "**do not worry about the code below here; this is for the actual testing and will be adapted as need be**" - ] - }, - { - "cell_type": "markdown", - "id": "f4844ce6-dffa-4d79-b631-6b5fa8ff17a2", - "metadata": {}, - "source": [ - "### >>> Preprocessing\n", - "\n", - "Please ensure that this code runs without error. Errors here mean that the data provided above is not consistent." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "b1a6af0f-89b0-443d-81cb-fcfea6722441", - "metadata": {}, - "outputs": [], - "source": [ - "def replace_tokens(dct):\n", - " \"\"\"replaces the token address with the token name in dct\"\"\"\n", - " tkns = dct[\"pair\"].split(\"/\")\n", - " for i in range(len(tkns)):\n", - " #tkns[i] = TOKENS.get(tkns[i]) or tkns[i]\n", - " tkns[i] = TOKENS[tkns[i]]\n", - " dct[\"pair\"] = \"/\".join(tkns)\n", - " return dct\n", - "\n", - "def p(pair=None, *, tknb=None, tknq=None, prices=None):\n", - " \"price of tknb in terms of tknq\"\n", - " if not pair is None:\n", - " tknb, tknq = pair.split(\"/\")\n", - " p = prices or PRICES\n", - " return p[tknb]/p[tknq]\n", - "\n", - "def round_(x, *args):\n", - " \"forgiving round()\"\n", - " try:\n", - " return round(x, *args)\n", - " except:\n", - " return x\n", - "\n", - "def wbp(c):\n", - " \"width of the range in bp [0 means infty]\"\n", - " try:\n", - " return max(int((c.p_max_primary()/c.p_min_primary() - 1)*10000), 1)\n", - " except:\n", - " return 0\n", - " \n", - "def cid0(c):\n", - " \"shortened cid (for standard format ones)\"\n", - " if len(c.cid) < 20: return c.cid\n", - " return f\"{c.cid[2:6]}{c.cid[-2:]}\"" - ] - }, - { - "cell_type": "markdown", - "id": "265bd6ae-c5c4-439c-99bc-b289d44cab63", - "metadata": {}, - "source": [ - "If this fails this probably means that one of the tokens has not been defined above" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "f7651ba3-2fb2-444f-9971-779326ae4758", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'ETH': 1950, 'LINK': 11, 'USDP': 1}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "CC = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw.asdicts()])\n", - "PRICES = {TOKENS[addr]:price for addr, price in PRICES_RAW.items()}\n", - "TARGET_TOKEN = TOKENS[TARGET_TOKEN_RAW]\n", - "PRICES" - ] - }, - { - "cell_type": "markdown", - "id": "9906cde3-7c6b-47dd-b322-c342189281d9", - "metadata": {}, - "source": [ - "Here you can change the preference order of numeraire tokens (in a pair, the one with the lower number will be chosen as numeraire; tokens not present here are considered to have higher numbers; draw means alphabetic order). \n", - "\n", - "The specific code below ensures that in ETH/LINK, LINK is the quote token and ETH the base token. As LINK is not in the list, otherwise this would be the other way round." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "9366ca04-201c-448d-8db3-62b17946fdd9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "SimplePair.NUMERAIRE_TOKENS[\"LINK\"] = SimplePair.NUMERAIRE_TOKENS[\"ETH\"] - 1\n", - "#SimplePair.NUMERAIRE_TOKENS" - ] - }, - { - "cell_type": "markdown", - "id": "f8d51655-c7d6-4966-ad44-e002dc4aca62", - "metadata": {}, - "source": [ - "## Curves" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "248d58be-fc70-4b24-a8c2-0cc3d59d54e9", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Num curves: 3\n", - "Pairs: {'ETH/USDP', 'LINK/USDP'}\n", - "Target token: USDP\n" - ] - } - ], - "source": [ - "print(\"Num curves: \", len(CC))\n", - "print(\"Pairs: \", set(c.pairo.primary_n for c in CC))\n", - "print(\"Target token: \", TARGET_TOKEN)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "4dd5ccb9-f1a8-4d1b-8965-fc08021dd9a9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "PRICE_DECIMALS = 2\n", - "curvedata = [dict(\n", - " cid0 = cid0(c),\n", - " exch = c.params.get('exchange', \"na\"),\n", - " pair = c.pairo.primary_n,\n", - " mktp = round(p(c.pairo.primary_n), PRICE_DECIMALS),\n", - " bs = c.buysell(),\n", - " tkn = c.pairo.primary_tknb,\n", - " p = round_(c.primaryp(), PRICE_DECIMALS),\n", - " p_min = round_(c.p_min_primary(), PRICE_DECIMALS),\n", - " p_max = round_(c.p_max_primary(), PRICE_DECIMALS),\n", - " tknp = p(tknb=c.pairo.primary_tknb, tknq=TARGET_TOKEN),\n", - " wbp = wbp(c),\n", - " liq = round(c.tvl(tkn=c.pairo.primary_tknb), 2),\n", - " liqtt = round(c.x_act*p(tknb=c.tknx, tknq=TARGET_TOKEN) + c.y_act*p(tknb=c.tkny, tknq=TARGET_TOKEN), 2),\n", - ") for c in CC]\n", - "#curvedata" - ] - }, - { - "cell_type": "markdown", - "id": "907431f0-9bb0-467d-9230-154e92a0e259", - "metadata": { - "tags": [] - }, - "source": [ - "- `cid0`: shortened CID (same as in `debug_tkn2`)\n", - "- `exch`: the type of the curve / exchange in question\n", - "- `pair`: the normalized pair of the curve\n", - "- `mktp`: the current market price of that pair (according to `PRICES_RAW`)\n", - "- `bs`: whether curves buys (\"b\"), sells (\"s\") the primary tokenm, or both\n", - "- `tkn`: the primary token (base token of primary pair)\n", - "- `p`, `p_min`, `p_max`: the current / minimum / maximum price of the curve\n", - "- `tknp`: the price of `tkn` (as above) in terms of `TARGET_TOKEN`, as per the market price\n", - "- `wbp`: width of the range (p_max/p_min) in basis points \n", - "- `liq`: liquidity (in units of `tkn` as defined above; converted at curve price)\n", - "- `liqtt`: total curve liquidity (in `TARGET_TOKEN` units; converted at `mktp`)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "3deeac05-5364-413c-a93a-c9fe9f218c79", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid0exchpairmktpbstknpp_minp_maxtknpwbpliqliqtt
0ETH/USDP1naETH/USDP1950.0bsETH2000.00None1950.000.0488.32
1LINK/USDP1naLINK/USDP11.0bsLINK10.00None11.00200.002100.00
2LINK/USDP1naLINK/USDP11.0bsLINK15.00None11.00200.002600.00
\n", - "
" - ], - "text/plain": [ - " cid0 exch pair mktp bs tkn p p_min p_max tknp \\\n", - "0 ETH/USDP1 na ETH/USDP 1950.0 bs ETH 2000.0 0 None 1950.0 \n", - "1 LINK/USDP1 na LINK/USDP 11.0 bs LINK 10.0 0 None 11.0 \n", - "2 LINK/USDP1 na LINK/USDP 11.0 bs LINK 15.0 0 None 11.0 \n", - "\n", - " wbp liq liqtt \n", - "0 0 0.04 88.32 \n", - "1 0 200.00 2100.00 \n", - "2 0 200.00 2600.00 " - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "curvedf = pd.DataFrame(curvedata)\n", - "curvedf" - ] - }, - { - "cell_type": "markdown", - "id": "54d0478d-d748-4f9a-ae3a-753ab61cc8de", - "metadata": {}, - "source": [ - "For reference, the CID dataframe `ciddf` (separate because the field is too long; can be joined to `curvedf` via index)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "0cc8423f-726b-42f6-9144-2f1de1d98d12", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cid
0ETH/USDP1
1LINK/USDP1
2LINK/USDP1
\n", - "
" - ], - "text/plain": [ - " cid\n", - "0 ETH/USDP1\n", - "1 LINK/USDP1\n", - "2 LINK/USDP1" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ciddf = pd.DataFrame([dict(cid=c.cid) for c in CC])\n", - "ciddf" - ] - }, - { - "cell_type": "markdown", - "id": "94f35eba-137c-4adf-a167-2218e68410e6", - "metadata": {}, - "source": [ - "## MargPOptimizer" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "d0200904-33d4-4dbe-951e-bd4ee834a59b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[margp_optimizer] targettkn = USDP\n", - "[margp_optimizer] WARNING - providing `pstart` as parameter is deprecated; use `pstart` variable instead\n", - "[margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n", - "\n", - "[margp_optimizer] USDP <- LINK, ETH\n", - "[margp_optimizer] p 11.00, 1,950.00\n", - "[margp_optimizer] 1/p 0.09, 0.00\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "tknq USDP\n", - "dLINK/d%pLINK, dLINK/d%pETH\n", - "dETH/d%pLINK, dETH/d%pETH\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-1.05533124e+00 0.00000000e+00]\n", - " [ 0.00000000e+00 -1.12663177e-04]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 0 =======>>>\n", - "USDP <- LINK, ETH\n", - "dtkn 12.121, 0.000\n", - "log p0 [1.0413926851582251, 3.290034611362518]\n", - "d logp [0.04963352 0.01092629]\n", - "log p [1.09102621 3.3009609 ]\n", - "p_t (12.331792458048913, 1999.6818306633254) USDP\n", - "p 12.33, 1,999.68\n", - "1/p 0.08, 0.00\n", - "crit 5.08e-02 [1; L2], eps=1e-06, c/e=5e+04]\n", - "dtkn_d {'LINK': 12.12110054878761, 'USDP': -167.2304491816911, 'ETH': 0.0002848609078940148}\n", - "<<<========== cycle 0 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-9.96717100e-01 0.00000000e+00]\n", - " [ 0.00000000e+00 -1.11254817e-04]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 1 =======>>>\n", - "USDP <- LINK, ETH\n", - "dtkn 0.340, 0.000\n", - "log p0 [1.0910262070143644, 3.300960900574236]\n", - "d logp [1.47298910e-03 6.90936545e-05]\n", - "log p [1.0924992 3.30102999]\n", - "p_t (12.37368899542703, 1999.9999933904442) USDP\n", - "p 12.37, 2,000.00\n", - "1/p 0.08, 0.00\n", - "crit 1.47e-03 [1; L2], eps=1e-06, c/e=1e+03]\n", - "dtkn_d {'LINK': 0.3397422895124862, 'USDP': -29.455434369539958, 'ETH': 1.778832904499733e-06}\n", - "<<<========== cycle 1 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-9.95028249e-01 0.00000000e+00]\n", - " [ 0.00000000e+00 -1.11245967e-04]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 2 =======>>>\n", - "USDP <- LINK, ETH\n", - "dtkn 0.000, 0.000\n", - "log p0 [1.0924991961136497, 3.301029994228734]\n", - "d logp [1.24113200e-06 1.43527413e-09]\n", - "log p [1.09250044 3.30103 ]\n", - "p_t (12.37372435715507, 2000.0000000001257) USDP\n", - "p 12.37, 2,000.00\n", - "1/p 0.08, 0.00\n", - "crit 1.24e-06 [1; L2], eps=1e-06, c/e=1e+00]\n", - "dtkn_d {'LINK': 0.00028577981608179925, 'USDP': -25.25866483792602, 'ETH': 3.694854144864479e-11}\n", - "<<<========== cycle 2 =======\n", - "\n", - "[margp_optimizer]\n", - "============= JACOBIAN% =============>>>\n", - "[[-9.95026828e-01 0.00000000e+00]\n", - " [ 0.00000000e+00 -1.11245967e-04]]\n", - "<<<============= JACOBIAN% =============\n", - "\n", - "\n", - "[margp_optimizer]\n", - "========== cycle 3 =======>>>\n", - "USDP <- LINK, ETH\n", - "dtkn -0.000, -0.000\n", - "log p0 [1.0925004372456533, 3.3010299956640083]\n", - "d logp [-6.91863792e-12 -2.73585985e-14]\n", - "log p [1.09250044 3.30103 ]\n", - "p_t (12.373724356957945, 1999.9999999999998) USDP\n", - "p 12.37, 2,000.00\n", - "1/p 0.08, 0.00\n", - "crit 6.92e-12 [1; L2], eps=1e-06, c/e=7e-06]\n", - "dtkn_d {'LINK': -1.593065235283575e-09, 'USDP': -25.255128588697247, 'ETH': -7.042977312465837e-16}\n", - "<<<========== cycle 3 =======\n" - ] - }, - { - "data": { - "text/plain": [ - "CPCArbOptimizer.MargpOptimizerResult(result=-25.255128608410814, time=0.0014278888702392578, method='margp', targettkn='USDP', p_optimal_t=(12.373724356957945, 1999.9999999999998), dtokens_t=(0.0, 3.469446951953614e-18), tokens_t=('LINK', 'ETH'), errormsg=None)" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "O = MargPOptimizer(CC)\n", - "r = O.optimize(sfc=TARGET_TOKEN, params=dict(\n", - " pstart=PRICES,\n", - " verbose=True,\n", - " debug=False,\n", - " debug_j=True,\n", - " debug_dtkn=False,\n", - " debug_dtkn2=False,\n", - " debug_dtknd=True,\n", - "))\n", - "r" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "c35856f7-43b3-4c1a-9335-f5e66271fb0b", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "ename": "RuntimeError", - "evalue": "No active exception to reraise", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m\n", - "\u001b[0;31mRuntimeError\u001b[0m: No active exception to reraise" - ] - } - ], - "source": [ - "raise" - ] - }, - { - "cell_type": "markdown", - "id": "873df8d7-78da-4089-88d7-530eeea75570", - "metadata": {}, - "source": [ - "### Explanation\n", - "\n", - "Convergence criterium is \"relative\" with given epsilon using L2 norm (unit does not matter here)\n", - "\n", - " [margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2)\n", - "\n", - "Base token is `USDP`; the prices and their inverses shown in order `ETH`, `LINK`\n", - "\n", - " [margp_optimizer] USDP <- ETH, LINK\n", - " [margp_optimizer] p 1,950.00, 11.00\n", - " [margp_optimizer] 1/p 0.00, 0.09\n", - " \n", - "Jacobian explainer: quote token us USDP\n", - "`dETH/d%pLINK` means the change in ETH (in ETH units) when the `LINK/USDP` price changes by 1%\n", - "\n", - " [margp_optimizer]\n", - " ============= JACOBIAN% =============>>>\n", - " tknq USDP\n", - " dETH/d%pETH, dLINK/d%pETH\n", - " dETH/d%pLINK, dLINK/d%pLINK\n", - " <<<============= JACOBIAN% =============\n", - "\n", - "Actual Jacobian in the same format as the explainer\n", - "\n", - " [margp_optimizer]\n", - " ============= JACOBIAN% =============>>>\n", - " [[-0.01045332 0.005415 ]\n", - " [ 0.95994502 -1.90864222]]\n", - " <<<============= JACOBIAN% =============\n", - " \n", - "Results of cycle 0\n", - "\n", - " [margp_optimizer]\n", - " ========== cycle 0 =======>>>\n", - " USDP <- ETH, LINK\n", - " dtkn 0.101, -26.364\n", - " log p0 [3.290034611362518, 1.0413926851582251]\n", - " d logp [ 0.01472711 -0.05228352]\n", - " log p [3.30476172 0.98910917]\n", - " p_t (2017.2592691917046, 9.752347514669442) USDP\n", - " p 2,017.26, 9.75\n", - " 1/p 0.00, 0.10\n", - " crit 5.43e-02 [1; L2], eps=1e-06, c/e=5e+04]\n", - " dtkn_d {'ETH': 0.10113974590360497, 'USDP': 72.4594621534543, 'LINK': -26.36377863280171}\n", - " <<<========== cycle 0 =======" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1c5fb34b-2855-4db0-a9b0-92614510d7c5", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,py:light" - }, - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/resources/NBTest/Optimizer_9999_TEMPLATE.py b/resources/NBTest/Optimizer_9999_TEMPLATE.py deleted file mode 100644 index a489150fc..000000000 --- a/resources/NBTest/Optimizer_9999_TEMPLATE.py +++ /dev/null @@ -1,311 +0,0 @@ -# --- -# jupyter: -# jupytext: -# formats: ipynb,py:light -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.2 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# + -from tools.curves import ConstantProductCurve, CurveContainer, SimplePair -from tools.optimizer import CPCArbOptimizer, PairOptimizer, MargPOptimizer -CPC = ConstantProductCurve - -import pandas as pd - -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(SimplePair)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CurveContainer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(PairOptimizer)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MargPOptimizer)) -# - - -# # Optimizer Testing (TEMPLATE) - -# This is a light workbook allowing to look at issues that may arise when running the optimizer on a specific set of curves. -# -# Instructions: -# -# - locate the **exact** curve set to feed to the optimizer (it will be somewhere in the logging output, and it will be a list of ConstantProductCurve objects) -# - assign it to the `CurvesRaw` variable as shown below -# - add the missing token addresses to the `TOKENS` dict below -# - provide consistent values for `PSTART` -# - run the workbook -# - if the import statement fails, ensure `fastlane_bot` is on the path, or create symlink to `tools` - -# ### >> Enter curves -# -# Place curves here in the form -# -# CurvesRaw = [ -# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, ...), -# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, ...), -# ... -# ] - -CurvesRaw = [ - CPC.from_pk(pair="ETH_/USDP_", cid="ETH/USDP1", p=2000, k=1), # 1E+$2000 @ 2000 - # CPC.from_pk(pair="ETH_/USDP_", cid="ETH/USDP1", p=2000, k=1*2000*1), # 1E+$2000 @ 2000 - # CPC.from_pk(pair="ETH_/USDP_", cid="ETH/USDP1", p=3000, k=1*3000*1), # 1E+$2000 @ 2000 - CPC.from_pk(pair="LINK_/USDP_", cid="LINK/USDP1", p= 10, k=100*1000), # 200L+$2000 @ 10 - CPC.from_pk(pair="LINK_/USDP_", cid="LINK/USDP1", p= 15, k=100*1500), # 200L+$2000 @ 10 - # CPC.from_pk(pair="ETH_/LINK_", cid="ETH/LINK1", p= 210, k=1*210*0.0000000000001), # ~1E @ 210 -] -CCRaw = CurveContainer(CurvesRaw) - -# + -# CurvesRaw = [ -# ConstantProductCurve(k=27518385.40998667, x=1272.2926367501436, x_act=0, y_act=2000.9999995236503, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 2000.9999995236503, 'yint': 2000.9999995236503, 'A': 0.38144823884371704, 'B': 3.7416573867739373, 'pa': 16.99999999999995, 'pb': 13.99999999999997}), -# ConstantProductCurve(k=6.160500599566333e+18, x=11099999985.149971, x_act=0, y_act=55.50000002646446, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x425d5d4ad7243f88d9f4cde8da52863b45af1f64e05bede1299909bcaa6c52d1-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 55.50000002646446, 'yint': 55.50000002646446, 'A': 0, 'B': 0.22360678656963742, 'pa': 0.04999999999999889, 'pb': 0.04999999999999889}), -# ConstantProductCurve(k=14449532.299465338, x=57487.82879658422, x_act=0, y_act=5.0, alpha=0.5, pair='0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-0', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 8.582730309868262, 'A': 0.002257868117407469, 'B': 0.06480740698407672, 'pa': 0.004497751124437756, 'pb': 0.004199999999999756}), -# ConstantProductCurve(k=14456757.06563651, x=251.4750925240284, x_act=0, y_act=807.9145301701096, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x514910771AF9Ca656af840dff83E8264EcF986CA', cid='0x3fcccfe0063b71fc973fab8dea39b6be9da80125910c10e57b924b3e4687295a-1', fee=2000, descr='carbon_v1 0x514910771AF9Ca656af840dff83E8264EcF986CA/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 807.9145301701096, 'yint': 1974.7090228584536, 'A': 0.519359008452966, 'B': 14.907119849998594, 'pa': 237.97624997025295, 'pb': 222.22222222222211}), -# ConstantProductCurve(k=56087178.30932376, x=131.6236694086859, x_act=0, y_act=15920.776548455418, alpha=0.5, pair='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/0x8E870D67F660D95d5be530380D0eC0bd388289E1', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-0', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 15920.776548455418, 'yint': 32755.67010983316, 'A': 4.373757425036729, 'B': 54.77225575051648, 'pa': 3498.2508745627138, 'pb': 2999.9999999999854}), -# ConstantProductCurve(k=56059148.73497429, x=426117.72306081816, x_act=0, y_act=5.0, alpha=0.5, pair='0x8E870D67F660D95d5be530380D0eC0bd388289E1/0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', cid='0x6cc4b198ec4cf17fdced081b5611279be73e200711238068b5340e606ba86646-1', fee=2000, descr='carbon_v1 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\/0x8E870D67F660D95d5be530380D0eC0bd388289E1 2000', constr='carb', params={'exchange': 'carbon_v1', 'y': 5.0, 'yint': 10.106093048875099, 'A': 0.0013497708452092638, 'B': 0.016903085094568837, 'pa': 0.0003331667499582927, 'pb': 0.0002857142857142352}) -# ] -# CCRaw = CurveContainer(CurvesRaw) -# - - -# ### >> Enter prices -# -# Provide current prices (`pstart`) here, in the format -# -# PRICES = { -# '0x8E87...': 0.0003087360213944532, -# '0x5149...': 0.004372219704179475, -# '0xEeee...': 1 -# } -# -# The price numeraire does not matter as long as they are all in the same numeraire. All tokens must be present. Additional tokens can be added and will be ignored. The keys in the dict here must correspond exactly to the -# keys that are used in the pairs in the curves above. - -PRICES_RAW = { - 'ETH_': 1950, - 'LINK_': 11, - 'USDP_': 1 -} - -# + -# PRICES_RAW = { -# '0x8E870D67F660D95d5be530380D0eC0bd388289E1': 0.0003087360213944532, -# '0x514910771AF9Ca656af840dff83E8264EcF986CA': 0.004372219704179475, -# '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 1 -# } -# - - -# ### >> Enter tokens -# -# Provide token tickers here, in the format -# -# TOKENS = { -# "0x5149...": "LINK", -# "0x8E87...": "USDP", -# "0xEeee...": "ETH", -# } -# -# All tokens must be present. Additional tokens will be ignored. You must also provide the `TARGET_TOKEN_RAW`, -# for example by picking from the token list - -# + -# TOKENS = { -# "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE": "ETH", -# "0x514910771AF9Ca656af840dff83E8264EcF986CA": "LINK", -# "0x8E870D67F660D95d5be530380D0eC0bd388289E1": "USDP", -# } - -# TARGET_TOKEN_RAW = list(TOKENS)[0] -# TARGET_TOKEN_RAW - -# + -TOKENS = { - "ETH_": "ETH", - "LINK_": "LINK", - "USDP_": "USDP", -} - -TARGET_TOKEN_RAW = list(TOKENS)[-1] -TARGET_TOKEN_RAW -# - - -# ### >>> Run optimizer -# -# please make sure that this line runs without errors (other than the error that needs to be addressed of course) - -O = MargPOptimizer(CCRaw) -r = O.optimize(sfc=TARGET_TOKEN_RAW, params=dict(pstart=PRICES_RAW)) -r - - -# **do not worry about the code below here; this is for the actual testing and will be adapted as need be** - -# ### >>> Preprocessing -# -# Please ensure that this code runs without error. Errors here mean that the data provided above is not consistent. - -# + -def replace_tokens(dct): - """replaces the token address with the token name in dct""" - tkns = dct["pair"].split("/") - for i in range(len(tkns)): - #tkns[i] = TOKENS.get(tkns[i]) or tkns[i] - tkns[i] = TOKENS[tkns[i]] - dct["pair"] = "/".join(tkns) - return dct - -def p(pair=None, *, tknb=None, tknq=None, prices=None): - "price of tknb in terms of tknq" - if not pair is None: - tknb, tknq = pair.split("/") - p = prices or PRICES - return p[tknb]/p[tknq] - -def round_(x, *args): - "forgiving round()" - try: - return round(x, *args) - except: - return x - -def wbp(c): - "width of the range in bp [0 means infty]" - try: - return max(int((c.p_max_primary()/c.p_min_primary() - 1)*10000), 1) - except: - return 0 - -def cid0(c): - "shortened cid (for standard format ones)" - if len(c.cid) < 20: return c.cid - return f"{c.cid[2:6]}{c.cid[-2:]}" - - -# - - -# If this fails this probably means that one of the tokens has not been defined above - -CC = CurveContainer.from_dicts([replace_tokens(d) for d in CCRaw.asdicts()]) -PRICES = {TOKENS[addr]:price for addr, price in PRICES_RAW.items()} -TARGET_TOKEN = TOKENS[TARGET_TOKEN_RAW] -PRICES - -# Here you can change the preference order of numeraire tokens (in a pair, the one with the lower number will be chosen as numeraire; tokens not present here are considered to have higher numbers; draw means alphabetic order). -# -# The specific code below ensures that in ETH/LINK, LINK is the quote token and ETH the base token. As LINK is not in the list, otherwise this would be the other way round. - -SimplePair.NUMERAIRE_TOKENS["LINK"] = SimplePair.NUMERAIRE_TOKENS["ETH"] - 1 -#SimplePair.NUMERAIRE_TOKENS - -# ## Curves - -print("Num curves: ", len(CC)) -print("Pairs: ", set(c.pairo.primary_n for c in CC)) -print("Target token: ", TARGET_TOKEN) - -PRICE_DECIMALS = 2 -curvedata = [dict( - cid0 = cid0(c), - exch = c.params.get('exchange', "na"), - pair = c.pairo.primary_n, - mktp = round(p(c.pairo.primary_n), PRICE_DECIMALS), - bs = c.buysell(), - tkn = c.pairo.primary_tknb, - p = round_(c.primaryp(), PRICE_DECIMALS), - p_min = round_(c.p_min_primary(), PRICE_DECIMALS), - p_max = round_(c.p_max_primary(), PRICE_DECIMALS), - tknp = p(tknb=c.pairo.primary_tknb, tknq=TARGET_TOKEN), - wbp = wbp(c), - liq = round(c.tvl(tkn=c.pairo.primary_tknb), 2), - liqtt = round(c.x_act*p(tknb=c.tknx, tknq=TARGET_TOKEN) + c.y_act*p(tknb=c.tkny, tknq=TARGET_TOKEN), 2), -) for c in CC] -#curvedata - -# - `cid0`: shortened CID (same as in `debug_tkn2`) -# - `exch`: the type of the curve / exchange in question -# - `pair`: the normalized pair of the curve -# - `mktp`: the current market price of that pair (according to `PRICES_RAW`) -# - `bs`: whether curves buys ("b"), sells ("s") the primary tokenm, or both -# - `tkn`: the primary token (base token of primary pair) -# - `p`, `p_min`, `p_max`: the current / minimum / maximum price of the curve -# - `tknp`: the price of `tkn` (as above) in terms of `TARGET_TOKEN`, as per the market price -# - `wbp`: width of the range (p_max/p_min) in basis points -# - `liq`: liquidity (in units of `tkn` as defined above; converted at curve price) -# - `liqtt`: total curve liquidity (in `TARGET_TOKEN` units; converted at `mktp`) -# - -curvedf = pd.DataFrame(curvedata) -curvedf - -# For reference, the CID dataframe `ciddf` (separate because the field is too long; can be joined to `curvedf` via index) - -ciddf = pd.DataFrame([dict(cid=c.cid) for c in CC]) -ciddf - -# ## MargPOptimizer - -O = MargPOptimizer(CC) -r = O.optimize(sfc=TARGET_TOKEN, params=dict( - pstart=PRICES, - verbose=True, - debug=False, - debug_j=True, - debug_dtkn=False, - debug_dtkn2=False, - debug_dtknd=True, -)) -r - -raise - -# ### Explanation -# -# Convergence criterium is "relative" with given epsilon using L2 norm (unit does not matter here) -# -# [margp_optimizer] crit=rel (eps=1e-06, unit=1, norm=L2) -# -# Base token is `USDP`; the prices and their inverses shown in order `ETH`, `LINK` -# -# [margp_optimizer] USDP <- ETH, LINK -# [margp_optimizer] p 1,950.00, 11.00 -# [margp_optimizer] 1/p 0.00, 0.09 -# -# Jacobian explainer: quote token us USDP -# `dETH/d%pLINK` means the change in ETH (in ETH units) when the `LINK/USDP` price changes by 1% -# -# [margp_optimizer] -# ============= JACOBIAN% =============>>> -# tknq USDP -# dETH/d%pETH, dLINK/d%pETH -# dETH/d%pLINK, dLINK/d%pLINK -# <<<============= JACOBIAN% ============= -# -# Actual Jacobian in the same format as the explainer -# -# [margp_optimizer] -# ============= JACOBIAN% =============>>> -# [[-0.01045332 0.005415 ] -# [ 0.95994502 -1.90864222]] -# <<<============= JACOBIAN% ============= -# -# Results of cycle 0 -# -# [margp_optimizer] -# ========== cycle 0 =======>>> -# USDP <- ETH, LINK -# dtkn 0.101, -26.364 -# log p0 [3.290034611362518, 1.0413926851582251] -# d logp [ 0.01472711 -0.05228352] -# log p [3.30476172 0.98910917] -# p_t (2017.2592691917046, 9.752347514669442) USDP -# p 2,017.26, 9.75 -# 1/p 0.00, 0.10 -# crit 5.43e-02 [1; L2], eps=1e-06, c/e=5e+04] -# dtkn_d {'ETH': 0.10113974590360497, 'USDP': 72.4594621534543, 'LINK': -26.36377863280171} -# <<<========== cycle 0 ======= - -