Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Balancer2 #88

Merged
merged 9 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added BRANCH_BALANCER2
Empty file.
56 changes: 53 additions & 3 deletions fastlane_bot/tools/cpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
NOTE: this class is not part of the API of the Carbon protocol, and you must expect breaking
changes even in minor version updates. Use at your own risk.
"""
__VERSION__ = "3.0"
__DATE__ = "22/Aug/2023"
__VERSION__ = "3.1"
__DATE__ = "25/Aug/2023"

from dataclasses import dataclass, field, asdict, InitVar
from .simplepair import SimplePair as Pair
Expand All @@ -25,6 +25,7 @@
from sys import float_info
from hashlib import md5 as digest
import time
from .cpcbase import CurveBase

try:
dataclass_ = dataclass(frozen=True, kw_only=True)
Expand Down Expand Up @@ -347,7 +348,7 @@ def __getattr__(self, name):


@dataclass_
class ConstantProductCurve:
class ConstantProductCurve(CurveBase):
"""
represents a, potentially levered, constant product curve
Expand Down Expand Up @@ -1247,6 +1248,25 @@ def kbar(self):
return sqrt(self.k)
return self.k**self.alpha

def invariant(self, xvec=None, *, include_target=False):
"""
returns the actual invariant of the curve (eg x*y for constant product)
:xvec: vector of x values (default: current)
:include_target: if True, the target invariant returned in addition to the actual invariant
:returns: invariant, or (invariant, target)
"""
if xvec is None:
xvec = {self.tknx: self.x, self.tkny: self.y}
x,y = xvec[self.tknx], xvec[self.tkny]
if self.is_constant_product():
invariant = sqrt(x * y)
else:
invariant = x**self.alpha * y**(1-self.alpha)
if not include_target:
return invariant
return (invariant, self.kbar)

@property
def x_min(self):
"minimum (virtual) x value"
Expand Down Expand Up @@ -1404,6 +1424,21 @@ def xyfromp_f(self, p=None, *, ignorebounds=False, withunits=False):

return x, y, p

def xvecfrompvec_f(self, pvec, *, ignorebounds=False):
"""
alternative API to xyfromp_f
:pvec: a dict containing all prices; the dict must contain the keys
for tknx and for tkny and the associated value must be the respective
price in any numeraire (only the ratio is used)
:returns: token amounts as dict {tknx: x, tkny: y}
"""
assert self.tknx in pvec, f"pvec must contain price for {self.tknx} [{pvec.keys()}]"
assert self.tkny in pvec, f"pvec must contain price for {self.tkny} [{pvec.keys()}]"
p = pvec[self.tknx] / pvec[self.tkny]
x, y, _ = self.xyfromp_f(p, ignorebounds=ignorebounds)
return {self.tknx: x, self.tkny: y}

def dxdyfromp_f(self, p=None, *, ignorebounds=False, withunits=False):
"""like xyfromp_f, but returns dx,dy,p instead of x,y,p"""
x, y, p = self.xyfromp_f(p, ignorebounds=ignorebounds)
Expand All @@ -1412,6 +1447,21 @@ def dxdyfromp_f(self, p=None, *, ignorebounds=False, withunits=False):
if withunits:
return dx, dy, p, self.tknxp, self.tknyp, self.pairp
return dx, dy, p

def dxvecfrompvec_f(self, pvec, *, ignorebounds=False):
"""
alternative API to dxdyfromp_f
:pvec: a dict containing all prices; the dict must contain the keys
for tknx and for tkny and the associated value must be the respective
price in any numeraire (only the ratio is used)
:returns: token difference amounts as dict {tknx: dx, tkny: dy}
"""
assert self.tknx in pvec, f"pvec must contain price for {self.tknx} [{pvec.keys()}]"
assert self.tkny in pvec, f"pvec must contain price for {self.tkny} [{pvec.keys()}]"
p = pvec[self.tknx] / pvec[self.tkny]
dx, dy, _ = self.dxdyfromp_f(p, ignorebounds=ignorebounds)
return {self.tknx: dx, self.tkny: dy}

def yfromx_f(self, x, *, ignorebounds=False):
"y value for given x value (if in range; None otherwise)"
Expand Down
51 changes: 51 additions & 0 deletions fastlane_bot/tools/cpcbase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
base class for representing a generic curve in the context of the optimizer*

(c) Copyright Bprotocol foundation 2023.
Licensed under MIT

*whilst the name of the file ("cpc") alludes to constant product curves, this is for
historical reasons only; this class deal with generic curves

NOTE: this class is not part of the API of the Carbon protocol, and you must expect breaking
changes even in minor version updates. Use at your own risk.
"""
from abc import ABC, abstractmethod
class CurveBase(ABC):
"""
base class for representing a generic curve in the context of the optimizer
"""

@abstractmethod
def dxvecfrompvec_f(self, pvec, *, ignorebounds=False):
"""
get token holding vector xvec from price vector pvec

