Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into ncpu__should_use__o…
Browse files Browse the repository at this point in the history
…s_cpu_count
  • Loading branch information
UmerHA committed Nov 9, 2022
2 parents 9c6951a + e55d08a commit adaa591
Show file tree
Hide file tree
Showing 97 changed files with 40,046 additions and 27,696 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up latest Python
uses: actions/setup-python@v4
with:
python-version: "*"
python-version: "3.10"
cache: 'pip'

- name: Install dependencies
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ __pycache__/

# hypothesis
/.hypothesis

# Sphinx
/docs/_build
25 changes: 25 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:
# - pdf

# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: requirements.txt
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
[![CI](https://github.com/curveresearch/curvesim/actions/workflows/CI.yml/badge.svg)](https://github.com/curveresearch/curvesim/actions/workflows/CI.yml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Docs](https://readthedocs.org/projects/curvesim/badge/?version=latest)](https://curvesim.readthedocs.io/en/latest)
![PyPI](https://img.shields.io/pypi/v/curvesim)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/curvesim)
![PyPI - License](https://img.shields.io/pypi/l/curvesim)


# CurveSim
Expand All @@ -13,6 +17,12 @@ Primary package dependencies: scipy, numpy, pandas, Web3, matplotlib, requests,
To avoid dependency issues, it is recommended to use the included `requirements.txt` file in a Python virtual environment (`venv`).



## Documentation

Check out the full documentation at https://curvesim.readthedocs.io/


## Basic Use: Autosim
The autosim() function simulates existing Curve pools with a range of A and/or fee parameters. The function fetches pool properties (e.g., current pool size) and 2 months of price/volume data, runs multiple simulations in parallel, and saves results plots to the "results" directory.

Expand Down
17 changes: 17 additions & 0 deletions curvesim/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import time

from .sim import autosim


def hello_world():
"""Simple sim run as a health check."""
t = time.time()
res = autosim("0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", test=True, ncpu=1)
elapsed = time.time() - t
print("Elapsed time:", elapsed)

return res


if __name__ == "__main__":
res = hello_world()
16 changes: 16 additions & 0 deletions curvesim/exceptions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CurvesimException(Exception):
"""Base exception class"""

pass


class SubgraphError(CurvesimException):
"""Raised for errors in subgraph query"""

pass


class SubgraphResultError(SubgraphError):
"""Raised when subgraph results aren't as expected"""

pass
10 changes: 10 additions & 0 deletions curvesim/iterators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Iterators for use in simulation runs.
These are input directly into :func:`.pipelines.templates.run_pipeline`,
along with a strategy that is run at each timestemp.
Iterators fall into two general categories:
1. :mod:`.param_samplers`: Generate pool with updated parameters per tick.
2. :mod:`.price_samplers`: Generate price, volume, and/or other time-series data per tick.
"""
7 changes: 7 additions & 0 deletions curvesim/iterators/param_samplers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Iterators that generate pools with updated parameters per tick.
"""

__all__ = ["Grid"]

from .grid import Grid
131 changes: 131 additions & 0 deletions curvesim/iterators/param_samplers/grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from copy import deepcopy
from itertools import product


class Grid:
"""
Iterates over a "grid" of all possible combinations of the input parameters.
"""

def __init__(self, pool, variable_params, fixed_params=None):
"""
Parameters
----------
pool : pool object
The "template" pool that will have its parameters modified.
variable_params: dict
Pool parameters to vary across simulations.
keys: pool parameters, values: iterables of ints
Basepool parameters can be included with a "basepool" key.
Example
-------
.. code-block ::
variable_params = {"A": [100, 1000], "basepool": {fee: [10**6, 4*10**6]}}
fixed_params : dict, optional
Pool parameters set before all simulations.
keys: pool parameters, values: ints
"""
self.pool_template = pool
self.set_attributes(self.pool_template, fixed_params)
self.param_grid = self.param_product(variable_params)
self.param_generator = iter(self.param_grid)

def __iter__(self):
return self

def __next__(self):
"""
Returns
-------
pool : pool object
A pool object with the current variable parameters set.
params : dict
A dictionary of the pool parameters set on this iteration.
"""
params = next(self.param_generator)
pool = deepcopy(self.pool_template)
self.set_attributes(pool, params)
return pool, params

def flat_grid(self):
"""
Returns
-------
list of dicts
A list of the parameters used in each iteration, flattened such
that basepool parameters are named, e.g., A_base, fee_base, etc.
"""
flat = self.param_grid.copy()
for params in flat:
basepool = params.pop("basepool", None)
if basepool:
for key, val in basepool.items():
params.update({key + "_base": val})

return flat

@staticmethod
def param_product(p_dict):
p_dict = p_dict.copy()
basepool = p_dict.pop("basepool", None)

keys = p_dict.keys()
vals = p_dict.values()

grid = []
for instance in product(*vals):
grid.append(dict(zip(keys, instance)))

if basepool:
base_keys = basepool.keys()
base_vals = basepool.values()
meta_grid = grid
grid = []

for meta_params in meta_grid:
for instance in product(*base_vals):
base_params = dict(zip(base_keys, instance))
meta_params.update({"basepool": base_params})
grid.append(meta_params.copy())

return grid

@staticmethod
def set_attributes(pool, attribute_dict):
if attribute_dict is None:
return

for key, value in attribute_dict.items():
if key == "basepool":
items = attribute_dict["basepool"].items()
for base_key, base_value in items:
if base_key == "D":
p = pool.basepool.p[:]
n = pool.basepool.n
D = base_value
x = [D // n * 10**18 // _p for _p in p]
pool.basepool.x = x

else:
setattr(pool.basepool, base_key, base_value)

else:
if key == "D":
p = getattr(pool, "rates", pool.p[:])
n = pool.n
D = value
x = [D // n * 10**18 // _p for _p in p]
pool.x = x

else:
setattr(pool, key, value)
7 changes: 7 additions & 0 deletions curvesim/iterators/price_samplers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Iterators that generate price, volume, and/or other time-series data per tick.
"""

__all__ = ["PriceVolume"]

from .price_volume import PriceVolume
81 changes: 81 additions & 0 deletions curvesim/iterators/price_samplers/price_volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from ...price_data import get


class PriceVolume:
"""
An iterator that retrieves price/volume and iterates over timepoints in the data.
"""

def __init__(self, coins, days=60, data_dir="data", src="coingecko"):
"""
Retrieves price/volume data and prepares it for iteration.
Parameters
----------
coins: list of str
Addresses of coins in the pool.
days: int, defaults to 60
Number of days to pull data for.
data_dir: str, defaults to "data"
Relative path to saved data folder.
src: str, defaults to "coingecko"
Identifies pricing source: coingecko, nomics, or local.
"""
prices, volumes, pzero = get(coins, days=days, data_dir=data_dir, src=src)

self.prices = prices
self.volumes = volumes
self.pzero = pzero

self.price_generator = prices.iterrows()
self.volume_generator = volumes.iterrows()

def __iter__(self):
return self

def __next__(self):
"""
Returns
-------
prices : pandas.Series
Prices for each pairwise coin combination.
volumes : pandas.Series
Prices for each pairwise coin combination.
timestamp : datetime.datetime
Timestamp for the current price/volume.
"""
prices = next(self.price_generator)
volumes = next(self.volume_generator)

assert prices[0] == volumes[0], "Price/volume timestamps did not match"

return prices[1], volumes[1], prices[0]

def total_volumes(self):
"""
Returns
-------
pandas.Series
Total volume for each pairwise coin combination, summed accross timestamps.
"""
return self.volumes.sum()

def restart(self):
"""
Resets the iterator.
Returns
-------
self
"""
self.price_generator = self.prices.iterrows()
self.volume_generator = self.volumes.iterrows()

return self
11 changes: 11 additions & 0 deletions curvesim/network/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Various network connectors and related utilities.
Primary data sources for general exchange prices and volumes are Coingecko and Nomics.
Curve subgraph is used for fetching pool data. The Llama Airforce REST API will also
be used in the future.
There is not a well-defined public API for this subpackage yet. A lot of the code
has been converted to use `asyncio` from a legacy implementation and further,
substantive improvements are anticipated.
"""
Loading

0 comments on commit adaa591

Please sign in to comment.