Skip to content

Instantly share code, notes, and snippets.

@raddy
Created April 18, 2022 16:11
Show Gist options
  • Save raddy/ed85af6dd6234595056287fc9cc175e1 to your computer and use it in GitHub Desktop.
Save raddy/ed85af6dd6234595056287fc9cc175e1 to your computer and use it in GitHub Desktop.
WiP on UniV2 arb finding
from dataclasses import dataclass
from dataclasses_json import dataclass_json
from abc import ABC, abstractmethod
from typing import List
from scipy import optimize
class Pool(ABC):
@abstractmethod
def amount_out(self, token_in : str, token_out : str, amount_in : int) -> int:
pass
@abstractmethod
def tokens(self) -> List[str]:
pass
@dataclass_json
@dataclass(frozen=True)
class Reserves:
reserve0 : int
reserve1 : int
class Swap:
def __init__(self, token_in : str, token_out : str, pool : Pool):
self.token_in = token_in
self.token_out = token_out
self.pool = pool
class UniV2Pool(Pool):
FEES_BP = 30
def __init__(self, token0 : str, token1 : str):
self.token0 = token0
self.token1 = token1
def update_reserves(self, new_reserves : Reserves):
self.reserves = new_reserves
def amount(self, amount : int, reserve_in : int, reserve_out : int) -> int:
amountInWithFee = int(amount) * (10000 - self.FEES_BP)
numerator = amountInWithFee * reserve_out
denominator = reserve_in * 10000 + amountInWithFee
return numerator // denominator
def amount_out(self, token_in : str, token_out : str, amount_in : int) -> int:
if token_in == self.token0 and token_out == self.token1:
return self.amount(amount_in, self.reserves.reserve0, self.reserves.reserve1)
elif token_in == self.token1 and token_out == self.token0:
return self.amount(amount_in, self.reserves.reserve1, self.reserves.reserve0)
raise ValueError("Tokens do not match pool")
def tokens(self) -> List[str]:
return [self.token0, self.token1]
# This is deprecated
#def find_solutions(self, current_token : str, depth: int, visited : List[str]):
# visited.append(current_token)
# if depth >= len(self.pools):
# self.solutions.append(visited)
# return
#
# for other_token in self.other_tokens(current_token, depth):
# self.find_solutions(other_token, depth+1, visited.copy())
class Path:
def __init__(self, swaps : List[Swap]):
self.swaps = swaps
def chain(self, amount_in : int) -> int:
current_qty = amount_in
for swap in self.swaps:
current_qty = swap.pool.amount_out(swap.token_in, swap.token_out, current_qty)
return current_qty
def arbitrage(self, qty : int) -> int:
return self.chain(qty) - qty
def solve_fmin(self, guess):
def f(qty):
if qty < 0:
return 99999
return -1 * self.arbitrage(qty)
sol, best, *rest = optimize.fmin(f, guess, full_output=1)
return {'profit': -best, 'qty': sol[0]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment