Skip to content

Commit

Permalink
remove lrna_imbalance parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
jepidoptera committed Oct 24, 2024
1 parent 28404ae commit 64275c1
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 803 deletions.
2 changes: 1 addition & 1 deletion hydradx/model/amm/global_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ def find_partial_otc_sell_amount(omnipool, otc):
sell_asset = otc.sell_asset

# if no arbitrage can happen at spot price, we cannot even partially satisfy the OTC order
if omnipool.price(omnipool, buy_asset, sell_asset) > otc.price:
if omnipool.price(buy_asset, sell_asset) > otc.price:
return 0

sell_amt = otc.sell_amount
Expand Down
69 changes: 17 additions & 52 deletions hydradx/model/amm/omnipool_amm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def __init__(self,
update_function: Callable = None,
last_asset_fee: dict or float = None,
last_lrna_fee: dict or float = None,
imbalance: float = 0.0,
last_oracle_values: dict = None,
max_withdrawal_per_block: float = 1,
max_lp_per_block: float = float('inf'),
Expand Down Expand Up @@ -64,7 +63,6 @@ def __init__(self,
self.weight_cap = {}
self.default_asset_fee = asset_fee if isinstance(asset_fee, Number) else 0.0
self.default_lrna_fee = asset_fee if isinstance(asset_fee, Number) else 0.0
self.lrna_imbalance = imbalance # AKA "L"
self.tvl_cap = tvl_cap
if preferred_stablecoin is None and "USD" in tokens:
self.stablecoin = "USD"
Expand Down Expand Up @@ -269,7 +267,6 @@ def __repr__(self):
f'Omnipool: {self.unique_id}\n'
f'********************************\n'
f'tvl cap: {self.tvl_cap}\n'
f'LRNA imbalance: {self.lrna_imbalance}\n'
f'lrna fee:\n\n'
f'{newline.join([" " + tkn + ": " + self.lrna_fee[tkn].name for tkn in self.asset_list])}\n\n'
f'asset fee:\n\n'
Expand Down Expand Up @@ -421,12 +418,7 @@ def swap(
agent: Agent,
tkn_buy: str, tkn_sell: str,
buy_quantity: float = 0,
sell_quantity: float = 0,
modify_imbalance: bool = True, # this is a hack to avoid modifying the imbalance for arbitrager LRNA swaps,
# since those would not actually be executed as LRNA swaps
# note that we still apply the imbalance modification due to LRNA fee
# collection, we just don't apply the imbalance modification from
# the sale of LRNA back to the pool.
sell_quantity: float = 0
):
"""
execute swap in place (modify and return self and agent)
Expand All @@ -447,9 +439,9 @@ def swap(
)

elif tkn_sell == 'LRNA':
return_val = self._lrna_swap(agent, buy_quantity, -sell_quantity, tkn_buy, modify_imbalance)
return_val = self._lrna_swap(agent, buy_quantity, -sell_quantity, tkn_buy)
elif tkn_buy == 'LRNA':
return_val = self._lrna_swap(agent, -sell_quantity, buy_quantity, tkn_sell, modify_imbalance)
return_val = self._lrna_swap(agent, -sell_quantity, buy_quantity, tkn_sell)

elif buy_quantity and not sell_quantity:
# back into correct delta_Ri, then execute sell
Expand Down Expand Up @@ -484,8 +476,7 @@ def swap(
tkn_buy] * self.lrna_mint_pct
delta_Qj = delta_Qt + delta_Qm
delta_Rj = self.liquidity[tkn_buy] * -delta_Qt / (self.lrna[tkn_buy] + delta_Qt) * (1 - asset_fee)
delta_L = min(-delta_Qi * lrna_fee, -self.lrna_imbalance)
delta_QH = -lrna_fee * delta_Qi - delta_L
delta_QH = -lrna_fee * delta_Qi

if self.liquidity[i] + sell_quantity > 10 ** 12:
return self.fail_transaction('Asset liquidity cannot exceed 10 ^ 12.', agent)
Expand All @@ -510,7 +501,6 @@ def swap(
self.liquidity[i] += delta_Ri
self.liquidity[j] += -buy_quantity or delta_Rj
self.lrna['HDX'] += delta_QH
self.lrna_imbalance += delta_L

if j not in agent.holdings:
agent.holdings[j] = 0
Expand Down Expand Up @@ -552,10 +542,6 @@ def _lrna_swap(
delta_qm = asset_fee * (-delta_qa) / self.lrna[tkn] * (self.lrna[tkn] - delta_qa) * self.lrna_mint_pct
delta_q = delta_qm - delta_qa

if modify_imbalance:
q = self.lrna_total
self.lrna_imbalance += -delta_q * (q + self.lrna_imbalance) / (q + delta_q) - delta_q

self.lrna[tkn] += delta_q
self.liquidity[tkn] += -delta_ra

Expand All @@ -569,10 +555,6 @@ def _lrna_swap(
delta_qm = -asset_fee * (1 - asset_fee) * (self.liquidity[tkn] / denom) * delta_qa * self.lrna_mint_pct
delta_q = -delta_qa + delta_qm

if modify_imbalance:
q = self.lrna_total
self.lrna_imbalance -= delta_q * (q + self.lrna_imbalance) / (q + delta_q) + delta_q

self.lrna[tkn] += delta_q
self.liquidity[tkn] -= delta_ra

Expand All @@ -593,9 +575,7 @@ def _lrna_swap(

# we assume, for now, that buying LRNA is only possible when modify_imbalance = False
lrna_fee_amt = -(delta_qa + delta_qi)
delta_l = min(-self.lrna_imbalance, lrna_fee_amt)
self.lrna_imbalance += delta_l
self.lrna["HDX"] += lrna_fee_amt - delta_l
self.lrna["HDX"] += lrna_fee_amt

elif delta_ra < 0:
# selling asset
Expand All @@ -611,9 +591,7 @@ def _lrna_swap(

# we assume, for now, that buying LRNA is only possible when modify_imbalance = False
lrna_fee_amt = -(delta_qa + delta_qi)
delta_l = min(-self.lrna_imbalance, lrna_fee_amt)
self.lrna_imbalance += delta_l
self.lrna["HDX"] += lrna_fee_amt - delta_l
self.lrna["HDX"] += lrna_fee_amt

else:
return self.fail_transaction('All deltas are zero.', agent)
Expand Down Expand Up @@ -905,21 +883,21 @@ def calculate_remove_liquidity(self, agent: Agent, quantity: float = None, tkn_r
else:
tkn_remove = agent.nfts[nft_id].tkn

delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l, nft_ids = 0, 0, 0, 0, 0, 0, []
delta_qa, delta_r, delta_q, delta_s, delta_b, nft_ids = 0, 0, 0, 0, 0, []
if quantity is not None:
if nft_id is None: # remove specified quantity of shares from holdings
k = (self.unique_id, tkn_remove)
delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l = self._calculate_remove_one_position(
delta_qa, delta_r, delta_q, delta_s, delta_b = self._calculate_remove_one_position(
quantity=quantity, tkn_remove=tkn_remove, share_price=agent.share_prices[k]
)
else: # remove specified quantity of shares from specified position
delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l = self._calculate_remove_one_position(
delta_qa, delta_r, delta_q, delta_s, delta_b = self._calculate_remove_one_position(
quantity=quantity, tkn_remove=tkn_remove, share_price=agent.nfts[nft_id].price
)
nft_ids = [nft_id]
else:
if nft_id is not None: # remove specified position
delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l = self._calculate_remove_one_position(
delta_qa, delta_r, delta_q, delta_s, delta_b = self._calculate_remove_one_position(
quantity=agent.nfts[nft_id].shares, tkn_remove=tkn_remove, share_price=agent.nfts[nft_id].price
)
nft_ids = [nft_id]
Expand All @@ -929,17 +907,16 @@ def calculate_remove_liquidity(self, agent: Agent, quantity: float = None, tkn_r
if isinstance(nft, OmnipoolLiquidityPosition):
if nft.pool_id == self.unique_id and nft.tkn == tkn_remove:
nft_ids.append(nft_id)
dqa, dr, dq, ds, db, dl = self._calculate_remove_one_position(
dqa, dr, dq, ds, db = self._calculate_remove_one_position(
quantity=nft.shares, tkn_remove=tkn_remove, share_price=nft.price
)
delta_qa += dqa
delta_r += dr
delta_q += dq
delta_s += ds
delta_b += db
delta_l += dl
if (self.unique_id, tkn_remove) in agent.holdings:
dqa, dr, dq, ds, db, dl = self._calculate_remove_one_position(
dqa, dr, dq, ds, db = self._calculate_remove_one_position(
quantity=agent.holdings[(self.unique_id, tkn_remove)], tkn_remove=tkn_remove,
share_price=agent.share_prices[(self.unique_id, tkn_remove)]
)
Expand All @@ -948,8 +925,7 @@ def calculate_remove_liquidity(self, agent: Agent, quantity: float = None, tkn_r
delta_q += dq
delta_s += ds
delta_b += db
delta_l += dl
return delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l, nft_ids
return delta_qa, delta_r, delta_q, delta_s, delta_b, nft_ids

def _calculate_remove_one_position(self, quantity, tkn_remove, share_price):
"""
Expand Down Expand Up @@ -1002,9 +978,8 @@ def _calculate_remove_one_position(self, quantity, tkn_remove, share_price):
delta_q *= 1 - fee

# L update: LRNA fees to be burned before they will start to accumulate again
delta_l = delta_r * piq * self.lrna_imbalance / self.lrna_total

return delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l
return delta_qa, delta_r, delta_q, delta_s, delta_b

def add_liquidity(
self,
Expand Down Expand Up @@ -1076,10 +1051,6 @@ def add_liquidity(
shares_added = delta_Q
self.shares[tkn_add] += shares_added

# L update: LRNA fees to be burned before they will start to accumulate again
delta_L = quantity * self.lrna_price(tkn_add) * self.lrna_imbalance / self.lrna_total
self.lrna_imbalance += delta_L

# LRNA add (mint)
self.lrna[tkn_add] += delta_Q

Expand Down Expand Up @@ -1163,9 +1134,7 @@ def remove_liquidity(self, agent: Agent, quantity: float = None, tkn_remove: str
)

val = self.calculate_remove_liquidity(agent, quantity, tkn_remove, nft_id)
delta_qa, delta_r, delta_q, delta_s, delta_b, delta_l = val[:6]
if len(val) == 7:
nft_ids = val[6]
delta_qa, delta_r, delta_q, delta_s, delta_b, nft_ids = val[:6]

max_remove = (
self.max_withdrawal_per_block * self.shares[tkn_remove] - self.current_block.withdrawals[tkn_remove]
Expand All @@ -1183,7 +1152,6 @@ def remove_liquidity(self, agent: Agent, quantity: float = None, tkn_remove: str
self.shares[tkn_remove] += delta_s
self.protocol_shares[tkn_remove] += delta_b
self.lrna[tkn_remove] += delta_q
self.lrna_imbalance += delta_l

# distribute tokens to agent
if delta_qa > 0:
Expand Down Expand Up @@ -1299,25 +1267,23 @@ def cash_out(self, agent: Agent, prices) -> float:
for k in agent.holdings:
if isinstance(k, tuple) and len(k) == 2 and k[0] == self.unique_id: # LP shares of correct pool
tkn = k[1]
dqa, dr, dq, ds, db, dl, ids = self.calculate_remove_liquidity(agent, tkn_remove=tkn)
dqa, dr, dq, ds, db, ids = self.calculate_remove_liquidity(agent, tkn_remove=tkn)
delta_qa += dqa
delta_r[tkn] = dr + (delta_r[tkn] if tkn in delta_r else 0)
delta_q[tkn] = dq + (delta_q[tkn] if tkn in delta_q else 0)
delta_s[tkn] = ds + (delta_s[tkn] if tkn in delta_s else 0)
delta_b[tkn] = db + (delta_b[tkn] if tkn in delta_b else 0)
delta_l += dl
nft_ids += ids

for nft_id in agent.nfts:
if nft_id not in nft_ids and agent.nfts[nft_id].pool_id == self.unique_id:
tkn = agent.nfts[nft_id].tkn
dqa, dr, dq, ds, db, dl, _ = self.calculate_remove_liquidity(agent, nft_id=nft_id)
dqa, dr, dq, ds, db, _ = self.calculate_remove_liquidity(agent, nft_id=nft_id)
delta_qa += dqa
delta_r[tkn] = dr + (delta_r[tkn] if tkn in delta_r else 0)
delta_q[tkn] = dq + (delta_q[tkn] if tkn in delta_q else 0)
delta_s[tkn] = ds + (delta_s[tkn] if tkn in delta_s else 0)
delta_b[tkn] = db + (delta_b[tkn] if tkn in delta_b else 0)
delta_l += dl

# agent_holdings = new_agent.holdings
lrna_removed = {tkn: -delta_q[tkn] if tkn in delta_q else 0 for tkn in self.asset_list}
Expand Down Expand Up @@ -1382,7 +1348,6 @@ def __init__(self, state: OmnipoolState):
self.lrna_total = sum(state.lrna.values())
self.shares = {k: v for (k, v) in state.shares.items()}
self.protocol_shares = {k: v for (k, v) in state.protocol_shares.items()}
self.lrna_imbalance = state.lrna_imbalance
self.fail = state.fail
self.stablecoin = state.stablecoin
# self.sub_pools = copy.deepcopy(self.sub_pools)
Expand Down
4 changes: 2 additions & 2 deletions hydradx/model/amm/omnipool_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def copy(self):
def price_route(self, tkn: str, denomination: str, tkn_pool_id: str, denom_pool_id: str) -> float:
if tkn_pool_id == denom_pool_id:
if tkn_pool_id == self.omnipool_id: # This is necessary because Omnipool has wrong price signature
return self.omnipool.price(self.omnipool, tkn, denomination)
return self.omnipool.price(tkn, denomination)
else:
return self.exchanges[tkn_pool_id].price(tkn, denomination)

Expand Down Expand Up @@ -181,7 +181,7 @@ def swap_route(
if buy_quantity:
# buy a specific quantity of a stableswap asset using LRNA
shares_needed = stable_pool.calculate_withdrawal_shares(tkn_remove=tkn_buy, quantity=buy_quantity)
omnipool.lrna_swap(agent, delta_ra=shares_needed, tkn=buy_pool_id)
omnipool.swap(agent, tkn_sell='LRNA', buy_quantity=shares_needed, tkn_buy=buy_pool_id)
if omnipool.fail:
# if the swap failed, the transaction failed.
return self.fail_transaction(omnipool.fail)
Expand Down
20 changes: 10 additions & 10 deletions hydradx/model/amm/trade_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ def strategy(state: GlobalState, agent_id: str):
# asset = agent.asset_list[i]
dr = percentage / 2 * omnipool.liquidity[asset]
lrna_init = state.agents[agent_id].holdings['LRNA']
omnipool.swap(agent=agent, tkn_sell=asset, tkn_buy='LRNA', sell_quantity=dr, modify_imbalance=False)
omnipool.swap(agent=agent, tkn_sell=asset, tkn_buy='LRNA', sell_quantity=dr)
dq = state.agents[agent_id].holdings['LRNA'] - lrna_init
omnipool.swap(agent=agent, tkn_sell='LRNA', tkn_buy=asset, sell_quantity=dq, modify_imbalance=False)
omnipool.swap(agent=agent, tkn_sell='LRNA', tkn_buy=asset, sell_quantity=dq)

return state

Expand Down Expand Up @@ -541,22 +541,22 @@ def strategy(state: GlobalState, agent_id: str) -> GlobalState:
if dq[i] > 0:
omnipool.swap(
agent=agent, tkn_sell="LRNA", tkn_buy=asset_list[i],
sell_quantity=dq[i] * j/arb_precision, modify_imbalance=False)
sell_quantity=dq[i] * j/arb_precision)
else:
omnipool.swap(
agent=agent, tkn_sell=asset_list[i], tkn_buy="LRNA",
buy_quantity=-dq[i] * j/arb_precision, modify_imbalance=False)
buy_quantity=-dq[i] * j/arb_precision)
break
elif j == arb_precision - 1:
for i in range(len(asset_list)):
if dq[i] > 0:
omnipool.swap(
agent=agent, tkn_sell="LRNA", tkn_buy=asset_list[i],
sell_quantity=dq[i], modify_imbalance=False)
sell_quantity=dq[i])
else:
omnipool.swap(
agent=agent, tkn_sell=asset_list[i], tkn_buy="LRNA",
buy_quantity=-dq[i], modify_imbalance=False)
buy_quantity=-dq[i])
break # technically unnecessary

return state
Expand Down Expand Up @@ -656,10 +656,10 @@ def strategy(state: GlobalState, agent_id: str) -> GlobalState:

pool = state.pools[pool_id]
agent = state.agents[agent_id]
current_price = oamm.lrna_price(pool, asset_name)
current_price = pool.lrna_price(asset_name)
if current_price <= 0:
return state
usd_price = oamm.lrna_price(pool, pool.stablecoin) / current_price
usd_price = pool.lrna_price(pool.stablecoin) / current_price
if usd_price <= 0:
return state
quantity = (
Expand Down Expand Up @@ -825,7 +825,7 @@ def execute(self, state: GlobalState, agent_id: str):
(omnipool.weight_cap[self.attack_asset] * omnipool.lrna_total
- omnipool.lrna[self.attack_asset])
/ (1 - omnipool.weight_cap[self.attack_asset])
/ oamm.lrna_price(omnipool, self.trade_asset)
/ omnipool.lrna_price(self.trade_asset)
) if omnipool.weight_cap[self.attack_asset] < 1 else float('inf')

# choose the largest trade size that will be allowed by the per block trade limit
Expand Down Expand Up @@ -862,7 +862,7 @@ def execute(self, state: GlobalState, agent_id: str):
(omnipool.weight_cap[self.attack_asset] * omnipool.lrna_total
- omnipool.lrna[self.attack_asset])
/ (1 - omnipool.weight_cap[self.attack_asset])
/ oamm.lrna_price(omnipool, self.attack_asset)
/ omnipool.lrna_price(self.attack_asset)
) if omnipool.weight_cap[self.attack_asset] < 1 else float('inf')
self.add_liquidity_target = min(
agent.holdings[self.attack_asset] / 2,
Expand Down
1 change: 0 additions & 1 deletion hydradx/tests/strategies_omnipool.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ def omnipool_config(
tvl_cap=tvl_cap_usd or float('inf'),
asset_fee=draw(st.floats(min_value=0, max_value=0.1)) if asset_fee is None else asset_fee,
lrna_fee=draw(st.floats(min_value=0, max_value=0.1)) if lrna_fee is None else lrna_fee,
imbalance=imbalance if imbalance is not None else draw(st.floats(min_value=-1, max_value=1)),
withdrawal_fee=withdrawal_fee
)

Expand Down
Loading

0 comments on commit 64275c1

Please sign in to comment.