Skip to content

Commit cc74145

Browse files
committed
Update orderbook page
1 parent a2dea2f commit cc74145

File tree

1 file changed

+82
-110
lines changed

1 file changed

+82
-110
lines changed

src/page/orderbook.py

Lines changed: 82 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,111 @@
1+
from typing import Dict, Optional, Tuple
2+
13
import requests
24
import streamlit as st
35

6+
HL_BASE_URL = "https://api.hyperliquid.xyz/info"
7+
DRIFT_BASE_URL = "https://dlob.drift.trade/l2"
48

5-
def fetch_orderbook_data(coin, size):
6-
post_url = "https://api.hyperliquid.xyz/info"
7-
payload = {"type": "metaAndAssetCtxs"}
8-
payload2 = {"type": "l2Book", "coin": coin}
9-
10-
post_headers = {"Content-Type": "application/json"}
119

12-
results = {}
10+
def fetch_hyperliquid_data(coin: str) -> Tuple[Optional[Dict], Optional[Dict]]:
11+
meta = requests.post(
12+
HL_BASE_URL,
13+
json={"type": "metaAndAssetCtxs"},
14+
headers={"Content-Type": "application/json"},
15+
).json()
16+
book = requests.post(
17+
HL_BASE_URL,
18+
json={"type": "l2Book", "coin": coin},
19+
headers={"Content-Type": "application/json"},
20+
).json()
21+
return meta, book
1322

14-
for nom, pay in [("hl_cxt", payload), ("hl_book", payload2)]:
15-
post_response = requests.post(post_url, json=pay, headers=post_headers)
16-
if post_response.status_code == 200:
17-
results[nom] = post_response.json()
18-
else:
19-
print("Error:", post_response.text, "\n")
2023

