def __init__(self, vat, gem): self.ADDRESS = "flopper" self.vat = vat self.gem = gem self.bids = dict() self.kicks = 0 self.pad = Wad.from_number(1.5) self.beg = Wad.from_number(1.05) self.ttl = 3 * 60 * 60 self.tau = 2 * 24 * 60 * 60
def get_slippage(self, pair_id, in_token, in_amt, t): self.tick(t) out_token = next( filter(lambda x: x != in_token, self.pairs[pair_id].keys())) in_reserve = Wad.from_number(float(self.pairs[pair_id][in_token])) out_reserve = Wad.from_number(float(self.pairs[pair_id][out_token])) initial_rate = out_reserve / in_reserve k = in_reserve * out_reserve new_in_reserve = in_reserve + in_amt new_out_reserve = k / new_in_reserve new_rate = new_out_reserve / new_in_reserve return ( Rad(out_reserve - new_out_reserve), (new_rate - initial_rate) / initial_rate, )
def run_bidding_model(self, bid, ilk_id): curr_price = Wad(bid.bid) / bid.lot if (bid.guy == self.ADDRESS or bid.lot == Wad(0) or curr_price > Wad( self.vat.ilks[ilk_id].spot * self.spotter.ilks[ilk_id].mat)): return {"price": Wad(0)} if bid.bid == Rad(0): return { "price": Wad.from_number(0.05) * Wad(bid.tab / Rad(bid.lot)) } return { "price": curr_price * (self.flippers[ilk_id].beg + Wad.from_number(random.uniform(0, 0.15))) }
def bark(self, ilk_id, urn_id, kpr, now): ink = self.vat.urns[ilk_id][urn_id].ink art = self.vat.urns[ilk_id][urn_id].art milk = self.ilks[ilk_id] rate = self.vat.ilks[ilk_id].rate spot = self.vat.ilks[ilk_id].spot dust = self.vat.ilks[ilk_id].dust require(spot > Ray(0) and spot * ink < rate * art, "Dog/not-unsafe") room = min(self.Hole - self.Dirt, milk.hole - milk.dirt) require(room > Rad(0) and room >= dust, "Dog/liquidation-limit-hit") dart = min(art, Wad(room / Rad(rate)) / milk.chop) if Rad(rate * (art - dart)) < dust: # Q: What if art > room? # Resetting dart = art here can push past liq limit dart = art dink = ink * dart / art require(dink > Wad(0), "Dog/null-auction") require( dart <= Wad.from_number(2**255) and dink <= Wad.from_number(2**255), "Dog/overflow", ) self.vat.grab( ilk_id, urn_id, milk.clip.ADDRESS, self.vow.ADDRESS, Wad(0) - dink, Wad(0) - dart, ) due = Rad(rate * dart) self.vow.fess(due, now) tab = due * Rad(milk.chop) self.Dirt += tab self.ilks[ilk_id].dirt = milk.dirt + tab milk.clip.kick(tab, dink, urn_id, kpr, now) return [tab]
def bite(self, ilk_id, urn, now): # TODO: Remove `now` once better timekeeping solution is implemented rate = self.vat.ilks[ilk_id].rate spot = self.vat.ilks[ilk_id].spot dust = self.vat.ilks[ilk_id].dust ink = self.vat.urns[ilk_id][urn].ink art = self.vat.urns[ilk_id][urn].art require(spot > Ray(0) and Rad(ink * spot) < Rad(art * rate), "Cat/not-unsafe") milk = self.ilks[ilk_id] room = self.box - self.litter require(self.litter < self.box and room >= dust, "Cat/liquidation-limit-hit") dart = Wad.min(art, Wad(Rad.min(milk.dunk, room)) / Wad(rate) / milk.chop) dink = Wad.min(ink, ink * dart / art) require(dart > Wad(0) and dink > Wad(0), "Cat/null-auction") require( dart <= Wad.from_number(2**255) and dink <= Wad.from_number(2**255), "Cat/overflow", ) self.vat.grab(ilk_id, urn, self.ADDRESS, self.vow.ADDRESS, Wad(0) - dink, Wad(0) - dart) self.vow.fess(Rad(dart * rate), now) tab = Rad(dart * rate * milk.chop) self.litter += tab milk.flip.kick(urn, self.vow.ADDRESS, tab, dink, Rad(0), now)
def open_max_vaults(self, actions): for ilk_id in self.ilks: vat_ilk = self.vat.ilks[ilk_id] if self.ilks[ilk_id].balanceOf( self.ADDRESS) > 0 and vat_ilk.spot > Ray(0): dink = Wad.from_number(self.ilks[ilk_id].balanceOf( self.ADDRESS)) dart = self.spot_paddings[ilk_id] * vat_ilk.spot * dink if dart > Wad(vat_ilk.dust) and Rad( dart * vat_ilk.rate) <= Rad(dink * vat_ilk.spot): actions.append({ "key": "OPEN_VAULT", "keeper": self, "handler": self.open_vault, "args": [ilk_id, dink, dart], "kwargs": {}, })
def peek(self, now): with open(self.price_feed_file) as price_feed_json: return Wad.from_number( # TODO: Constantize the "price_close" field here json.load(price_feed_json)[now]["price_close"])
def track_stat(state, action, _results): if action["key"] == "T_START": state["stats"]["gas_price_gwei"] = float( state["gas_oracle"].peek(state["t"]) * Wad.from_number(10 ** -9) )
# "09-05-2020", ]: timeframe_params = deepcopy(parameters) timeframe_params["Spotter"]["WETH"]["pip"] = PipLike( f"feeds/eth/{timeframe}.json") timeframe_params["GasOracle"][ "price_feed_file"] = f"feeds/gas/{timeframe}.json" timeframe_params["Uniswap"]["pairs"][ "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"][ "path"] = f"feeds/eth_dai_liquidity/{timeframe}.json" swept_params = sweep( { # "Clipper.WETH.chip": [Wad.from_number(0.001), Wad.from_number(0.01), Wad.from_number(0.1)], # "Clipper.WETH.tip": [Rad.from_number(100), Rad.from_number(500), Rad.from_number(1000)], "Clipper.WETH.chip": [Wad.from_number(0.001)], "Clipper.WETH.tip": [Rad.from_number(1000)], }, timeframe_params, ) DutchAuctionsSims = [ DutchAuctionsExperiment( contracts, keepers, sort_actions, ilk_ids, Token, stat_trackers, params, ) for params in swept_params
def peek(self, now): with open(self.price_feed_file) as price_feed_json: # TODO: Constantize the "avgGasDay" field here # TODO: Format gas feed file to get rid of "data" return Wad.from_number( json.load(price_feed_json)["data"][now]["avgGasDay"])
} }, "Keepers": { "NaiveVaultKeeper": { "amount": 500, "get_params": lambda state: [ state["vat"], state["dai_join"], [{ "ilk_id": "WETH", "token": state["ilks"]["WETH"], "init_balance": random.gauss(10, 2.155), "gem_join": state["gem_joins"]["WETH"], "spot_padding": Wad.from_number( random.gauss(12 / 14, 0.216)), }], state["uniswap"], ], }, "NaiveFlipperKeeper": { "amount": 5, "get_params": lambda state: [ state["vat"], state["dai_join"], [{ "ilk_id": "WETH", "token": state["ilks"]["WETH"], "init_balance": random.gauss(250, 64.655),
num_sales_taken(), auction_debt(), ilk_price("WETH"), gas_price_gwei(), avg_time_to_liquidation("WETH"), ] parameters = { "Abacus": { "tau": 72 }, "Clipper": { "WETH": { "buf": Ray.from_number(1.05), "tail": 72, "cusp": Ray.from_number(0.5), "chip": Wad.from_number(0.08), "tip": Rad.from_number(1000), } }, "Dog": { "Hole": Rad(15000000000000000000000000000000000000000000000000000), "WETH": { "chop": Wad.from_number(1.13), "hole": Rad(15000000000000000000000000000000000000000000000000000), }, }, "Keepers": { "NaiveVaultKeeper": { "amount": 50, "get_params":