-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #163 from curveresearch/bonding-curve
Refactor and test bonding curve
- Loading branch information
Showing
7 changed files
with
202 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Added | ||
----- | ||
- End-to-end test for the bonding curve that creates a pool | ||
using the `make` pool factory. This covers some important | ||
gaps in our codebase. | ||
|
||
|
||
Changed | ||
------- | ||
- Refactored the bonding curve function, separating the core logic | ||
from the plotting functionality. | ||
- Created `tools` module to house the bonding curve and in anticipation | ||
of further tools, e.g. orderbook. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
"""Package to simulate Curve pool.""" | ||
__all__ = ["autosim", "bonding_curve", "order_book", "__version__", "__version_info__"] | ||
|
||
from ._bonding_curve import bonding_curve | ||
from ._order_book import order_book | ||
from .sim import autosim | ||
from .tools import bonding_curve | ||
from .version import __version__, __version_info__ |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
"Handy functions for the user interacting with Curvesim pools." | ||
|
||
__all__ = ["bonding_curve"] | ||
|
||
from .bonding_curve import bonding_curve |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
""" | ||
Contains the bonding_curve function, which computes a pool's bonding | ||
curve and current reserves for each pair of coins and optionally | ||
plots the curves using Matplotlib. | ||
""" | ||
from itertools import combinations | ||
|
||
import matplotlib.pyplot as plt | ||
from numpy import linspace | ||
|
||
from curvesim.pool import CurveMetaPool | ||
|
||
D_UNIT = 10**18 | ||
|
||
|
||
def bonding_curve(pool, *, truncate=0.0005, resolution=1000, plot=False): | ||
""" | ||
Computes and optionally plots a pool's bonding curve and current reserves. | ||
Parameters | ||
---------- | ||
pool : CurvePool or CurveMetaPool | ||
The pool object for which the bonding curve is computed. | ||
truncate : float, optional (default=0.0005) | ||
Determines where to truncate the bonding curve. The truncation point is given | ||
by D*truncate, where D is the total supply of tokens in the pool. | ||
resolution : int, optional (default=1000) | ||
The number of points to compute along the bonding curve. | ||
plot : bool, optional (default=False) | ||
Plots the bonding curves using Matplotlib. | ||
Returns | ||
------- | ||
pair_to_curve : dict | ||
Dictionary with coin index pairs as keys and lists of corresponding reserves | ||
as values. Each list of reserves is a list of pairs, where each pair consists | ||
of the reserves for the first and second coin of the corresponding pair. | ||
Example | ||
-------- | ||
>>> import curvesim | ||
>>> pool_address = "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7" | ||
>>> pool = curvesim.pool.get(pool_address) | ||
>>> pair_to_curve = curvesim.bonding_curve(pool, plot=True) | ||
""" | ||
|
||
if isinstance(pool, CurveMetaPool): | ||
combos = [(0, 1)] | ||
else: | ||
combos = combinations(range(pool.n), 2) | ||
|
||
D = pool.D() | ||
xp = pool._xp() # pylint: disable=protected-access | ||
|
||
pair_to_curve = {} | ||
for (i, j) in combos: | ||
truncated_D = int(D * truncate) | ||
x_max = pool.get_y(j, i, truncated_D, xp) | ||
xs = linspace(truncated_D, x_max, resolution).round() | ||
|
||
curve = [] | ||
for x in xs: | ||
y = pool.get_y(i, j, int(x), xp) | ||
curve.append((x, y)) | ||
curve = [(x / D_UNIT, y / D_UNIT) for x, y in curve] | ||
pair_to_curve[(i, j)] = curve | ||
|
||
if plot: | ||
labels = pool.coin_names | ||
if not labels: | ||
labels = [f"Coin {str(label)}" for label in range(pool.n)] | ||
|
||
_plot_bonding_curve(pair_to_curve, labels, xp) | ||
|
||
return pair_to_curve | ||
|
||
|
||
def _plot_bonding_curve(pair_to_curve, labels, xp): | ||
n = len(pair_to_curve) | ||
_, axs = plt.subplots(1, n, constrained_layout=True) | ||
if n == 1: | ||
axs = [axs] | ||
|
||
for pair, ax in zip(pair_to_curve, axs): | ||
curve = pair_to_curve[pair] | ||
xs, ys = zip(*curve) | ||
ax.plot(xs, ys, color="black") | ||
|
||
i, j = pair | ||
ax.scatter(xp[i] / D_UNIT, xp[j] / D_UNIT, s=40, color="black") | ||
ax.set_xlabel(labels[i]) | ||
ax.set_ylabel(labels[j]) | ||
|
||
plt.show() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import curvesim | ||
from curvesim import bonding_curve | ||
|
||
|
||
def test_bonding_curve_stableswap(): | ||
"""Simple test of the bonding curve for a regular stableswap.""" | ||
A = 2000 | ||
balances = [96930673769101734848937206, 96029665968769, 94203880672841] | ||
rates = [10**18, 10**30, 10**30] | ||
pool = curvesim.pool.make(A, balances, 3, rates=rates) | ||
pair_to_curve = bonding_curve(pool, resolution=5) | ||
expected_result = { | ||
(0, 1): [ | ||
(143582.10515040305, 207709896.10151905), | ||
(52035160.60424256, 140938067.54743478), | ||
(103926739.10333471, 89033886.31117772), | ||
(155818317.6024269, 37171084.50615266), | ||
(207709896.10151905, 143582.1051504031), | ||
], | ||
(0, 2): [ | ||
(143582.10515040305, 205740351.86334246), | ||
(51542774.54469842, 139604657.24397892), | ||
(102941966.98424643, 88192864.27513982), | ||
(154341159.42379445, 36822438.40404793), | ||
(205740351.86334246, 143582.10515040308), | ||
], | ||
(1, 2): [ | ||
(143582.10515040305, 204771181.49157524), | ||
(51300481.95175662, 138945948.269023), | ||
(102457381.79836284, 87776447.07614492), | ||
(153614281.64496905, 36648317.74309717), | ||
(204771181.49157527, 143582.10515040296), | ||
], | ||
} | ||
assert pair_to_curve == expected_result | ||
|
||
|
||
def test_bonding_curve_metapool(): | ||
"""Simple test of the bonding curve for a regular stableswap. | ||
Note: test data was generated via | ||
pool_address = "0x4e43151b78b5fbb16298C1161fcbF7531d5F8D93" | ||
pool = curvesim.pool.get(pool_address) | ||
basepool = pool.basepool | ||
pair_to_curve = bonding_curve(pool, resolution=5) | ||
""" | ||
pool_address = "0x4e43151b78b5fbb16298C1161fcbF7531d5F8D93" | ||
pool = curvesim.pool.get(pool_address) | ||
basepool = pool.basepool | ||
pair_to_curve = bonding_curve(pool, resolution=5) | ||
|
||
A = 1500 | ||
rates = [10**18, 10**30] | ||
balances = [350744085115649212803306457, 141003714500628] | ||
bp_tokens = 491124709934878945923137105 | ||
basepool = curvesim.pool.make(A, balances, 2, rates=rates, tokens=bp_tokens) | ||
|
||
A = 1500 | ||
balances = [7059917, 88935085280709722288137] | ||
rate_multiplier = 10**34 | ||
pool = curvesim.pool.make( | ||
A, | ||
balances, | ||
2, | ||
rate_multiplier=rate_multiplier, | ||
basepool=basepool, | ||
) | ||
pair_to_curve = bonding_curve(pool, resolution=5) | ||
expected_result = { | ||
(0, 1): [ | ||
(79.81988656375063, 182748.88552045962), | ||
(45747.08629503773, 113904.53710112568), | ||
(91414.35270351169, 68226.56650379577), | ||
(137081.61911198567, 22614.30606286462), | ||
(182748.88552045965, 79.81988656375057), | ||
] | ||
} | ||
|
||
assert pair_to_curve == expected_result |