21-
get_url = "https://dlob.drift.trade/l2"
22-
get_params = {
23-
"marketName": coin + "-PERP",
24-
"depth": 5,
24+
def fetch_drift_data(coin: str) -> Optional[Dict]:
25+
params = {
26+
"marketName": f"{coin}-PERP",
27+
"depth": 500,
2528
"includeOracle": "true",
2629
"includeVamm": "true",
2730
}
31+
return requests.get(DRIFT_BASE_URL, params=params).json()
2832

29-
get_response = requests.get(get_url, params=get_params)
30-
if not get_response.status_code == 200:
31-
print("Error:", get_response.text)
32-
33-
results["dr_book"] = get_response.json()
34-
35-
def calculate_average_fill_price_dr(order_book, volume):
36-
volume = volume
37-
38-
bids = order_book["bids"]
39-
asks = order_book["asks"]
40-
41-
print(f'{float(bids[0]["price"])/1e6}/{float(asks[0]["price"])/1e6}')
42-
43-
def average_price(levels, volume, is_buy):
44-
total_volume = 0
45-
total_cost = 0.0
46-
47-
for level in levels:
48-
# Price is in 1e6 precision, size is in 1e9 precision
49-
price = float(level["price"]) / 1e6
50-
size = float(level["size"]) / 1e9
5133

52-
if total_volume + size >= volume:
53-
# Only take the remaining required volume at this level
54-
remaining_volume = volume - total_volume
55-
total_cost += remaining_volume * price
56-
total_volume += remaining_volume
57-
break
58-
else:
59-
# Take the whole size at this level
60-
total_cost += size * price
61-
total_volume += size
34+
def calculate_avg_fill_price(
35+
levels: list, volume: float, is_drift: bool = False
36+
) -> float:
37+
total_volume = 0
38+
total_cost = 0.0
6239

63-
if total_volume < volume:
64-
raise ValueError(
65-
"Insufficient volume in the order book to fill the order"
66-
)
67-
68-
return total_cost / volume
69-
70-
try:
71-
buy_price = average_price(asks, volume, is_buy=True)
72-
sell_price = average_price(bids, volume, is_buy=False)
73-
except ValueError as e:
74-
return str(e)
75-
76-
return {"average_buy_price": buy_price, "average_sell_price": sell_price}
77-
78-
def calculate_average_fill_price_hl(order_book, volume):
79-
buy_levels = order_book["levels"][1] # Bids (lower prices first)
80-
sell_levels = order_book["levels"][0] # Asks (higher prices first)
81-
82-
def average_price(levels, volume):
83-
total_volume = 0
84-
total_cost = 0.0
40+
for level in levels:
41+
if is_drift:
42+
price = float(level["price"]) / 1e6
43+
size = float(level["size"]) / 1e9
44+
else:
45+
price = float(level["px"])
46+
size = float(level["sz"])
47+
48+
if total_volume + size >= volume:
49+
remaining_volume = volume - total_volume
50+
total_cost += remaining_volume * price
51+
total_volume += remaining_volume
52+
break
53+
else:
54+
total_cost += size * price
55+
total_volume += size
8556

86-
for level in levels:
87-
px = float(level["px"])
88-
sz = float(level["sz"])
57+
if total_volume < volume:
58+
raise ValueError("Insufficient volume in the order book")
8959

90-
if total_volume + sz >= volume:
91-
# Only take the remaining required volume at this level
92-
remaining_volume = volume - total_volume
93-
total_cost += remaining_volume * px
94-
total_volume += remaining_volume
95-
break
96-
else:
97-
# Take the whole size at this level
98-
total_cost += sz * px
99-
total_volume += sz
60+
return total_cost / volume
10061

101-
if total_volume < volume:
102-
raise ValueError(
103-
"Insufficient volume in the order book to fill the order"
104-
)
10562

106-
return total_cost / volume
63+
def get_orderbook_data(coin: str, size: float) -> Tuple[Dict, Dict, float, Dict]:
64+
hl_meta, hl_book = fetch_hyperliquid_data(coin)
65+
drift_book = fetch_drift_data(coin)
10766

108-
try:
109-
buy_price = average_price(buy_levels, volume)
110-
sell_price = average_price(sell_levels, volume)
111-
except ValueError as e:
112-
return str(e)
67+
try:
68+
hl_buy = calculate_avg_fill_price(hl_book["levels"][1], size)
69+
hl_sell = calculate_avg_fill_price(hl_book["levels"][0], size)
70+
hl_prices = {"average_buy_price": hl_buy, "average_sell_price": hl_sell}
71+
except (ValueError, KeyError) as e:
72+
hl_prices = str(e)
11373

114-
return {"average_buy_price": buy_price, "average_sell_price": sell_price}
74+
try:
75+
drift_buy = calculate_avg_fill_price(drift_book["asks"], size, is_drift=True)
76+
drift_sell = calculate_avg_fill_price(drift_book["bids"], size, is_drift=True)
77+
drift_prices = {
78+
"average_buy_price": drift_buy,
79+
"average_sell_price": drift_sell,
80+
}
81+
except (ValueError, KeyError) as e:
82+
drift_prices = str(e)
11583

116-
r = calculate_average_fill_price_hl(results["hl_book"], size)
117-
d = calculate_average_fill_price_dr(results["dr_book"], size)
118-
return (r, d, results["dr_book"]["oracle"] / 1e6, results["hl_cxt"])
84+
return hl_prices, drift_prices, drift_book["oracle"] / 1e6, hl_meta
11985

12086

12187
def orderbook_page():
122-
s1, s2 = st.columns(2)
88+
st.title("Orderbook comparison")
89+
col1, col2 = st.columns(2)
90+
coin = col1.selectbox("Coin:", ["SOL", "BTC", "ETH"])
91+
size = col2.number_input("Size:", min_value=0.1, value=1.0, help="in base units")
92+
93+
hl_prices, drift_prices, drift_oracle, hl_meta = get_orderbook_data(coin, size)
12394

124-
coin = s1.selectbox("coin:", ["SOL", "BTC", "ETH"])
125-
size = s2.number_input("size:", min_value=0.1, value=1.0, help="in base units")
126-
hl, dr, dr_oracle, hl_ctx = fetch_orderbook_data(coin, size)
95+
coin_idx = next(
96+
i for i, x in enumerate(hl_meta[0]["universe"]) if coin == x["name"]
97+
)
98+
col1, col2 = st.columns(2)
12799

128-
uni_id = [i for (i, x) in enumerate(hl_ctx[0]["universe"]) if coin == x["name"]]
100+
with col1:
101+
st.header("Hyperliquid")
102+
st.write(float(hl_meta[1][coin_idx]["oraclePx"]))
103+
st.write(hl_prices)
129104

130-
o1, o2 = st.columns(2)
131-
o1.header("hyperliquid")
132-
o1.write(float(hl_ctx[1][uni_id[0]]["oraclePx"]))
133-
o1.write(hl)
105+
with col2:
106+
st.header("Drift")
107+
st.write(drift_oracle)
108+
st.write(drift_prices)
134109

135-
o2.header("drift")
136-
o2.write(dr_oracle)
137-
o2.write(dr)
138110
if st.button("Refresh"):
139111
st.cache_data.clear()

0 commit comments

Comments
 (0)