:pvec: a dict containing all prices; the dict must contain the keys
for tknx and for tkny and the associated value must be the respective
price in any numeraire (only the ratio is used)
:returns: token difference amounts as dict {tknx: dx, tkny: dy}
"""
raise NotImplementedError("dxvecfrompvec_f must be implemented by subclass")

@abstractmethod
def xvecfrompvec_f(self, pvec, *, ignorebounds=False):
"""
get change in token holding vector xvec, dxvec, from price vector pvec

:pvec: a dict containing all prices; the dict must contain the keys
for tknx and for tkny and the associated value must be the respective
price in any numeraire (only the ratio is used)
:returns: token amounts as dict {tknx: x, tkny: y}
"""
raise NotImplementedError("dxvecfrompvec_f must be implemented by subclass")

@abstractmethod
def invariant(self, include_target=False):
"""
returns the actual invariant of the curve (eg x*y for constant product)

:include_target: if True, the target invariant returned in addition to the actual invariant
:returns: invariant, or (invariant, target)
"""
raise NotImplementedError("invariant must be implemented by subclass")
34 changes: 25 additions & 9 deletions fastlane_bot/tools/optimizer/margpoptimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
This module is still subject to active research, and comments and suggestions are welcome.
The corresponding author is Stefan Loesch <[email protected]>
"""
__VERSION__ = "5.0"
__DATE__ = "26/Jul/2023"
__VERSION__ = "5.1"
__DATE__ = "25/Aug/2023"

from dataclasses import dataclass, field, fields, asdict, astuple, InitVar
import pandas as pd
Expand Down Expand Up @@ -211,7 +211,13 @@ def dtknfromp_f(p, *, islog10=True, asdct=False, quiet=False):
print(f"\n[dtknfromp_f] =====================>>>")
print(f"prices={p}")
print(f"tokens={tokens_t}")


# pvec is dict {tkn -> (log) price} for all tokens in p
pvec = {tkn: p_ for tkn, p_ in zip(tokens_t, p)}
pvec[targettkn] = 1
if P("debug") and not quiet:
print(f"pvec={pvec}")

sum_by_tkn = {t: 0 for t in alltokens_s}
for pair, (tknb, tknq) in zip(pairs, pairs_t):
if get(p, tokens_ix.get(tknq)) > 0:
Expand All @@ -221,8 +227,14 @@ def dtknfromp_f(p, *, islog10=True, asdct=False, quiet=False):
price = 1
curves = curves_by_pair[pair]
c0 = curves[0]
dxdy = tuple(dxdy_f(c.dxdyfromp_f(price)) for c in curves)
#dxdy = tuple(dxdy_f(c.dxdyfromp_f(price)) for c in curves)
dxvecs = (c.dxvecfrompvec_f(pvec) for c in curves)

if P("debug2") and not quiet:
dxdy = tuple(dxdy_f(c.dxdyfromp_f(price)) for c in curves)
# TODO: rewrite this using the dxvec
# there is no need to extract dy dx; just iterate over dict
# however not urgent because this is debug code
print(f"\n{c0.pairp} --->>")
print(f" price={price:,.4f}, 1/price={1/price:,.4f}")
for r, c in zip(dxdy, curves):
Expand All @@ -233,12 +245,16 @@ def dtknfromp_f(p, *, islog10=True, asdct=False, quiet=False):
print(s)
print(f"<<--- {c0.pairp}")

sumdx, sumdy = sum(dxdy)
sum_by_tkn[tknq] += sumdy
sum_by_tkn[tknb] += sumdx
# old code from dxdy = tuple(dxdy_f(c.dxdyfromp_f(price)) for c in curves)
# sumdx, sumdy = sum(dxdy)
# sum_by_tkn[tknq] += sumdy
# sum_by_tkn[tknb] += sumdx
for dxvec in dxvecs:
for tkn, dx_ in dxvec.items():
sum_by_tkn[tkn] += dx_

if P("debug") and not quiet:
print(f"pair={c0.pairp}, {sumdy:,.4f} {tn(tknq)}, {sumdx:,.4f} {tn(tknb)}, price={price:,.4f} {tn(tknq)} per {tn(tknb)} [{len(curves)} funcs]")
# if P("debug") and not quiet:
# print(f"pair={c0.pairp}, {sumdy:,.4f} {tn(tknq)}, {sumdx:,.4f} {tn(tknb)}, price={price:,.4f} {tn(tknq)} per {tn(tknb)} [{len(curves)} funcs]")

result = tuple(sum_by_tkn[t] for t in tokens_t)
if P("debug") and not quiet:
Expand Down
21 changes: 12 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
Licensed under MIT
"""

env_var = "TENDERLY_FORK_ID"
with open(".env", "r") as file:
lines = file.readlines()

with open(".env", "w") as file:
for line in lines:
if line.startswith(f"{env_var}=") or line.startswith(f"export {env_var}="):
line = f"{env_var}="
file.write(line)
try:
env_var = "TENDERLY_FORK_ID"
with open(".env", "r") as file:
lines = file.readlines()

with open(".env", "w") as file:
for line in lines:
if line.startswith(f"{env_var}=") or line.startswith(f"export {env_var}="):
line = f"{env_var}="
file.write(line)
except:
pass

import time
from typing import List
Expand Down
Loading
Loading