Trireme commited on
Commit
41e70e0
·
verified ·
1 Parent(s): 1edd569

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +292 -38
app.py CHANGED
@@ -1,5 +1,7 @@
1
  # -*- coding: utf-8 -*-
 
2
  from pymongo import MongoClient
 
3
  import pandas as pd
4
  import requests
5
  import json
@@ -8,10 +10,272 @@ import gradio as gr
8
  import datetime
9
  import os
10
 
11
- client = MongoClient(os.getenv('MONGO_DB_URI'))
12
- db = client["Patchy_balances"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  collection = db["balance_data"]
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def load_from_mongo():
16
  latest = collection.find_one(sort=[("timestamp", -1)])
17
  if latest:
@@ -19,56 +283,46 @@ def load_from_mongo():
19
  df1 = pd.DataFrame(latest["df1"]).T
20
  df2 = pd.DataFrame(latest["df2"]).T
21
  df3 = pd.DataFrame(latest["df3"]).T
22
- df4 = pd.DataFrame(latest["df4"]).T
23
 
24
  return (
25
  df0, latest["total0"],
26
  df1, latest["total1"],
27
  df2, latest["total2"],
28
  df3, latest["total3"],
29
- df4, latest["total4"],
30
- f"PNL : {latest['pnl']:,.2f}",
31
- f"LP Rewards : {latest['rewards']:,.2f}"
32
  )
33
  else:
34
  empty_df = pd.DataFrame()
35
- return empty_df, 0, empty_df, 0, empty_df, 0, empty_df, 0, empty_df, 0,"PNL : $0.00","LP Rewards : $0.00"
36
 
37
- if __name__ == "__main__":
38
- with gr.Blocks() as demo:
39
- gr.Markdown("## Patchy Balances and PnL")
40
 
41
- df0_out = gr.Dataframe(label="Starting Balances")
42
- txt0_out = gr.Textbox(label="Starting Value Total")
43
 
44
- df2_out = gr.Dataframe(label="Wallet Balances")
45
- txt2_out = gr.Textbox(label="Wallet Value Total")
46
 
47
- df3_out = gr.Dataframe(label="JUP Limit Balances")
48
- txt3_out = gr.Textbox(label="JUP Limit Value Total")
49
 
50
- df4_out = gr.Dataframe(label="LP Balances")
51
- txt4_out = gr.Textbox(label="LP Balances Value Total")
52
 
53
- reward_out = gr.Textbox(label="LP Rewards")
54
 
55
- df1_out = gr.Dataframe(label="Total Balances")
56
- txt1_out = gr.Textbox(label="Current Value Total")
57
-
58
- pnl_out = gr.Textbox(label="PNL (AUM Model)")
59
-
60
- # Load from MongoDB on app load (sync function)
61
- demo.load(
62
- fn=load_from_mongo,
63
- inputs=[],
64
- outputs=[
65
- df0_out, txt0_out,
66
- df1_out, txt1_out,
67
- df2_out, txt2_out,
68
- df3_out, txt3_out,
69
- df4_out, txt4_out,
70
- pnl_out,reward_out
71
- ]
72
- )
73
 
74
- demo.launch(debug=True, share=True)
 
1
  # -*- coding: utf-8 -*-
2
+ import asyncio
3
  from pymongo import MongoClient
4
+ import aiohttp
5
  import pandas as pd
6
  import requests
7
  import json
 
10
  import datetime
11
  import os
12
 
13
+
14
+ wallets = [
15
+ "J7QAjhEGTAx71RoS1Nnuz4aKqK866xEnRXky4zhPa2WG",
16
+ "9huTEYifjBMJVhPWG3dX84S1Pr6pgXBH9i7274dpPeMr",
17
+ "CoA4vLyykjYobxEsDWHEx2Rna9WribGQMxSxVkH5NwN6",
18
+ "BpaD3QF9Z2YtUqPRxpTn7dgC2sBzpzxro5zrEdwhwNd9",
19
+ "FWmhs5vdUSMHUE5sHPQmd1hBEQVWD8wyCPe9op3KwTNg",
20
+ "HW1qacccywvtEmUK6mDWfaJfxcM1R64T8BmhfjmxA6Nx",
21
+ "3QpWHc77Vze5uiqm6WDfxYawKUj1bVbKEegS3YYBLGvL",
22
+ "5FyNV778E1SZ4ZBwUXCgbx43zrJFdMy4UgUysSw3yocU",
23
+ "4L3wPZc8smLYQbnpMSxHCiRB5cojbtuc33NkTNsrtdug",
24
+ "MruHB1owAkBQwtSkzTqTDpqZEDPmz4iUWz3oHCYHKWV"
25
+ ]
26
+
27
+ #SCRAPE_DO_TOKEN = os.getenv('SCRAPE_DO_KEY')
28
+ #client = MongoClient(os.getenv('MONGO_DB_URI'))
29
+
30
+
31
+ SCRAPE_DO_TOKEN = "c3cb4da35304433483052fb6ba0c7011fef2ff42d62"
32
+ client = MongoClient("mongodb+srv://djamaal:FHmV2N733lzrLkWf@test-cluster.mys4n.mongodb.net/")
33
+
34
+ db = client["billy_balances"]
35
+ token_collection = db["turnstile-tokens"]
36
+
37
+ turnstile_token = token_collection.find_one(sort=[("timestamp", -1)])['x-turnstile-token']
38
+
39
+ common_headers = {
40
+ "accept": "application/json",
41
+ "accept-encoding": "identity",
42
+ "accept-language": "en-GB,en-US;q=0.9,en;q=0.8",
43
+ "authorization": "Bearer CGtF4EdvDbBpwUXmZSKW3HsYkajy7e",
44
+ "content-type": "application/json",
45
+ "origin": "https://portfolio.jup.ag",
46
+ "referer": "https://portfolio.jup.ag/",
47
+ "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
48
+ "x-turnstile-token": turnstile_token # keep this updated
49
+ }
50
+
51
+ async def fetch_portfolio(session, wallet_address, results):
52
+ base_url = f"https://portfolio-api-jup.sonar.watch/v1/portfolio/fetch?address={wallet_address}&addressSystem=solana"
53
+ encoded_url = urllib.parse.quote(base_url)
54
+ proxy_url = f"http://api.scrape.do/?token={SCRAPE_DO_TOKEN}&url={encoded_url}&forwardHeaders=True&super=True"
55
+
56
+ try:
57
+ async with session.get(proxy_url, headers=common_headers) as resp:
58
+ text = await resp.json()
59
+ if resp.status == 200:
60
+ print(f"✅ Wallet {wallet_address[:6]}...: success")
61
+ results.append({"wallet": wallet_address,"data": text})
62
+ else:
63
+ print(f"❌ Wallet {wallet_address[:6]}...: HTTP {resp.status}")
64
+ results.append({"wallet": wallet_address, "data": None})
65
+ except Exception as e:
66
+ print(f"⚠️ Error fetching {wallet_address}: {e}")
67
+ results.append({"wallet": wallet_address, "status": "error", "error": str(e)})
68
+
69
+ async def get_data(wallet_addresses):
70
+ results = []
71
+ async with aiohttp.ClientSession() as session:
72
+ tasks = [fetch_portfolio(session, address, results) for address in wallet_addresses]
73
+ await asyncio.gather(*tasks)
74
+ return results
75
+ #Have a button function which does all this
76
+
77
+ async def process_data():
78
+ portfolios = await get_data(wallets)
79
+ df = pd.DataFrame(portfolios)
80
+ token_rows = []
81
+
82
+ for index, row in df.iterrows():
83
+ data = row['data']
84
+
85
+ # Token info mapping
86
+ token_info = data.get('tokenInfo', {}).get('solana', {})
87
+
88
+ # Navigate to assets list
89
+ elements = data.get('elements', [])
90
+ for element in elements:
91
+ if element.get('type') == 'multiple':
92
+ assets = element.get('data', {}).get('assets', [])
93
+ for asset in assets:
94
+ asset_data = asset.get('data', {})
95
+ address = asset_data.get('address')
96
+ amount = asset_data.get('amount')
97
+ value = asset.get('value')
98
+
99
+ # Get symbol using address
100
+ symbol = token_info.get(address, {}).get('symbol', 'UNKNOWN')
101
+
102
+ token_rows.append({
103
+ 'original_row': index,
104
+ 'address': address,
105
+ 'symbol': symbol,
106
+ 'amount': amount,
107
+ 'value': value
108
+ })
109
+
110
+ # Final DataFrame
111
+ tokens_df = pd.DataFrame(token_rows)
112
+ tokens_df['original_row'] = tokens_df['original_row'].apply(lambda x: df.loc[x, 'wallet'])
113
+ tokens_df = tokens_df.dropna()
114
+
115
+ # Pivot for values
116
+ value_pivot = tokens_df.pivot(index='original_row', columns='symbol', values='value')
117
+ value_pivot.columns = [f'{col}_value' for col in value_pivot.columns]
118
+
119
+ # Pivot for amounts
120
+ amount_pivot = tokens_df.pivot(index='original_row', columns='symbol', values='amount')
121
+ amount_pivot.columns = [f'{col}_amount' for col in amount_pivot.columns]
122
+
123
+ # Combine both
124
+ final_df = pd.concat([value_pivot, amount_pivot], axis=1).reset_index()
125
+
126
+ # Optional: Fill NaNs with 0
127
+ final_df = final_df.fillna(0)
128
+
129
+ rows = []
130
+ for idx, row in df.iterrows():
131
+ data = row['data']
132
+ original_row = row['wallet'] # or whatever uniquely identifies the row
133
+
134
+ for element in data.get("elements", []):
135
+ if element.get("platformId") == "jupiter-exchange":
136
+ input_token = element.get("data", {}).get("assets", {}).get("input", {})
137
+ if input_token:
138
+ token_data = input_token.get("data", {})
139
+ address = token_data.get("address")
140
+ value = input_token.get("value")
141
+ amount = token_data.get("amount")
142
+ symbol = token_info.get(address, {}).get("symbol", address)
143
+
144
+ rows.append({
145
+ "original_row": original_row,
146
+ "address": address,
147
+ "symbol": symbol,
148
+ "amount": amount,
149
+ "value": value
150
+ })
151
+
152
+ # Convert to DataFrame
153
+ jup_tokens_df = pd.DataFrame(rows)
154
+
155
+ jup_tokens_df['symbol'] = jup_tokens_df['symbol'].apply(lambda x: "SOL" if x == "So11111111111111111111111111111111111111112" else x)
156
+
157
+ # Pivot
158
+ # Group by original_row and symbol, sum value and amount
159
+ tokens_grouped = jup_tokens_df.groupby(['original_row', 'symbol']).agg({
160
+ 'value': 'sum',
161
+ 'amount': 'sum'
162
+ }).reset_index()
163
+
164
+ # Pivot
165
+ value_pivot = tokens_grouped.pivot(index='original_row', columns='symbol', values='value')
166
+ value_pivot.columns = [f'{col}_value' for col in value_pivot.columns]
167
+
168
+ amount_pivot = tokens_grouped.pivot(index='original_row', columns='symbol', values='amount')
169
+ amount_pivot.columns = [f'{col}_amount' for col in amount_pivot.columns]
170
+
171
+ jup_df = pd.concat([value_pivot, amount_pivot], axis=1).reset_index().fillna(0)
172
+
173
+ if "9Rhbn9G5poLvgnFzuYBtJgbzmiipNra35QpnUek9virt_value" in jup_df.columns:
174
+ jup_df = jup_df.rename(columns={"9Rhbn9G5poLvgnFzuYBtJgbzmiipNra35QpnUek9virt_value":"BILLY_value"})
175
+ if "9Rhbn9G5poLvgnFzuYBtJgbzmiipNra35QpnUek9virt_amount" in jup_df.columns:
176
+ jup_df = jup_df.rename(columns={"9Rhbn9G5poLvgnFzuYBtJgbzmiipNra35QpnUek9virt_amount":"BILLY_amount"})
177
+
178
+ final_df1 = final_df.set_index('original_row')
179
+ final_df2 = jup_df.set_index('original_row')
180
+
181
+ # Combine the two DataFrames, adding values where they overlap
182
+ combined_df = final_df1.add(final_df2, fill_value=0)
183
+
184
+ # Reset index if you want original_row back as a column
185
+ combined_df = combined_df.reset_index()
186
+
187
+ # Optional: fill NaNs (if any) with 0 just in case
188
+ combined_df = combined_df.fillna(0)
189
+
190
+ # Sum all numeric columns except the original_row which is non-numeric
191
+ totals = combined_df.select_dtypes(include='number').sum()
192
+
193
+ # Add a row with these totals at the bottom of the dataframe
194
+ totals_row = pd.DataFrame(totals).T
195
+ totals_row['original_row'] = 'Total'
196
+
197
+ # Append the totals row to the original df
198
+ df_with_totals = pd.concat([combined_df, totals_row], ignore_index=True)
199
+
200
+ totals = final_df.select_dtypes(include='number').sum()
201
+
202
+ # Add a row with these totals at the bottom of the dataframe
203
+ totals_row = pd.DataFrame(totals).T
204
+ totals_row['original_row'] = 'Total'
205
+
206
+ # Append the totals row to the original df
207
+ final_df = pd.concat([final_df, totals_row], ignore_index=True)
208
+
209
+ totals = jup_df.select_dtypes(include='number').sum()
210
+
211
+ # Add a row with these totals at the bottom of the dataframe
212
+ totals_row = pd.DataFrame(totals).T
213
+ totals_row['original_row'] = 'Total'
214
+
215
+ # Append the totals row to the original df
216
+ jup_df = pd.concat([jup_df, totals_row], ignore_index=True)
217
+
218
+ final_df = final_df.rename(columns={'original_row': ' '})
219
+ jup_df = jup_df.rename(columns={'original_row': ' '})
220
+ df_with_totals = df_with_totals.rename(columns={'original_row': ' '})
221
+
222
+ sol_price = 170
223
+ billy_price = 0.001845
224
+
225
+ # Starting balances
226
+ starting_balances = {
227
+ " ": ["Total"],
228
+ "SOL_amount": [344],
229
+ "SOL_value": [344 * sol_price],
230
+ "BILLY_amount": [75_000_000],
231
+ "BILLY_value": [75_000_000 * billy_price]
232
+ }
233
+
234
+ # Create the DataFrame
235
+ starting_df = pd.DataFrame(starting_balances)
236
+
237
+ return(starting_df,final_df.tail(1),jup_df.tail(1),df_with_totals.tail(1))
238
+
239
+
240
+
241
  collection = db["balance_data"]
242
 
243
+ def df_to_mongo_safe_dict(df):
244
+ return {str(k): v for k, v in df.to_dict(orient="index").items()}
245
+
246
+
247
+ async def display_data():
248
+ df0, df1, df2, df3 = await process_data()
249
+
250
+ def summarize(df):
251
+ value_cols = [col for col in df.columns if "value" in col.lower()]
252
+ total_value = df[value_cols].sum(axis=1).values[0] if value_cols else 0
253
+ return df, total_value
254
+
255
+ df0, total0 = summarize(df0)
256
+ df1, total1 = summarize(df1)
257
+ df2, total2 = summarize(df2)
258
+ df3, total3 = summarize(df3)
259
+
260
+ pnl = float(total3) - float(total0)
261
+
262
+ # Save to MongoDB
263
+ record = {
264
+ "timestamp": datetime.datetime.utcnow(),
265
+ "df0": df_to_mongo_safe_dict(df0),
266
+ "total0": float(total0),
267
+ "df1": df_to_mongo_safe_dict(df1),
268
+ "total1": float(total1),
269
+ "df2": df_to_mongo_safe_dict(df2),
270
+ "total2": float(total2),
271
+ "df3": df_to_mongo_safe_dict(df3),
272
+ "total3": float(total3),
273
+ "pnl": float(pnl)
274
+ }
275
+ collection.insert_one(record)
276
+
277
+ return df0, total0, df1, total1, df2, total2, df3, total3, f"PNL : {pnl:,.2f}"
278
+
279
  def load_from_mongo():
280
  latest = collection.find_one(sort=[("timestamp", -1)])
281
  if latest:
 
283
  df1 = pd.DataFrame(latest["df1"]).T
284
  df2 = pd.DataFrame(latest["df2"]).T
285
  df3 = pd.DataFrame(latest["df3"]).T
 
286
 
287
  return (
288
  df0, latest["total0"],
289
  df1, latest["total1"],
290
  df2, latest["total2"],
291
  df3, latest["total3"],
292
+ f"PNL : {latest['pnl']:,.2f}"
 
 
293
  )
294
  else:
295
  empty_df = pd.DataFrame()
296
+ return empty_df, 0, empty_df, 0, empty_df, 0, empty_df, 0, "PNL : 0.00"
297
 
298
+ with gr.Blocks() as demo:
299
+ gr.Markdown("## BILLY Balances and PnL")
 
300
 
301
+ df0_out = gr.Dataframe(label="Starting Balances")
302
+ txt0_out = gr.Textbox(label="Starting Value Total")
303
 
304
+ df1_out = gr.Dataframe(label="Wallet Balances")
305
+ txt1_out = gr.Textbox(label="Wallet Value Total")
306
 
307
+ df2_out = gr.Dataframe(label="JUP Limit Balances")
308
+ txt2_out = gr.Textbox(label="JUP Limit Value Total")
309
 
310
+ df3_out = gr.Dataframe(label="Total Balances")
311
+ txt3_out = gr.Textbox(label="Current Value Total")
312
 
313
+ pnl_out = gr.Textbox(label="PNL (AUM Model)")
314
 
315
+ # Load from MongoDB on app load (sync function)
316
+ demo.load(
317
+ fn=load_from_mongo,
318
+ inputs=[],
319
+ outputs=[
320
+ df0_out, txt0_out,
321
+ df1_out, txt1_out,
322
+ df2_out, txt2_out,
323
+ df3_out, txt3_out,
324
+ pnl_out
325
+ ]
326
+ )
 
 
 
 
 
 
327
 
328
+ demo.launch(debug=True, share=True)