From ed50381d9818b293ef61490c377008ff585ac803 Mon Sep 17 00:00:00 2001
From: sklbancor <109073706+sklbancor@users.noreply.github.com>
Date: Fri, 3 May 2024 23:17:16 +0100
Subject: [PATCH] NBTest 102
---
resources/NBTest/NBTest_102_APIBasics.ipynb | 1403 +++++++++++++++++++
resources/NBTest/NBTest_102_APIBasics.py | 102 +-
2 files changed, 1499 insertions(+), 6 deletions(-)
create mode 100644 resources/NBTest/NBTest_102_APIBasics.ipynb
diff --git a/resources/NBTest/NBTest_102_APIBasics.ipynb b/resources/NBTest/NBTest_102_APIBasics.ipynb
new file mode 100644
index 000000000..92864ef97
--- /dev/null
+++ b/resources/NBTest/NBTest_102_APIBasics.ipynb
@@ -0,0 +1,1403 @@
+{
+ "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-alpha02 (04/May/2024)\n",
+ "CurveContainer v4.0-alpha02 (04/May/2024)\n",
+ "MargPOptimizer v6.0-alpha02 (04/May/2024)\n"
+ ]
+ }
+ ],
+ "source": [
+ "try:\n",
+ " from fastlane_bot.tools.cpc import CurveBase, ConstantProductCurve as CPC, CurveContainer\n",
+ " from fastlane_bot.tools.optimizer import MargPOptimizer\n",
+ " from fastlane_bot.testing import *\n",
+ "\n",
+ "except:\n",
+ " from tools.cpc import CurveBase, ConstantProductCurve as CPC, CurveContainer\n",
+ " from tools.optimizer import MargPOptimizer\n",
+ " from tools.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 [NBTest102]\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(x=10, y=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(x=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(y=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.0003840923309326172, 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.538042440545, time=0.0003368854522705078, method='margp', targettkn='USDC', p_optimal_t=(10.931723975202656,), dtokens_t=(-2.9103830456733704e-11,), 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",
+ " pair | \n",
+ " pairp | \n",
+ " tknin | \n",
+ " tknout | \n",
+ " USDC | \n",
+ " LINK | \n",
+ "
\n",
+ " \n",
+ " cid | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " c10 | \n",
+ " LINK/USDC | \n",
+ " LINK/USDC | \n",
+ " USDC | \n",
+ " LINK | \n",
+ " 113872.124742 | \n",
+ " -10891.133853 | \n",
+ "
\n",
+ " \n",
+ " c12 | \n",
+ " LINK/USDC | \n",
+ " LINK/USDC | \n",
+ " LINK | \n",
+ " USDC | \n",
+ " -124740.662784 | \n",
+ " 10891.133853 | \n",
+ "
\n",
+ " \n",
+ "
\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",
+ " pair | \n",
+ " pairp | \n",
+ " tknin | \n",
+ " tknout | \n",
+ " USDC | \n",
+ " LINK | \n",
+ "
\n",
+ " \n",
+ " cid | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " c10 | \n",
+ " LINK/USDC | \n",
+ " LINK/USDC | \n",
+ " USDC | \n",
+ " LINK | \n",
+ " 113872.124742 | \n",
+ " -10891.133853 | \n",
+ "
\n",
+ " \n",
+ " c12 | \n",
+ " LINK/USDC | \n",
+ " LINK/USDC | \n",
+ " LINK | \n",
+ " USDC | \n",
+ " -124740.662784 | \n",
+ " 10891.133853 | \n",
+ "
\n",
+ " \n",
+ "
\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",
+ " USDC | \n",
+ " LINK | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " c10 | \n",
+ " 113872.124742 | \n",
+ " -1.089113e+04 | \n",
+ "
\n",
+ " \n",
+ " c12 | \n",
+ " -124740.662784 | \n",
+ " 1.089113e+04 | \n",
+ "
\n",
+ " \n",
+ " PRICE | \n",
+ " 1.000000 | \n",
+ " 1.093172e+01 | \n",
+ "
\n",
+ " \n",
+ " AMMIn | \n",
+ " 113872.124742 | \n",
+ " 1.089113e+04 | \n",
+ "
\n",
+ " \n",
+ " AMMOut | \n",
+ " -124740.662784 | \n",
+ " -1.089113e+04 | \n",
+ "
\n",
+ " \n",
+ " TOTAL NET | \n",
+ " -10868.538042 | \n",
+ " -2.910383e-11 | \n",
+ "
\n",
+ " \n",
+ "
\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",
+ " fee | \n",
+ " pair | \n",
+ " amt_tknq | \n",
+ " tknq | \n",
+ " margp0 | \n",
+ " effp | \n",
+ " margp | \n",
+ " gain_r | \n",
+ " gain_tknq | \n",
+ " gain_ttkn | \n",
+ "
\n",
+ " \n",
+ " exch | \n",
+ " cid | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " NaN | \n",
+ " c12 | \n",
+ " None | \n",
+ " LINK/USDC | \n",
+ " -124740.662784 | \n",
+ " USDC | \n",
+ " 12.0 | \n",
+ " 11.453414 | \n",
+ " 10.931724 | \n",
+ " 0.047723 | \n",
+ " 5952.943453 | \n",
+ " 5952.943453 | \n",
+ "
\n",
+ " \n",
+ " c10 | \n",
+ " None | \n",
+ " LINK/USDC | \n",
+ " 113872.124742 | \n",
+ " USDC | \n",
+ " 10.0 | \n",
+ " 10.455488 | \n",
+ " 10.931724 | \n",
+ " 0.043565 | \n",
+ " 4960.786211 | \n",
+ " 4960.786211 | \n",
+ "
\n",
+ " \n",
+ "
\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": null,
+ "id": "5de61457-828c-48fc-a5dc-25fc2c2914e0",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ca17dbf8-222d-4880-9c37-06653d157610",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "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_102_APIBasics.py b/resources/NBTest/NBTest_102_APIBasics.py
index 17f5c1c03..6ef22b960 100644
--- a/resources/NBTest/NBTest_102_APIBasics.py
+++ b/resources/NBTest/NBTest_102_APIBasics.py
@@ -16,12 +16,12 @@
# +
try:
- from fastlane_bot.tools.cpc import CurveBase, ConstantProductCurve as CPC, CPCContainer
+ from fastlane_bot.tools.cpc import CurveBase, ConstantProductCurve as CPC, CurveContainer
from fastlane_bot.tools.optimizer import MargPOptimizer
from fastlane_bot.testing import *
except:
- from tools.cpc import CurveBase, ConstantProductCurve as CPC, CPCContainer
+ from tools.cpc import CurveBase, ConstantProductCurve as CPC, CurveContainer
from tools.optimizer import MargPOptimizer
from tools.testing import *
@@ -33,7 +33,7 @@
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(CPCContainer))
+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')
@@ -301,14 +301,104 @@ def invariant(self, include_target=False):
# #### Uniswap v3 constructor
-raises(CPC.from_univ2, y=10, **kwargs)
+# +
+# TODO
+# -
-# ### CurveContainer CPCContainer
+# ### CurveContainer
#
# A `CurveContainer` (legacy name: `CPCContainer`) is a container object for curve objects (`CurveBase` derivatives)
+# +
+# TODO
+# -
+
# ## MargPOptimizer
-pass
+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)
+
+