Skip to content

Commit

Permalink
Merge pull request #88 from bancorprotocol/balancer2
Browse files Browse the repository at this point in the history
Balancer2
  • Loading branch information
mikewcasale authored Aug 31, 2023
2 parents 58a385a + 3169396 commit 5d3c29e
Show file tree
Hide file tree
Showing 15 changed files with 2,247 additions and 790 deletions.
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

0 comments on commit 5d3c29e

Please sign in to comment.