Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
2f97f4f
two-way slip fee (wip)
jepidoptera Nov 13, 2025
c61be00
add test_buy_sell_equivalency
jepidoptera Nov 13, 2025
8329661
fees should maybe not affect price? They do
jepidoptera Nov 17, 2025
ede35dd
app to measure slip fees for a given trade size
jepidoptera Nov 17, 2025
089dfc8
Merge branch 'slip_fees' into slip_fees_both_ways
jepidoptera Nov 17, 2025
9bdf3c5
finished two-way slip fees
jepidoptera Nov 21, 2025
5ec8b8c
add lrna_in and lrna_out to measure trades independently of LPs
jepidoptera Nov 21, 2025
ac07081
add test_lrna_without_mint_or_burn_is_constant
jepidoptera Nov 21, 2025
2f8d788
clean up comments
jepidoptera Nov 21, 2025
09e2b33
clean up comments
jepidoptera Nov 21, 2025
929574a
tweaks to buy/sell calculations and fee depositing
jepidoptera Dec 5, 2025
e732df4
moved one test over to other_tests/misc
jepidoptera Dec 5, 2025
5d25c7e
new non-integration test file
jepidoptera Dec 5, 2025
9f12d76
allow list for agents parameter
jepidoptera Dec 5, 2025
340f17e
fixes
jepidoptera Dec 5, 2025
155106e
semi-presentable result
jepidoptera Dec 5, 2025
01b5665
add some non-integration tests
jepidoptera Dec 16, 2025
2bca38a
iterate through asset_info to avoid tokens that don't have info
jepidoptera Dec 16, 2025
6c3c9eb
overhaul
jepidoptera Dec 16, 2025
c10b26a
correct slip fees percentage calculation
jepidoptera Dec 16, 2025
2190205
add test
jepidoptera Dec 18, 2025
08ba503
get_omnipool_liquidity_at_intervals and get_blocks_at_timestamps
jepidoptera Dec 29, 2025
63b01c4
cash_out defaults to lrna
jepidoptera Dec 29, 2025
aced340
update block/timestamp cache
jepidoptera Dec 29, 2025
946f155
default to enforce_holdings = False
jepidoptera Jan 5, 2026
3d34bf3
some debugging
jepidoptera Jan 5, 2026
a5613e9
several new tests
jepidoptera Jan 5, 2026
7d0e326
compute max_withdrawal based on shares at start of block
jepidoptera Jan 5, 2026
62fc464
update
jepidoptera Jan 5, 2026
49093dc
track shares
jepidoptera Jan 5, 2026
12863fb
update name of get_current_omnipool_asset_ids
jepidoptera Jan 5, 2026
fbfa733
add test_get_omnipool_trades
jepidoptera Jan 5, 2026
6804587
default to enforce_holdings=False unless holdings are given
jepidoptera Jan 6, 2026
0807ea7
fix bug with non-decimal asset_ids
jepidoptera Jan 6, 2026
8097007
fix test_swap_agent_changes
jepidoptera Jan 6, 2026
57c0a98
simplify omnipool.swap
jepidoptera Jan 7, 2026
38b4edc
use agent.get_holdings
jepidoptera Jan 9, 2026
23aae90
simplify swap function
jepidoptera Jan 9, 2026
9c886d2
delete unneeded test
jepidoptera Jan 9, 2026
d2b5599
tweak test
jepidoptera Jan 9, 2026
980881a
fix some tests
jepidoptera Jan 9, 2026
1bafcd6
fix some tests
jepidoptera Jan 9, 2026
a7ab416
refactor
jepidoptera Jan 19, 2026
f0af3f2
fix test
jepidoptera Jan 19, 2026
b564271
refactor
jepidoptera Jan 19, 2026
485cd82
one more app to test
jepidoptera Jan 19, 2026
46f0ba3
don't include subpools in omnipool composite
jepidoptera Jan 19, 2026
27998be
cache update
jepidoptera Jan 19, 2026
071cb4d
don't include fees in delta_qi
jepidoptera Jan 19, 2026
5f7605f
testing ideas for redirecting H2O to HDX
jepidoptera Jan 19, 2026
14b82ab
add get_dates_of_blocks
jepidoptera Jan 19, 2026
5e4b17e
ignore all cached data
jepidoptera Jan 19, 2026
974c376
correct per-block trade limit
jepidoptera Jan 19, 2026
dad1d09
when buying LRNA, there is no delta_qj
jepidoptera Jan 20, 2026
a592c08
leave lrna fee in buy pool if no treasury agent
jepidoptera Jan 20, 2026
67c41d2
debugging test_remove_liquidity_no_fee_different_price
jepidoptera Jan 20, 2026
ac24b59
remove imbalance parameter from OmnipoolState
jepidoptera Jan 20, 2026
7765cf2
clean up token distribution code
jepidoptera Jan 20, 2026
82cf0d0
delete some code
jepidoptera Jan 21, 2026
c0a0a48
wip
jepidoptera Jan 21, 2026
8028442
add destination agent (test_remove_liquidity_no_fee_different_price)
jepidoptera Jan 21, 2026
1eb7ff9
use validate_holdings instead of agent.holdings
jepidoptera Jan 29, 2026
82263b9
refactor __repr__ and ensure swap LRNA totals to 0
jepidoptera Jan 29, 2026
e930415
delete outdated tests
jepidoptera Jan 29, 2026
4cf98bb
improve some tests
jepidoptera Jan 29, 2026
5015ac4
constant_swaps treats negative sell quantities as a buy
jepidoptera Jan 29, 2026
77a9741
fix add_token bug
jepidoptera Feb 4, 2026
24a9015
save_state and load_state accept Path as input
jepidoptera Feb 4, 2026
24f1e18
add test_HDX_sandwich
jepidoptera Feb 4, 2026
a2f2475
delete broken import
jepidoptera Feb 4, 2026
a3a8e44
remove references to deleted obsolete functions
jepidoptera Feb 4, 2026
44a29de
minor corrections to calculate_out_given_in and calculate_in_given_out
jepidoptera Feb 9, 2026
8ce731a
two new slip fee tests
jepidoptera Feb 24, 2026
82eb336
two new app tests
jepidoptera Feb 24, 2026
53237d7
default load_state from 'cached data'
jepidoptera Feb 24, 2026
476b128
cache more dates-to-blocks data
jepidoptera Feb 24, 2026
5a365dc
in value_assets, skip assets with quantity 0
jepidoptera Feb 24, 2026
ff18b54
price comparison between binance records and DIA oracle
jepidoptera Feb 24, 2026
5d844f5
change output format for get_omnipool_liquidity_at_intervals
jepidoptera Feb 24, 2026
861525e
cleanup
jepidoptera Feb 24, 2026
2589027
add get_binance_prices
jepidoptera Feb 24, 2026
d1525d6
app simulating hdx buy/burn as fee discount mechanism
jepidoptera Feb 24, 2026
c747d43
fix delta quantities for LRNA buy
jepidoptera Feb 24, 2026
9deb983
ignore rounding error
jepidoptera Feb 24, 2026
b76d5b5
include slip_fee_sell in test_lrna_split_buy_calculation
jepidoptera Feb 24, 2026
a1d2ebe
move hdx sandwich attack to other_tests
jepidoptera Feb 24, 2026
052a528
move get_binance_prices to eur_usd app
jepidoptera Feb 24, 2026
3ce809f
app to simulate arbitrage against a USD/EURO pegged stableswap
jepidoptera Feb 28, 2026
e90032e
fix buy/sell calculations
jepidoptera Feb 28, 2026
01694b9
test calculate_buy_from_sell with drifting peg
jepidoptera Feb 28, 2026
af416ad
require binance package
jepidoptera Feb 28, 2026
05bad67
make data available offline
jepidoptera Feb 28, 2026
1b8fe01
adjust default time range
jepidoptera Feb 28, 2026
ec8a99b
ignore secrets file
jepidoptera Mar 2, 2026
05f2df3
require boto3
jepidoptera Mar 2, 2026
b9cb7ff
update secrets location
jepidoptera Mar 2, 2026
9e62362
update with latest from DIA
jepidoptera Mar 3, 2026
e266d6d
add cloud storage for faster loading/caching
jepidoptera Mar 3, 2026
6aea6c9
delete extra files
jepidoptera Mar 4, 2026
97c0093
delete extra files
jepidoptera Mar 4, 2026
451ec14
don't run demo on cloud
jepidoptera Mar 5, 2026
5752d46
refactors
jepidoptera Mar 5, 2026
332db5f
tests for new apps
jepidoptera Mar 5, 2026
33293e1
update prices from DIA
jepidoptera Mar 5, 2026
a97743a
better simulation results
jepidoptera Mar 12, 2026
4d402ba
update data
jepidoptera Mar 12, 2026
e1de183
better layout
jepidoptera Mar 12, 2026
aff8044
account for pool depth
jepidoptera Mar 12, 2026
c57cd86
generalize get_omnipool_trades into get_all_trades
jepidoptera Mar 27, 2026
d64e3bd
factor out trade downloading/caching logic
jepidoptera Mar 27, 2026
afa281c
update type hint syntax
jepidoptera Mar 27, 2026
945f669
helper app
jepidoptera Mar 27, 2026
c044db5
adjustable pool depth
jepidoptera Mar 27, 2026
d4a50a1
factor out get_trade_for_dates
jepidoptera Mar 27, 2026
49aab67
esxploring undo option
jepidoptera Mar 27, 2026
f3b94fa
update type hinting
jepidoptera Mar 30, 2026
4eeafff
remove unused imports
jepidoptera Mar 30, 2026
a3691c0
more analysis
jepidoptera Mar 30, 2026
64a1715
add singular get_block_at_timestamp
jepidoptera Mar 30, 2026
273f05f
update type hints
jepidoptera Mar 30, 2026
3a14121
minor fixes
jepidoptera Mar 30, 2026
1303372
add cache_directory option
jepidoptera Mar 30, 2026
d798008
add some tests
jepidoptera Mar 30, 2026
246cc64
AI notes
jepidoptera Mar 30, 2026
be503a6
update
jepidoptera Mar 30, 2026
8c2167d
add tokenomics test
jepidoptera Mar 30, 2026
7469b51
faster reload
jepidoptera Mar 30, 2026
4c10077
factored out cloud storage utilties
jepidoptera Mar 30, 2026
b14e0f0
factored out cloud storage utilities
jepidoptera Mar 30, 2026
2a0ece7
use cloud storage
jepidoptera Mar 30, 2026
ca590b7
improved loading time and accuracy
jepidoptera Mar 30, 2026
aa13191
moved streamlit secrets file
jepidoptera Mar 30, 2026
2952f21
clarify percentages
jepidoptera Mar 30, 2026
81602cf
Update Python version to 3.10 in workflow
jepidoptera Mar 31, 2026
0becc42
more accurate calculation
jepidoptera Mar 31, 2026
f737012
allow specifying both buy and sell quantities
jepidoptera Mar 31, 2026
11576c8
Merge remote-tracking branch 'origin/eur_usd_stableswap' into eur_usd…
jepidoptera Mar 31, 2026
29fd364
correct asset fee expectation
jepidoptera Apr 10, 2026
92f33d9
don't allow both sell_quantity and buy_quantity
jepidoptera Apr 10, 2026
0e478e7
calculate specific arb losses
jepidoptera Apr 10, 2026
144ccec
fix missing quote in query
jepidoptera Apr 10, 2026
d2afa2e
move slow indexer tests out of integration requirement
jepidoptera Apr 10, 2026
09f194f
update python version
jepidoptera Apr 10, 2026
3c8b40d
fix test_lowering_price
jepidoptera Apr 13, 2026
e33359c
remove some debug logging
jepidoptera Apr 13, 2026
6b6b324
remove some debug logging
jepidoptera Apr 13, 2026
62bb2e0
Update Python version to 3.13.5 in workflow
jepidoptera Apr 13, 2026
ec7bcd8
add logging for flaky test
jepidoptera Apr 14, 2026
3f1c386
add logging for flaky test
jepidoptera Apr 14, 2026
262749a
fix lrna_fee_destination init in constructor
jepidoptera Apr 14, 2026
d50eb07
Merge branch 'main' into eur_usd_stableswap
jepidoptera Apr 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
- name: Set up Python 3.13.5
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.13.5"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@
*.env
/hydradx/apps/fees/data
/hydradx/apps/money_market/archive
/hydradx/apps/fees/acct_swaps_5_0x7279fcf9694718e1234d102825dccaf332f0ea36edf1ca7c0358c4b68260d24b.json
/hydradx/apps/omnipool/cached data/all_trades.txt
/hydradx/other tests/cached data/all_trades.txt
/hydradx/apps/omnipool/cached data/lrna_sells.txt
/hydradx/other tests/cached data/lrna_sells.txt
/hydradx/tests/money_market_save_test.json
**/cached\ data/**
/.streamlit/secrets.toml
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The main HydraDX model can be found in "hydradx".

Installation:
* Install Python 3.9. Not 3.8, it doesn't support all the features used in this code. Not 3.10, there is a compatibility issue with one of the libraries that you don't want to deal with. Link: https://www.python.org/downloads/release/python-3912/
* Install Python 3.10 or higher
* Clone the repository and navigate to the root folder, HydraDx-simulations
* In terminal, enter 'pip install -r requirements.txt'
* Alternatively, open the project folder in PyCharm, and you'll be prompted to create a virtual environment for this project.
Expand Down
2 changes: 1 addition & 1 deletion hydradx/apps/everything_is_collateral/other_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from hydradx.model.amm.omnipool_amm import OmnipoolState
from hydradx.model.amm.agents import Agent
from hydradx.model.plot_utils import color_gradient
from hydradx.model.indexer_utils import get_current_omnipool, get_omnipool_trades, get_current_omnipool_assets, \
from hydradx.model.indexer_utils import get_current_omnipool, get_omnipool_trades, get_current_omnipool_asset_ids, \
get_asset_info_by_ids

st.markdown("""
Expand Down
82 changes: 82 additions & 0 deletions hydradx/apps/fees/slip_fees_chart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import random

from IPython.core.pylabtools import figsize
from matplotlib import pyplot as plt
import sys, os
import streamlit as st
import copy

from matplotlib.lines import lineStyles
from streamlit import session_state

project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../"))
sys.path.append(project_root)

from hydradx.model import production_settings
from hydradx.model.indexer_utils import get_current_omnipool_router

st.markdown("""
<style>
.stNumberInput button {
display: none;
}
</style>
""", unsafe_allow_html=True)

@st.cache_data(show_spinner=True)
def load_omnipool_router():
router = get_current_omnipool_router()
return router

def run_app():
st.session_state.router = load_omnipool_router()
st.session_state.omnipool = st.session_state.router.exchanges['omnipool']
omnipool = st.session_state.omnipool
omnipool.asset_fee = 0
omnipool.lrna_fee = 0
omnipool.max_lrna_fee = 1
omnipool.max_asset_fee = 1
col1, col2, col3 = st.columns(3)
with col1:
st.session_state.tkn_buy = st.selectbox("Select token to buy:", options=omnipool.asset_list, index=omnipool.asset_list.index('HDX'))
with col2:
st.session_state.tkn_sell = st.selectbox("Select token to sell:", options=omnipool.asset_list, index=omnipool.asset_list.index('DOT'))
with col3:
omnipool.slip_factor = st.number_input("Slip factor:", min_value=0.0, max_value=10.0, value=1.0)
plot_trade_sizes(st.session_state.tkn_buy, st.session_state.tkn_sell, st.session_state.router, st.session_state.omnipool)

def plot_trade_sizes(tkn_buy, tkn_sell, router, omnipool):
trade_sizes = [10 ** (i / 5) for i in range(0, 26)]
fees = []
for trade_size in trade_sizes:
sell_quantity = trade_size * router.price('Tether', tkn_sell)
outputs = omnipool.calculate_out_given_in(tkn_buy=tkn_buy, tkn_sell=tkn_sell, sell_quantity=sell_quantity)
buy_quantity, delta_qi, delta_qj, asset_fee_total, lrna_fee_total, slip_fee_buy, slip_fee_sell = outputs
slip_fee_total = slip_fee_buy + slip_fee_sell
slip_fee_percent = slip_fee_total / -delta_qi
print(f"${trade_size:.2f} worth of {tkn_sell} sold for {tkn_buy} = {slip_fee_percent * 100:.4f}% slip fee")
fees.append(slip_fee_percent)

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(trade_sizes, [fee * 100 for fee in fees], label='Slip Fee %', color='orange')
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel(f'Value of {tkn_sell} sold for {tkn_buy} (USD)')
ax.set_xticks([1, 10, 100, 1000, 10000, 100000], ['$1', '$10', '$100', '$1000', '$10k', '$100k'])
ax.set_ylabel('Slip Fee (%)')
ax.set_yticks(
[0.0001, 0.001, 0.01, 0.1, 1] + ([10] if max(fees) * 100 > 1 else []),
['0.0001%', '0.001%', '0.01%', '0.1%', '1%'] + (['10%'] if max(fees) * 100 > 1 else [])
)
# label the slip fee values at each dollar-value tick
for i, trade_size in enumerate(trade_sizes):
if trade_size in [1, 10, 100, 1000, 10000, 100000]:
ax.text(trade_size, fees[i] * 100, f"{fees[i] * 100:.4f}%", fontsize=8, ha='center', va='bottom')
ax.set_title('Total Slip Fee')
ax.grid(True, which="both", ls="--", linewidth=0.5, color="gray")
ax.legend()
st.pyplot(fig)

st.set_page_config(layout="wide")
st.title("Omnipool Slip Fees Chart")
run_app()
123 changes: 123 additions & 0 deletions hydradx/apps/omnipool/assets_liquidity_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
from hydradx.model.indexer_utils import query_indexer, get_blocks_at_timestamps, get_asset_info_by_ids
import datetime
from matplotlib import pyplot as plt
from pathlib import Path
import streamlit as st
import json
import math

LIQUIDITY_GRAPH_TARGET_POINTS = 1000


def _sort_key(value):
try:
return int(value)
except (TypeError, ValueError):
return value


def compress_liquidity_series(liquidity_series: dict, target_points: int) -> dict:
if target_points <= 0:
raise ValueError("target_points must be > 0")
if len(liquidity_series) <= target_points:
return dict(liquidity_series)

items = sorted(liquidity_series.items(), key=lambda item: _sort_key(item[0]))
total = len(items)
batch_size = max(1, math.ceil(total / target_points))
compressed = {}

for idx in range(0, total, batch_size):
batch = items[idx: idx + batch_size]
first_key = batch[0][0]
avg_value = sum(value for _, value in batch) / len(batch)
compressed[first_key] = avg_value

last_key, last_value = items[-1]
compressed[last_key] = last_value
return compressed


def _to_int_keyed(series: dict) -> dict:
return {int(k): v for k, v in series.items()}


def get_liquidity_over_time():
dates = [
datetime.datetime(2025, 11, day=i + 1) for i in range(30)
] + [
datetime.datetime(year=2025, month=12, day=i + 1) for i in range(31)
]
block_map = get_blocks_at_timestamps(dates)
ordered_blocks = sorted(block_map.items(), key=lambda item: item[0])
ordered_dates = [item[0] for item in ordered_blocks]
block_numbers = [item[1] for item in ordered_blocks]
liquidity = {}

if not Path.exists(Path(__file__).parent / 'cached data' / 'liquidity.json'):
for i, start_block in enumerate(block_numbers[:-1]):
date = dates[i]
print(f"scanning {date}")
blocks_per_query = 1000
end_block = block_numbers[1 + 1]
for block in range(start_block, end_block, blocks_per_query):
query_start = block
query_end = min(block + blocks_per_query, end_block)
query = f"""
query AssetBalancesByBlockHeight {{
omnipoolAssetHistoricalData(
filter: {{paraBlockHeight: {{greaterThanOrEqualTo: {query_start}, lessThan: {query_end}}}}}
) {{
nodes
{{
freeBalance
assetId
paraBlockHeight
}}
}}
}}
"""

results = query_indexer("https://galacticcouncil.squids.live/hydration-pools:unified-prod/api/graphql", query)
for result in results["data"]["omnipoolAssetHistoricalData"]["nodes"]:
asset_id = result["assetId"]
free_balance = int(result["freeBalance"])
result_block = int(result["paraBlockHeight"])
if asset_id not in liquidity:
liquidity[asset_id] = {}
liquidity[asset_id][result_block] = free_balance

with open (Path(__file__).parent / 'cached data' / 'liquidity.json', 'w') as f:
json.dump(liquidity, f)
else:
with open (Path(__file__).parent / 'cached data' / 'liquidity.json', 'r') as f:
liquidity = json.load(f)

asset_names = {tkn.id: tkn.unique_id for tkn in get_asset_info_by_ids(list(liquidity.keys())).values()}
graph_liquidity = {}
for tkn in liquidity:
raw_series = _to_int_keyed(liquidity[tkn])
if len(raw_series) > LIQUIDITY_GRAPH_TARGET_POINTS:
graph_liquidity[tkn] = compress_liquidity_series(
raw_series,
target_points=LIQUIDITY_GRAPH_TARGET_POINTS,
)
else:
graph_liquidity[tkn] = dict(raw_series)
graph_liquidity[tkn][block_numbers[0]] = list(raw_series.values())[0]
graph_liquidity[tkn][block_numbers[-1]] = list(raw_series.values())[-1]
sorted_items = sorted(graph_liquidity[tkn].items(), key=lambda item: _sort_key(item[0]))
fig, ax = plt.subplots(figsize=(12, 4))
ax.plot([item[0] for item in sorted_items], [item[1] for item in sorted_items])
ax.set_title(f"Liquidity of {asset_names[tkn]} in Omnipool")
ax.set_xlabel("Date")
ax.set_ylabel("Free Balance")
ax.set_xticks(block_numbers)
ax.set_xticklabels([date.strftime('%Y-%m-%d') for date in ordered_dates])
ax.tick_params(axis="x", labelsize=8)

plt.tight_layout()
plt.show()
st.pyplot(fig)
pass

Loading
Loading