rosacastillo commited on
Commit
f9ef62b
·
1 Parent(s): be3f31a

updating all files with new mech calls functions and better trader type description

Browse files
app.py CHANGED
@@ -223,7 +223,7 @@ with demo:
223
  trades_df=trades_df,
224
  )
225
  with gr.Column(scale=1):
226
- trade_details_text = get_trade_metrics_text()
227
 
228
  trade_details_selector.change(
229
  update_trade_details,
@@ -251,7 +251,7 @@ with demo:
251
  trader_filter="Olas",
252
  )
253
  with gr.Column(scale=1):
254
- trade_details_text = get_trade_metrics_text()
255
 
256
  def update_a_trade_details(trade_detail, trade_o_details_plot):
257
  new_a_plot = plot_trade_metrics(
@@ -287,7 +287,7 @@ with demo:
287
  trader_filter="non_Olas",
288
  )
289
  with gr.Column(scale=1):
290
- trade_details_text = get_trade_metrics_text()
291
 
292
  def update_na_trade_details(trade_detail, trade_details_plot):
293
  new_no_plot = plot_trade_metrics(
@@ -306,7 +306,7 @@ with demo:
306
  if len(unknown_trades) > 0:
307
  with gr.Row():
308
  gr.Markdown(
309
- "# Weekly trading metrics for trades coming from unknown traders"
310
  )
311
  with gr.Row():
312
  trade_u_details_selector = gr.Dropdown(
@@ -323,7 +323,9 @@ with demo:
323
  trader_filter="all",
324
  )
325
  with gr.Column(scale=1):
326
- trade_details_text = get_trade_metrics_text()
 
 
327
 
328
  def update_na_trade_details(trade_detail, trade_u_details_plot):
329
  new_u_plot = plot_trade_metrics(
 
223
  trades_df=trades_df,
224
  )
225
  with gr.Column(scale=1):
226
+ trade_details_text = get_trade_metrics_text(trader_type=None)
227
 
228
  trade_details_selector.change(
229
  update_trade_details,
 
251
  trader_filter="Olas",
252
  )
253
  with gr.Column(scale=1):
254
+ trade_details_text = get_trade_metrics_text(trader_type="Olas")
255
 
256
  def update_a_trade_details(trade_detail, trade_o_details_plot):
257
  new_a_plot = plot_trade_metrics(
 
287
  trader_filter="non_Olas",
288
  )
289
  with gr.Column(scale=1):
290
+ trade_details_text = get_trade_metrics_text("non_Olas")
291
 
292
  def update_na_trade_details(trade_detail, trade_details_plot):
293
  new_no_plot = plot_trade_metrics(
 
306
  if len(unknown_trades) > 0:
307
  with gr.Row():
308
  gr.Markdown(
309
+ "# Weekly trading metrics for trades coming from Unclassified traders"
310
  )
311
  with gr.Row():
312
  trade_u_details_selector = gr.Dropdown(
 
323
  trader_filter="all",
324
  )
325
  with gr.Column(scale=1):
326
+ trade_details_text = get_trade_metrics_text(
327
+ trader_type="unclassified"
328
+ )
329
 
330
  def update_na_trade_details(trade_detail, trade_u_details_plot):
331
  new_u_plot = plot_trade_metrics(
data/all_trades_profitability.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:6d097ed0d81bd0fa9f2e301a1db66da1a5cb122f1ad8626327715dcaff127b83
3
- size 3558217
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ec1f80e9de64d8981ac58b91de9e17f371c0620544c9012168519a6a789b512c
3
+ size 3537818
data/daily_info.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d6d36bd873a5fe9564f556eda0210078a0e9c3d0dd81fec2158cf029ed462573
3
- size 911119
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fed76273653048f900faca2d612b07f42be43d076238f0dac7f30e8882a1ec1b
3
+ size 374565
data/service_map.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:574e816f13aee41f153346e0590bbaeb5115578faa6aa9129dbda8b49b4d7fd2
3
- size 90733
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6109116eb0c946088a55420b04cc85576985cb0bef7ec47c3b2be97ee85688e8
3
+ size 90766
data/tools_accuracy.csv CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:15077d12895fc6ee9f9e8e1ac3a1d84e45350e261590bb15af5a11378ce83c49
3
  size 1101
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33bf015940a44f02ababb579398272ffc258a48d10e16be075179f18f4a2d578
3
  size 1101
scripts/daily_data.py CHANGED
@@ -5,7 +5,11 @@ from profitability import (
5
  label_trades_by_staking,
6
  )
7
  import pandas as pd
8
- from nr_mech_calls import create_unknown_traders_df
 
 
 
 
9
 
10
  logging.basicConfig(level=logging.INFO)
11
 
@@ -16,8 +20,16 @@ def prepare_live_metrics(
16
  ):
17
  fpmmTrades = pd.read_parquet(TMP_DIR / trades_filename)
18
  tools = pd.read_parquet(TMP_DIR / tools_filename)
 
 
 
 
 
 
19
  print("Analysing trades...")
20
- all_trades_df = analyse_all_traders(fpmmTrades, tools, daily_info=True)
 
 
21
 
22
  # staking label
23
  label_trades_by_staking(all_trades_df)
 
5
  label_trades_by_staking,
6
  )
7
  import pandas as pd
8
+ from nr_mech_calls import (
9
+ create_unknown_traders_df,
10
+ compute_daily_mech_calls,
11
+ transform_to_datetime,
12
+ )
13
 
14
  logging.basicConfig(level=logging.INFO)
15
 
 
20
  ):
21
  fpmmTrades = pd.read_parquet(TMP_DIR / trades_filename)
22
  tools = pd.read_parquet(TMP_DIR / tools_filename)
23
+
24
+ fpmmTrades["creationTimestamp"] = fpmmTrades["creationTimestamp"].apply(
25
+ lambda x: transform_to_datetime(x)
26
+ )
27
+ print("Computing the estimated mech calls dataset")
28
+ trader_mech_calls = compute_daily_mech_calls(fpmmTrades=fpmmTrades, tools=tools)
29
  print("Analysing trades...")
30
+ all_trades_df = analyse_all_traders(
31
+ fpmmTrades, tools, trader_mech_calls, daily_info=True
32
+ )
33
 
34
  # staking label
35
  label_trades_by_staking(all_trades_df)
scripts/get_mech_info.py CHANGED
@@ -1,7 +1,13 @@
1
  from string import Template
2
  from typing import Any
3
  from datetime import datetime, timedelta, UTC
4
- from utils import SUBGRAPH_API_KEY, measure_execution_time, DATA_DIR, TMP_DIR
 
 
 
 
 
 
5
  import requests
6
  import pandas as pd
7
  import numpy as np
@@ -16,14 +22,6 @@ from mech_request_utils import (
16
  )
17
  from web3_utils import updating_timestamps
18
 
19
- OLD_MECH_SUBGRAPH_URL = (
20
- "https://api.thegraph.com/subgraphs/name/stakewise/ethereum-gnosis"
21
- )
22
-
23
- NETWORK_SUBGRAPH_URL = Template(
24
- """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/FxV6YUix58SpYmLBwc9gEHkwjfkqwe1X5FJQjn8nKPyA"""
25
- )
26
-
27
  SUBGRAPH_HEADERS = {
28
  "Accept": "application/json, multipart/mixed",
29
  "Content-Type": "application/json",
@@ -321,18 +319,19 @@ def get_mech_events_since_last_run():
321
  last_block_number = get_last_block_number()
322
 
323
  # mech requests
324
- requests_dict, duplicatedReqId = collect_all_mech_requests(
325
  from_block=last_run_block_number,
326
  to_block=last_block_number,
327
  filename="new_mech_requests.json",
328
  )
329
-
330
  # mech delivers
331
- delivers_dict, duplicatedIds = collect_all_mech_delivers(
332
  from_block=last_run_block_number,
333
  to_block=last_block_number,
334
  filename="new_mech_delivers.json",
335
  )
 
336
  if delivers_dict is None:
337
  return None
338
  # clean delivers
@@ -357,14 +356,14 @@ def get_mech_events_last_60_days():
357
  earliest_block_number = get_last_60_days_block_number()
358
  last_block_number = get_last_block_number()
359
  # mech requests
360
- requests_dict, duplicatedReqId = collect_all_mech_requests(
361
  from_block=earliest_block_number,
362
  to_block=last_block_number,
363
  filename="mech_requests.json",
364
  )
365
 
366
  # mech delivers
367
- delivers_dict, duplicatedIds = collect_all_mech_delivers(
368
  from_block=earliest_block_number,
369
  to_block=last_block_number,
370
  filename="mech_delivers.json",
 
1
  from string import Template
2
  from typing import Any
3
  from datetime import datetime, timedelta, UTC
4
+ from utils import (
5
+ SUBGRAPH_API_KEY,
6
+ measure_execution_time,
7
+ DATA_DIR,
8
+ TMP_DIR,
9
+ NETWORK_SUBGRAPH_URL,
10
+ )
11
  import requests
12
  import pandas as pd
13
  import numpy as np
 
22
  )
23
  from web3_utils import updating_timestamps
24
 
 
 
 
 
 
 
 
 
25
  SUBGRAPH_HEADERS = {
26
  "Accept": "application/json, multipart/mixed",
27
  "Content-Type": "application/json",
 
319
  last_block_number = get_last_block_number()
320
 
321
  # mech requests
322
+ requests_dict, duplicatedReqId, nr_errors = collect_all_mech_requests(
323
  from_block=last_run_block_number,
324
  to_block=last_block_number,
325
  filename="new_mech_requests.json",
326
  )
327
+ print(f"NUMBER OF MECH REQUEST ERRORS={nr_errors}")
328
  # mech delivers
329
+ delivers_dict, duplicatedIds, nr_errors = collect_all_mech_delivers(
330
  from_block=last_run_block_number,
331
  to_block=last_block_number,
332
  filename="new_mech_delivers.json",
333
  )
334
+ print(f"NUMBER OF MECH DELIVER ERRORS={nr_errors}")
335
  if delivers_dict is None:
336
  return None
337
  # clean delivers
 
356
  earliest_block_number = get_last_60_days_block_number()
357
  last_block_number = get_last_block_number()
358
  # mech requests
359
+ requests_dict, duplicatedReqId, nr_errors = collect_all_mech_requests(
360
  from_block=earliest_block_number,
361
  to_block=last_block_number,
362
  filename="mech_requests.json",
363
  )
364
 
365
  # mech delivers
366
+ delivers_dict, duplicatedIds, nr_errors = collect_all_mech_delivers(
367
  from_block=earliest_block_number,
368
  to_block=last_block_number,
369
  filename="mech_delivers.json",
scripts/markets.py CHANGED
@@ -26,7 +26,12 @@ import requests
26
  from tqdm import tqdm
27
  from typing import List, Dict
28
  from utils import SUBGRAPH_API_KEY, DATA_DIR, TMP_DIR
29
- from web3_utils import FPMM_QS_CREATOR, FPMM_PEARL_CREATOR, query_omen_xdai_subgraph
 
 
 
 
 
30
  from queries import (
31
  FPMMS_QUERY,
32
  ID_FIELD,
@@ -45,9 +50,6 @@ SubgraphResponseType = Dict[str, ResponseItemType]
45
  BATCH_SIZE = 1000
46
  DEFAULT_TO_TIMESTAMP = 2147483647 # around year 2038
47
  DEFAULT_FROM_TIMESTAMP = 0
48
- OMEN_SUBGRAPH_URL = Template(
49
- """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/9fUVQpFwzpdWS9bq5WkAnmKbNNcoBwatMR4yZq81pbbz"""
50
- )
51
 
52
  MAX_UINT_HEX = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
53
  DEFAULT_FILENAME = "fpmms.parquet"
 
26
  from tqdm import tqdm
27
  from typing import List, Dict
28
  from utils import SUBGRAPH_API_KEY, DATA_DIR, TMP_DIR
29
+ from web3_utils import (
30
+ FPMM_QS_CREATOR,
31
+ FPMM_PEARL_CREATOR,
32
+ query_omen_xdai_subgraph,
33
+ OMEN_SUBGRAPH_URL,
34
+ )
35
  from queries import (
36
  FPMMS_QUERY,
37
  ID_FIELD,
 
50
  BATCH_SIZE = 1000
51
  DEFAULT_TO_TIMESTAMP = 2147483647 # around year 2038
52
  DEFAULT_FROM_TIMESTAMP = 0
 
 
 
53
 
54
  MAX_UINT_HEX = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
55
  DEFAULT_FILENAME = "fpmms.parquet"
scripts/mech_request_utils.py CHANGED
@@ -36,7 +36,7 @@ from tools import (
36
  from tqdm import tqdm
37
  from web3_utils import FPMM_QS_CREATOR, FPMM_PEARL_CREATOR, IPFS_POLL_INTERVAL
38
  from concurrent.futures import ThreadPoolExecutor, as_completed
39
- from utils import DATA_DIR, JSON_DATA_DIR
40
 
41
  NUM_WORKERS = 10
42
  BLOCKS_CHUNK_SIZE = 10000
@@ -44,7 +44,6 @@ TEXT_ALIGNMENT = 30
44
  MINIMUM_WRITE_FILE_DELAY_SECONDS = 20
45
  MECH_FROM_BLOCK_RANGE = 50000
46
  IPFS_ADDRESS = "https://gateway.autonolas.tech/ipfs/"
47
- THEGRAPH_ENDPOINT = "https://api.studio.thegraph.com/query/57238/mech/0.0.2"
48
  last_write_time = 0.0
49
 
50
  REQUESTS_QUERY_FILTER = """
@@ -109,10 +108,12 @@ def collect_all_mech_requests(from_block: int, to_block: int, filename: str) ->
109
  print(f"Fetching all mech requests from {from_block} to {to_block}")
110
  mech_requests = {}
111
  duplicated_reqIds = []
112
- transport = RequestsHTTPTransport(url=THEGRAPH_ENDPOINT)
 
113
  client = Client(transport=transport, fetch_schema_from_transport=True)
114
 
115
  id_gt = "0x00"
 
116
  while True:
117
  variables = {
118
  "sender_not_in": [FPMM_QS_CREATOR, FPMM_PEARL_CREATOR],
@@ -121,9 +122,6 @@ def collect_all_mech_requests(from_block: int, to_block: int, filename: str) ->
121
  "blockNumber_lte": str(to_block), # str
122
  }
123
  try:
124
- # response = client.execute(
125
- # gql(REQUESTS_QUERY_FILTER), variable_values=variables
126
- # )
127
  response = fetch_with_retry(client, REQUESTS_QUERY_FILTER, variables)
128
 
129
  items = response.get("requests", [])
@@ -137,6 +135,8 @@ def collect_all_mech_requests(from_block: int, to_block: int, filename: str) ->
137
  else:
138
  duplicated_reqIds.append(mech_request["id"])
139
  except Exception as e:
 
 
140
  print(f"Error while getting the response: {e}")
141
 
142
  id_gt = items[-1]["id"]
@@ -149,7 +149,7 @@ def collect_all_mech_requests(from_block: int, to_block: int, filename: str) ->
149
  print(f"Number of requests = {len(mech_requests)}")
150
  print(f"Number of duplicated req Ids = {len(duplicated_reqIds)}")
151
  save_json_file(mech_requests, filename)
152
- return mech_requests, duplicated_reqIds
153
 
154
 
155
  def fetch_with_retry(client, query, variables, max_retries=5):
@@ -169,12 +169,14 @@ def collect_all_mech_delivers(from_block: int, to_block: int, filename: str) ->
169
 
170
  mech_delivers = {}
171
  duplicated_requestIds = []
172
- transport = RequestsHTTPTransport(url=THEGRAPH_ENDPOINT)
 
173
  client = Client(transport=transport, fetch_schema_from_transport=True)
174
  to_block = (
175
  to_block + MECH_FROM_BLOCK_RANGE
176
  ) # there is a delay between deliver and request
177
  id_gt = ""
 
178
  while True:
179
  variables = {
180
  "id_gt": id_gt,
@@ -182,9 +184,6 @@ def collect_all_mech_delivers(from_block: int, to_block: int, filename: str) ->
182
  "blockNumber_lte": str(to_block), # str
183
  }
184
  try:
185
- # response = client.execute(
186
- # gql(DELIVERS_QUERY_NO_FILTER), variable_values=variables
187
- # )
188
  response = fetch_with_retry(client, DELIVERS_QUERY_NO_FILTER, variables)
189
  items = response.get("delivers", [])
190
 
@@ -198,8 +197,10 @@ def collect_all_mech_delivers(from_block: int, to_block: int, filename: str) ->
198
  duplicated_requestIds.append(mech_deliver["requestId"])
199
  # we will handle the duplicated later
200
  except Exception as e:
 
 
201
  print(f"Error while getting the response: {e}")
202
- return None, None
203
 
204
  id_gt = items[-1]["id"]
205
  time.sleep(IPFS_POLL_INTERVAL)
@@ -210,7 +211,7 @@ def collect_all_mech_delivers(from_block: int, to_block: int, filename: str) ->
210
  print(f"Number of delivers = {len(mech_delivers)}")
211
  print(f"Number of duplicated request id = {len(duplicated_requestIds)}")
212
  save_json_file(mech_delivers, filename)
213
- return mech_delivers, duplicated_requestIds
214
 
215
 
216
  def collect_missing_delivers(request_id: int, block_number: int) -> Dict[str, Any]:
@@ -219,7 +220,8 @@ def collect_missing_delivers(request_id: int, block_number: int) -> Dict[str, An
219
  ) # there is a delay between deliver and request
220
  print(f"Fetching all missing delivers from {block_number} to {to_block}")
221
  mech_delivers = {}
222
- transport = RequestsHTTPTransport(url=THEGRAPH_ENDPOINT)
 
223
  client = Client(transport=transport, fetch_schema_from_transport=True)
224
 
225
  variables = {
@@ -277,7 +279,7 @@ def populate_requests_ipfs_contents(
277
  updated_dict[k] = mech_request
278
  time.sleep(IPFS_POLL_INTERVAL)
279
 
280
- return updated_dict
281
 
282
 
283
  def populate_delivers_ipfs_contents(
@@ -285,6 +287,7 @@ def populate_delivers_ipfs_contents(
285
  ) -> dict:
286
  """Function to complete the delivers content info from ipfs"""
287
  updated_dict = {}
 
288
  for k in tqdm(
289
  keys_to_traverse,
290
  desc="Fetching IPFS contents for delivers",
@@ -316,6 +319,7 @@ def populate_delivers_ipfs_contents(
316
  tqdm.write(f"Skipping {mech_request} because of JSONDecodeError")
317
  continue
318
  except Exception:
 
319
  tqdm.write(
320
  f"Skipping {mech_request} because of error parsing the response"
321
  )
@@ -323,7 +327,7 @@ def populate_delivers_ipfs_contents(
323
  updated_dict[k] = mech_request
324
  time.sleep(IPFS_POLL_INTERVAL)
325
 
326
- return updated_dict
327
 
328
 
329
  def write_mech_events_to_file(
@@ -500,6 +504,7 @@ def get_ipfs_data(input_filename: str, output_filename: str):
500
  session = create_session()
501
  print("UPDATING IPFS CONTENTS OF REQUESTS")
502
  # requests
 
503
  with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
504
  futures = []
505
  for i in range(0, len(mech_requests), GET_CONTENTS_BATCH_SIZE):
@@ -517,12 +522,15 @@ def get_ipfs_data(input_filename: str, output_filename: str):
517
  total=len(futures),
518
  desc=f"Fetching all ipfs contents from requests ",
519
  ):
520
- partial_dict = future.result()
 
521
  updated_mech_requests.update(partial_dict)
522
 
523
  save_json_file(updated_mech_requests, output_filename)
 
524
 
525
  # delivers
 
526
  print("UPDATING IPFS CONTENTS OF DELIVERS")
527
  total_keys_to_traverse = list(updated_mech_requests.keys())
528
  final_tools_content = {}
@@ -543,10 +551,12 @@ def get_ipfs_data(input_filename: str, output_filename: str):
543
  total=len(futures),
544
  desc=f"Fetching all ipfs contents from delivers ",
545
  ):
546
- partial_dict = future.result()
 
547
  final_tools_content.update(partial_dict)
548
 
549
  save_json_file(final_tools_content, output_filename)
 
550
 
551
 
552
  def only_delivers_loop():
 
36
  from tqdm import tqdm
37
  from web3_utils import FPMM_QS_CREATOR, FPMM_PEARL_CREATOR, IPFS_POLL_INTERVAL
38
  from concurrent.futures import ThreadPoolExecutor, as_completed
39
+ from utils import DATA_DIR, JSON_DATA_DIR, MECH_SUBGRAPH_URL, SUBGRAPH_API_KEY
40
 
41
  NUM_WORKERS = 10
42
  BLOCKS_CHUNK_SIZE = 10000
 
44
  MINIMUM_WRITE_FILE_DELAY_SECONDS = 20
45
  MECH_FROM_BLOCK_RANGE = 50000
46
  IPFS_ADDRESS = "https://gateway.autonolas.tech/ipfs/"
 
47
  last_write_time = 0.0
48
 
49
  REQUESTS_QUERY_FILTER = """
 
108
  print(f"Fetching all mech requests from {from_block} to {to_block}")
109
  mech_requests = {}
110
  duplicated_reqIds = []
111
+ mech_subgraph_url = MECH_SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
112
+ transport = RequestsHTTPTransport(url=mech_subgraph_url)
113
  client = Client(transport=transport, fetch_schema_from_transport=True)
114
 
115
  id_gt = "0x00"
116
+ nr_errors = 0
117
  while True:
118
  variables = {
119
  "sender_not_in": [FPMM_QS_CREATOR, FPMM_PEARL_CREATOR],
 
122
  "blockNumber_lte": str(to_block), # str
123
  }
124
  try:
 
 
 
125
  response = fetch_with_retry(client, REQUESTS_QUERY_FILTER, variables)
126
 
127
  items = response.get("requests", [])
 
135
  else:
136
  duplicated_reqIds.append(mech_request["id"])
137
  except Exception as e:
138
+ # counter for errors
139
+ nr_errors += 1
140
  print(f"Error while getting the response: {e}")
141
 
142
  id_gt = items[-1]["id"]
 
149
  print(f"Number of requests = {len(mech_requests)}")
150
  print(f"Number of duplicated req Ids = {len(duplicated_reqIds)}")
151
  save_json_file(mech_requests, filename)
152
+ return mech_requests, duplicated_reqIds, nr_errors
153
 
154
 
155
  def fetch_with_retry(client, query, variables, max_retries=5):
 
169
 
170
  mech_delivers = {}
171
  duplicated_requestIds = []
172
+ mech_subgraph_url = MECH_SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
173
+ transport = RequestsHTTPTransport(url=mech_subgraph_url)
174
  client = Client(transport=transport, fetch_schema_from_transport=True)
175
  to_block = (
176
  to_block + MECH_FROM_BLOCK_RANGE
177
  ) # there is a delay between deliver and request
178
  id_gt = ""
179
+ nr_errors = 0
180
  while True:
181
  variables = {
182
  "id_gt": id_gt,
 
184
  "blockNumber_lte": str(to_block), # str
185
  }
186
  try:
 
 
 
187
  response = fetch_with_retry(client, DELIVERS_QUERY_NO_FILTER, variables)
188
  items = response.get("delivers", [])
189
 
 
197
  duplicated_requestIds.append(mech_deliver["requestId"])
198
  # we will handle the duplicated later
199
  except Exception as e:
200
+ # counter for errors
201
+ nr_errors += 1
202
  print(f"Error while getting the response: {e}")
203
+ # return None, None
204
 
205
  id_gt = items[-1]["id"]
206
  time.sleep(IPFS_POLL_INTERVAL)
 
211
  print(f"Number of delivers = {len(mech_delivers)}")
212
  print(f"Number of duplicated request id = {len(duplicated_requestIds)}")
213
  save_json_file(mech_delivers, filename)
214
+ return mech_delivers, duplicated_requestIds, nr_errors
215
 
216
 
217
  def collect_missing_delivers(request_id: int, block_number: int) -> Dict[str, Any]:
 
220
  ) # there is a delay between deliver and request
221
  print(f"Fetching all missing delivers from {block_number} to {to_block}")
222
  mech_delivers = {}
223
+ mech_subgraph_url = MECH_SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
224
+ transport = RequestsHTTPTransport(url=mech_subgraph_url)
225
  client = Client(transport=transport, fetch_schema_from_transport=True)
226
 
227
  variables = {
 
279
  updated_dict[k] = mech_request
280
  time.sleep(IPFS_POLL_INTERVAL)
281
 
282
+ return updated_dict, wrong_response_count
283
 
284
 
285
  def populate_delivers_ipfs_contents(
 
287
  ) -> dict:
288
  """Function to complete the delivers content info from ipfs"""
289
  updated_dict = {}
290
+ errors = 0
291
  for k in tqdm(
292
  keys_to_traverse,
293
  desc="Fetching IPFS contents for delivers",
 
319
  tqdm.write(f"Skipping {mech_request} because of JSONDecodeError")
320
  continue
321
  except Exception:
322
+ errors += 1
323
  tqdm.write(
324
  f"Skipping {mech_request} because of error parsing the response"
325
  )
 
327
  updated_dict[k] = mech_request
328
  time.sleep(IPFS_POLL_INTERVAL)
329
 
330
+ return updated_dict, errors
331
 
332
 
333
  def write_mech_events_to_file(
 
504
  session = create_session()
505
  print("UPDATING IPFS CONTENTS OF REQUESTS")
506
  # requests
507
+ nr_errors = 0
508
  with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
509
  futures = []
510
  for i in range(0, len(mech_requests), GET_CONTENTS_BATCH_SIZE):
 
522
  total=len(futures),
523
  desc=f"Fetching all ipfs contents from requests ",
524
  ):
525
+ partial_dict, error_counter = future.result()
526
+ nr_errors += error_counter
527
  updated_mech_requests.update(partial_dict)
528
 
529
  save_json_file(updated_mech_requests, output_filename)
530
+ print(f"NUMBER OF MECH REQUEST IPFS ERRORS={nr_errors}")
531
 
532
  # delivers
533
+ nr_deliver_errors = 0
534
  print("UPDATING IPFS CONTENTS OF DELIVERS")
535
  total_keys_to_traverse = list(updated_mech_requests.keys())
536
  final_tools_content = {}
 
551
  total=len(futures),
552
  desc=f"Fetching all ipfs contents from delivers ",
553
  ):
554
+ partial_dict, error_counter = future.result()
555
+ nr_deliver_errors += error_counter
556
  final_tools_content.update(partial_dict)
557
 
558
  save_json_file(final_tools_content, output_filename)
559
+ print(f"NUMBER OF MECH DELIVERS IPFS ERRORS={nr_deliver_errors}")
560
 
561
 
562
  def only_delivers_loop():
scripts/nr_mech_calls.py CHANGED
@@ -1,6 +1,15 @@
1
  import pandas as pd
2
  from utils import DATA_DIR, DEFAULT_MECH_FEE
3
  from tqdm import tqdm
 
 
 
 
 
 
 
 
 
4
 
5
 
6
  def update_roi(row: pd.DataFrame) -> float:
@@ -12,6 +21,38 @@ def update_roi(row: pd.DataFrame) -> float:
12
  return new_value
13
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def create_unknown_traders_df(trades_df: pd.DataFrame) -> pd.DataFrame:
16
  """filter trades coming from non-Olas traders that are placing no mech calls"""
17
  no_mech_calls_mask = (trades_df["staking"] == "non_Olas") & (
@@ -66,6 +107,163 @@ def update_trade_nr_mech_calls(non_agents: bool = False):
66
  # summary_df.to_parquet(DATA_DIR / "summary_profitability.parquet", index=False)
67
 
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  if __name__ == "__main__":
70
  # update_trade_nr_mech_calls(non_agents=True)
71
  trades_df = pd.read_parquet(DATA_DIR / "all_trades_profitability.parquet")
 
1
  import pandas as pd
2
  from utils import DATA_DIR, DEFAULT_MECH_FEE
3
  from tqdm import tqdm
4
+ from datetime import datetime, timezone
5
+ from typing import Dict, Any
6
+ from collections import defaultdict
7
+ from tools import IRRELEVANT_TOOLS
8
+ import re
9
+
10
+
11
+ def transform_to_datetime(x):
12
+ return datetime.fromtimestamp(int(x), tz=timezone.utc)
13
 
14
 
15
  def update_roi(row: pd.DataFrame) -> float:
 
21
  return new_value
22
 
23
 
24
+ def get_mech_statistics(mech_requests: Dict[str, Any]) -> Dict[str, Dict[str, int]]:
25
+ """Outputs a table with Mech statistics"""
26
+
27
+ mech_statistics: Dict[str, Dict[str, int]] = defaultdict(lambda: defaultdict(int))
28
+
29
+ for mech_request in mech_requests.values():
30
+ if (
31
+ "ipfs_contents" not in mech_request
32
+ or "tool" not in mech_request["ipfs_contents"]
33
+ or "prompt" not in mech_request["ipfs_contents"]
34
+ ):
35
+ continue
36
+
37
+ if mech_request["ipfs_contents"]["tool"] in IRRELEVANT_TOOLS:
38
+ continue
39
+
40
+ prompt = mech_request["ipfs_contents"]["prompt"]
41
+ prompt = prompt.replace("\n", " ")
42
+ prompt = prompt.strip()
43
+ prompt = re.sub(r"\s+", " ", prompt)
44
+ prompt_match = re.search(r"\"(.*)\"", prompt)
45
+ if prompt_match:
46
+ question = prompt_match.group(1)
47
+ else:
48
+ question = prompt
49
+
50
+ mech_statistics[question]["count"] += 1
51
+ mech_statistics[question]["fees"] += mech_request["fee"]
52
+
53
+ return mech_statistics
54
+
55
+
56
  def create_unknown_traders_df(trades_df: pd.DataFrame) -> pd.DataFrame:
57
  """filter trades coming from non-Olas traders that are placing no mech calls"""
58
  no_mech_calls_mask = (trades_df["staking"] == "non_Olas") & (
 
107
  # summary_df.to_parquet(DATA_DIR / "summary_profitability.parquet", index=False)
108
 
109
 
110
+ def get_daily_mech_calls_estimation(
111
+ daily_trades: pd.DataFrame, daily_tools: pd.DataFrame
112
+ ) -> list:
113
+ # for each market
114
+ daily_markets = daily_trades.title.unique()
115
+ trader = daily_trades.iloc[0].trader_address
116
+ day = daily_trades.iloc[0].creation_date
117
+ estimations = []
118
+ for market in daily_markets:
119
+ estimation_dict = {}
120
+ estimation_dict["trader_address"] = trader
121
+ estimation_dict["trading_day"] = day
122
+ # tools usage of this market
123
+ market_requests = daily_tools.loc[daily_tools["title"] == market]
124
+ # trades done on this market
125
+ market_trades = daily_trades[daily_trades["title"] == market]
126
+ mech_calls_estimation = 0
127
+ total_trades = len(market_trades)
128
+ total_requests = 0
129
+ if len(market_requests) > 0:
130
+ total_requests = len(market_requests)
131
+ mech_calls_estimation = total_requests / total_trades
132
+ estimation_dict["total_trades"] = total_trades
133
+ estimation_dict["total_mech_requests"] = total_requests
134
+ estimation_dict["market"] = market
135
+ estimation_dict["mech_calls_per_trade"] = mech_calls_estimation
136
+ estimations.append(estimation_dict)
137
+ return estimations
138
+
139
+
140
+ def compute_daily_mech_calls(
141
+ fpmmTrades: pd.DataFrame, tools: pd.DataFrame
142
+ ) -> pd.DataFrame:
143
+ """Function to compute the daily mech calls at the trader and market level"""
144
+ nr_traders = len(fpmmTrades["trader_address"].unique())
145
+ fpmmTrades["creation_timestamp"] = pd.to_datetime(fpmmTrades["creationTimestamp"])
146
+ fpmmTrades["creation_date"] = fpmmTrades["creation_timestamp"].dt.date
147
+ trades_df = trades_df.sort_values(by="creation_timestamp", ascending=True)
148
+ tools["request_time"] = pd.to_datetime(tools["request_time"])
149
+ tools["request_date"] = tools["request_time"].dt.date
150
+ tools = tools.sort_values(by="request_time", ascending=True)
151
+ all_mech_calls = []
152
+ for trader in tqdm(
153
+ fpmmTrades["trader_address"].unique(),
154
+ total=nr_traders,
155
+ desc="creating mech calls estimation based on timestamps",
156
+ ):
157
+ # compute the mech calls estimations for each trader
158
+ all_trades = fpmmTrades[fpmmTrades["trader_address"] == trader]
159
+ all_tools = tools[tools["trader_address"] == trader]
160
+ trading_days = all_trades.creation_date.unique()
161
+ for trading_day in trading_days:
162
+ daily_trades = all_trades.loc[all_trades["creation_date"] == trading_day]
163
+ daily_tools = all_tools.loc[all_tools["request_date"] == trading_day]
164
+ trader_entry = {}
165
+ trader_entry["trader_address"] = trader
166
+ trader_entry["total_trades"] = len(daily_trades)
167
+ trader_entry["trading_day"] = trading_day
168
+ trader_entry["total_mech_calls"] = len(daily_tools)
169
+ all_mech_calls.append(trader_entry)
170
+ return pd.DataFrame.from_dict(all_mech_calls, orient="columns")
171
+
172
+
173
+ def compute_mech_call_estimations(
174
+ fpmmTrades: pd.DataFrame, tools: pd.DataFrame
175
+ ) -> pd.DataFrame:
176
+ """Function to compute the estimated mech calls needed per trade at the trader and market level"""
177
+ nr_traders = len(fpmmTrades["trader_address"].unique())
178
+ fpmmTrades["creation_timestamp"] = pd.to_datetime(fpmmTrades["creationTimestamp"])
179
+ fpmmTrades["creation_date"] = fpmmTrades["creation_timestamp"].dt.date
180
+ tools["request_time"] = pd.to_datetime(tools["request_time"])
181
+ tools["request_date"] = tools["request_time"].dt.date
182
+ all_estimations = []
183
+ for trader in tqdm(
184
+ fpmmTrades["trader_address"].unique(),
185
+ total=nr_traders,
186
+ desc="creating mech calls estimation dataframe",
187
+ ):
188
+ # compute the mech calls estimations for each trader
189
+ all_trades = fpmmTrades[fpmmTrades["trader_address"] == trader]
190
+ all_tools = tools[tools["trader_address"] == trader]
191
+ trading_days = all_trades.creation_date.unique()
192
+ for trading_day in trading_days:
193
+ daily_trades = all_trades.loc[all_trades["creation_date"] == trading_day]
194
+ daily_tools = all_tools.loc[all_tools["request_date"] == trading_day]
195
+ daily_estimations = get_daily_mech_calls_estimation(
196
+ daily_trades=daily_trades, daily_tools=daily_tools
197
+ )
198
+ all_estimations.extend(daily_estimations)
199
+ return pd.DataFrame.from_dict(all_estimations, orient="columns")
200
+
201
+
202
+ def compute_timestamp_mech_calls(
203
+ all_trades: pd.DataFrame, all_tools: pd.DataFrame
204
+ ) -> list:
205
+ """Function to compute the mech calls based on timestamps but without repeating mech calls"""
206
+ mech_calls_contents = []
207
+ request_timestamps_used = {}
208
+ # intialize the dict with all markets
209
+ all_markets = all_trades.title.unique()
210
+ for market in all_markets:
211
+ request_timestamps_used[market] = []
212
+
213
+ for i, trade in all_trades.iterrows():
214
+ trader = trade["trader_address"]
215
+ trade_id = trade["id"]
216
+ market = trade["title"]
217
+ trade_ts = trade["creation_timestamp"]
218
+ market_requests = all_tools.loc[
219
+ (all_tools["trader_address"] == trader) & (all_tools["title"] == market)
220
+ ]
221
+ # traverse market requests
222
+ total_mech_calls = 0
223
+ for mech_request in market_requests:
224
+ # check timestamp (before the trade)
225
+ request_ts = mech_request.request_time
226
+ if request_ts < trade_ts:
227
+ # check the timestamp has not been used in a previous trade
228
+ used_timestamps = request_timestamps_used[market]
229
+ if request_ts not in used_timestamps:
230
+ request_timestamps_used[market].append(request_ts)
231
+ total_mech_calls += 1
232
+ # create enty for the dataframe
233
+ mech_call_entry = {}
234
+ mech_call_entry["trader_address"] = trader
235
+ mech_call_entry["market"] = market
236
+ mech_call_entry["trade_id"] = trade_id
237
+ mech_call_entry["total_mech_calls"] = total_mech_calls
238
+ mech_calls_contents.append(mech_call_entry)
239
+ return mech_calls_contents
240
+
241
+
242
+ def compute_mech_calls_based_on_timestamps(
243
+ fpmmTrades: pd.DataFrame, tools: pd.DataFrame
244
+ ) -> pd.DataFrame:
245
+ """Function to compute the mech calls needed per trade at the trader and market level using timestamps"""
246
+ nr_traders = len(fpmmTrades["trader_address"].unique())
247
+ fpmmTrades["creation_timestamp"] = pd.to_datetime(fpmmTrades["creationTimestamp"])
248
+ fpmmTrades["creation_date"] = fpmmTrades["creation_timestamp"].dt.date
249
+ trades_df = trades_df.sort_values(by="creation_timestamp", ascending=True)
250
+ tools["request_time"] = pd.to_datetime(tools["request_time"])
251
+ tools["request_date"] = tools["request_time"].dt.date
252
+ tools = tools.sort_values(by="request_time", ascending=True)
253
+ all_mech_calls = []
254
+ for trader in tqdm(
255
+ fpmmTrades["trader_address"].unique(),
256
+ total=nr_traders,
257
+ desc="creating mech calls estimation based on timestamps",
258
+ ):
259
+ # compute the mech calls estimations for each trader
260
+ all_trades = fpmmTrades[fpmmTrades["trader_address"] == trader]
261
+ all_tools = tools[tools["trader_address"] == trader]
262
+ trader_mech_calls = compute_timestamp_mech_calls(all_trades, all_tools)
263
+ all_mech_calls.extend(trader_mech_calls)
264
+ return pd.DataFrame.from_dict(all_mech_calls, orient="columns")
265
+
266
+
267
  if __name__ == "__main__":
268
  # update_trade_nr_mech_calls(non_agents=True)
269
  trades_df = pd.read_parquet(DATA_DIR / "all_trades_profitability.parquet")
scripts/profitability.py CHANGED
@@ -40,7 +40,11 @@ from utils import (
40
  DEFAULT_MECH_FEE,
41
  )
42
  from staking import label_trades_by_staking
43
- from nr_mech_calls import create_unknown_traders_df
 
 
 
 
44
 
45
  DUST_THRESHOLD = 10000000000000
46
  INVALID_ANSWER = -1
@@ -215,12 +219,14 @@ def analyse_trader(
215
  trader_address: str,
216
  fpmmTrades: pd.DataFrame,
217
  tools: pd.DataFrame,
 
218
  daily_info: bool = False,
219
  ) -> pd.DataFrame:
220
  """Analyse a trader's trades"""
 
 
221
  # Filter trades and tools for the given trader
222
  trades = fpmmTrades[fpmmTrades["trader_address"] == trader_address]
223
- tools_usage = tools[tools["trader_address"] == trader_address]
224
 
225
  # Prepare the DataFrame
226
  trades_df = pd.DataFrame(columns=ALL_TRADES_STATS_DF_COLS)
@@ -238,14 +244,12 @@ def analyse_trader(
238
  for i, trade in tqdm(trades.iterrows(), total=len(trades), desc="Analysing trades"):
239
  try:
240
  market_answer = trade["fpmm.currentAnswer"]
 
 
241
  if not daily_info and not market_answer:
242
  print(f"Skipping trade {i} because currentAnswer is NaN")
243
  continue
244
  # Parsing and computing shared values
245
-
246
- creation_timestamp_utc = datetime.datetime.fromtimestamp(
247
- int(trade["creationTimestamp"]), tz=datetime.timezone.utc
248
- )
249
  collateral_amount = wei_to_unit(float(trade["collateralAmount"]))
250
  fee_amount = wei_to_unit(float(trade["feeAmount"]))
251
  outcome_tokens_traded = wei_to_unit(float(trade["outcomeTokensTraded"]))
@@ -280,25 +284,23 @@ def analyse_trader(
280
  earnings = outcome_tokens_traded
281
  winner_trade = True
282
 
283
- # Compute mech calls
284
- if len(tools_usage) == 0:
285
- print("No tools usage information")
286
- num_mech_calls = 0
 
 
287
  else:
288
- try:
289
- num_mech_calls = (
290
- tools_usage["prompt_request"]
291
- .apply(lambda x: trade["title"] in x)
292
- .sum()
293
- )
294
- except Exception:
295
- print(f"Error while getting the number of mech calls")
296
- num_mech_calls = 2 # Average value
297
 
298
  net_earnings = (
299
  earnings
300
  - fee_amount
301
- - (num_mech_calls * DEFAULT_MECH_FEE)
302
  - collateral_amount
303
  )
304
 
@@ -308,7 +310,7 @@ def analyse_trader(
308
  "market_creator": market_creator,
309
  "trade_id": trade["id"],
310
  "market_status": market_status.name,
311
- "creation_timestamp": creation_timestamp_utc,
312
  "title": trade["title"],
313
  "collateral_amount": collateral_amount,
314
  "outcome_index": trade["outcomeIndex"],
@@ -320,11 +322,13 @@ def analyse_trader(
320
  "earnings": earnings,
321
  "redeemed": redemption,
322
  "redeemed_amount": earnings if redemption else 0,
323
- "num_mech_calls": num_mech_calls,
324
- "mech_fee_amount": num_mech_calls * DEFAULT_MECH_FEE,
325
  "net_earnings": net_earnings,
326
  "roi": net_earnings
327
- / (collateral_amount + fee_amount + num_mech_calls * DEFAULT_MECH_FEE),
 
 
328
  }
329
 
330
  except Exception as e:
@@ -336,16 +340,27 @@ def analyse_trader(
336
 
337
 
338
  def analyse_all_traders(
339
- trades: pd.DataFrame, tools: pd.DataFrame, daily_info: bool = False
 
 
 
340
  ) -> pd.DataFrame:
341
  """Analyse all creators."""
 
342
  all_traders = []
343
  for trader in tqdm(
344
  trades["trader_address"].unique(),
345
  total=len(trades["trader_address"].unique()),
346
  desc="Analysing creators",
347
  ):
348
- all_traders.append(analyse_trader(trader, trades, tools, daily_info))
 
 
 
 
 
 
 
349
 
350
  # concat all creators
351
  all_creators_df = pd.concat(all_traders)
@@ -414,8 +429,16 @@ def run_profitability_analysis(
414
  update_tools_parquet(rpc, tools_filename)
415
  tools = pd.read_parquet(DATA_DIR / "tools.parquet")
416
 
 
 
 
 
 
 
 
 
417
  print("Analysing trades...")
418
- all_trades_df = analyse_all_traders(fpmmTrades, tools)
419
 
420
  # # merge previous files if requested
421
  if merge:
 
40
  DEFAULT_MECH_FEE,
41
  )
42
  from staking import label_trades_by_staking
43
+ from nr_mech_calls import (
44
+ create_unknown_traders_df,
45
+ transform_to_datetime,
46
+ compute_mech_calls_based_on_timestamps,
47
+ )
48
 
49
  DUST_THRESHOLD = 10000000000000
50
  INVALID_ANSWER = -1
 
219
  trader_address: str,
220
  fpmmTrades: pd.DataFrame,
221
  tools: pd.DataFrame,
222
+ trader_estimated_mech_calls: pd.DataFrame,
223
  daily_info: bool = False,
224
  ) -> pd.DataFrame:
225
  """Analyse a trader's trades"""
226
+ fpmmTrades["creation_timestamp"] = pd.to_datetime(fpmmTrades["creationTimestamp"])
227
+ fpmmTrades["creation_date"] = fpmmTrades["creation_timestamp"].dt.date
228
  # Filter trades and tools for the given trader
229
  trades = fpmmTrades[fpmmTrades["trader_address"] == trader_address]
 
230
 
231
  # Prepare the DataFrame
232
  trades_df = pd.DataFrame(columns=ALL_TRADES_STATS_DF_COLS)
 
244
  for i, trade in tqdm(trades.iterrows(), total=len(trades), desc="Analysing trades"):
245
  try:
246
  market_answer = trade["fpmm.currentAnswer"]
247
+ trading_day = trade["creation_date"]
248
+ trade_id = trade["id"]
249
  if not daily_info and not market_answer:
250
  print(f"Skipping trade {i} because currentAnswer is NaN")
251
  continue
252
  # Parsing and computing shared values
 
 
 
 
253
  collateral_amount = wei_to_unit(float(trade["collateralAmount"]))
254
  fee_amount = wei_to_unit(float(trade["feeAmount"]))
255
  outcome_tokens_traded = wei_to_unit(float(trade["outcomeTokensTraded"]))
 
284
  earnings = outcome_tokens_traded
285
  winner_trade = True
286
 
287
+ # Compute mech calls using the title, and trade id
288
+ if daily_info:
289
+ total_mech_calls = trader_estimated_mech_calls.loc[
290
+ (trader_estimated_mech_calls["trading_day"] == trading_day),
291
+ "total_mech_calls",
292
+ ].iloc[0]
293
  else:
294
+ total_mech_calls = trader_estimated_mech_calls.loc[
295
+ (trader_estimated_mech_calls["market"] == trade["title"])
296
+ & (trader_estimated_mech_calls["trade_id"] == trade_id),
297
+ "mech_calls_per_trade",
298
+ ].iloc[0]
 
 
 
 
299
 
300
  net_earnings = (
301
  earnings
302
  - fee_amount
303
+ - (total_mech_calls * DEFAULT_MECH_FEE)
304
  - collateral_amount
305
  )
306
 
 
310
  "market_creator": market_creator,
311
  "trade_id": trade["id"],
312
  "market_status": market_status.name,
313
+ "creation_timestamp": trade["creationTimestamp"],
314
  "title": trade["title"],
315
  "collateral_amount": collateral_amount,
316
  "outcome_index": trade["outcomeIndex"],
 
322
  "earnings": earnings,
323
  "redeemed": redemption,
324
  "redeemed_amount": earnings if redemption else 0,
325
+ "num_mech_calls": total_mech_calls,
326
+ "mech_fee_amount": total_mech_calls * DEFAULT_MECH_FEE,
327
  "net_earnings": net_earnings,
328
  "roi": net_earnings
329
+ / (
330
+ collateral_amount + fee_amount + total_mech_calls * DEFAULT_MECH_FEE
331
+ ),
332
  }
333
 
334
  except Exception as e:
 
340
 
341
 
342
  def analyse_all_traders(
343
+ trades: pd.DataFrame,
344
+ tools: pd.DataFrame,
345
+ estimated_mech_calls: pd.DataFrame,
346
+ daily_info: bool = False,
347
  ) -> pd.DataFrame:
348
  """Analyse all creators."""
349
+
350
  all_traders = []
351
  for trader in tqdm(
352
  trades["trader_address"].unique(),
353
  total=len(trades["trader_address"].unique()),
354
  desc="Analysing creators",
355
  ):
356
+ trader_estimated_mech_calls = estimated_mech_calls.loc[
357
+ estimated_mech_calls["trader_address"] == trader
358
+ ]
359
+ all_traders.append(
360
+ analyse_trader(
361
+ trader, trades, tools, trader_estimated_mech_calls, daily_info
362
+ )
363
+ )
364
 
365
  # concat all creators
366
  all_creators_df = pd.concat(all_traders)
 
429
  update_tools_parquet(rpc, tools_filename)
430
  tools = pd.read_parquet(DATA_DIR / "tools.parquet")
431
 
432
+ fpmmTrades["creationTimestamp"] = fpmmTrades["creationTimestamp"].apply(
433
+ lambda x: transform_to_datetime(x)
434
+ )
435
+ print("Computing the estimated mech calls dataset")
436
+ trade_mech_calls = compute_mech_calls_based_on_timestamps(
437
+ fpmmTrades=fpmmTrades, tools=tools
438
+ )
439
+ print(trade_mech_calls.total_mech_calls.describe())
440
  print("Analysing trades...")
441
+ all_trades_df = analyse_all_traders(fpmmTrades, tools, trade_mech_calls)
442
 
443
  # # merge previous files if requested
444
  if merge:
scripts/pull_data.py CHANGED
@@ -3,7 +3,7 @@ from datetime import datetime
3
  import pandas as pd
4
  from markets import etl as mkt_etl, DEFAULT_FILENAME as MARKETS_FILENAME, fpmmTrades_etl
5
  from tools import DEFAULT_FILENAME as TOOLS_FILENAME, generate_tools_file
6
- from profitability import run_profitability_analysis, DEFAULT_60_DAYS_AGO_TIMESTAMP
7
  from utils import (
8
  get_question,
9
  current_answer,
@@ -13,7 +13,6 @@ from utils import (
13
  HIST_DIR,
14
  )
15
  from get_mech_info import (
16
- get_mech_events_last_60_days,
17
  get_mech_events_since_last_run,
18
  update_json_files,
19
  )
@@ -57,7 +56,7 @@ def save_historical_data():
57
  filename = f"tools_{timestamp}.parquet"
58
  tools.to_parquet(HIST_DIR / filename, index=False)
59
  # save into cloud storage
60
- # load_historical_file(filename)
61
  except Exception as e:
62
  print(f"Error saving tools file in the historical folder {e}")
63
 
@@ -66,7 +65,7 @@ def save_historical_data():
66
  filename = f"all_trades_profitability_{timestamp}.parquet"
67
  all_trades.to_parquet(HIST_DIR / filename, index=False)
68
  # save into cloud storage
69
- # load_historical_file(filename)
70
 
71
  except Exception as e:
72
  print(
@@ -80,7 +79,7 @@ def only_new_weekly_analysis():
80
  rpc = RPC
81
  # Run markets ETL
82
  logging.info("Running markets ETL")
83
- # mkt_etl(MARKETS_FILENAME)
84
  logging.info("Markets ETL completed")
85
 
86
  # Mech events ETL
@@ -128,7 +127,7 @@ def only_new_weekly_analysis():
128
 
129
  save_historical_data()
130
 
131
- clean_old_data_from_parquet_files("2024-10-14")
132
 
133
  compute_tools_accuracy()
134
 
 
3
  import pandas as pd
4
  from markets import etl as mkt_etl, DEFAULT_FILENAME as MARKETS_FILENAME, fpmmTrades_etl
5
  from tools import DEFAULT_FILENAME as TOOLS_FILENAME, generate_tools_file
6
+ from profitability import run_profitability_analysis
7
  from utils import (
8
  get_question,
9
  current_answer,
 
13
  HIST_DIR,
14
  )
15
  from get_mech_info import (
 
16
  get_mech_events_since_last_run,
17
  update_json_files,
18
  )
 
56
  filename = f"tools_{timestamp}.parquet"
57
  tools.to_parquet(HIST_DIR / filename, index=False)
58
  # save into cloud storage
59
+ load_historical_file(filename)
60
  except Exception as e:
61
  print(f"Error saving tools file in the historical folder {e}")
62
 
 
65
  filename = f"all_trades_profitability_{timestamp}.parquet"
66
  all_trades.to_parquet(HIST_DIR / filename, index=False)
67
  # save into cloud storage
68
+ load_historical_file(filename)
69
 
70
  except Exception as e:
71
  print(
 
79
  rpc = RPC
80
  # Run markets ETL
81
  logging.info("Running markets ETL")
82
+ mkt_etl(MARKETS_FILENAME)
83
  logging.info("Markets ETL completed")
84
 
85
  # Mech events ETL
 
127
 
128
  save_historical_data()
129
 
130
+ clean_old_data_from_parquet_files("2024-10-17")
131
 
132
  compute_tools_accuracy()
133
 
scripts/utils.py CHANGED
@@ -9,6 +9,7 @@ import re
9
  from dataclasses import dataclass
10
  from pathlib import Path
11
  from enum import Enum
 
12
  from json.decoder import JSONDecodeError
13
 
14
  DEFAULT_MECH_FEE = 0.01
@@ -48,6 +49,21 @@ INC_TOOLS = [
48
  "prediction-request-reasoning-claude",
49
  "superforcaster",
50
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  SUBGRAPH_API_KEY = os.environ.get("SUBGRAPH_API_KEY", None)
53
  RPC = os.environ.get("RPC", None)
 
9
  from dataclasses import dataclass
10
  from pathlib import Path
11
  from enum import Enum
12
+ from string import Template
13
  from json.decoder import JSONDecodeError
14
 
15
  DEFAULT_MECH_FEE = 0.01
 
49
  "prediction-request-reasoning-claude",
50
  "superforcaster",
51
  ]
52
+ SUBGRAPH_URL = Template(
53
+ """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/7s9rGBffUTL8kDZuxvvpuc46v44iuDarbrADBFw5uVp2"""
54
+ )
55
+ OMEN_SUBGRAPH_URL = Template(
56
+ """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/9fUVQpFwzpdWS9bq5WkAnmKbNNcoBwatMR4yZq81pbbz"""
57
+ )
58
+ NETWORK_SUBGRAPH_URL = Template(
59
+ """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/FxV6YUix58SpYmLBwc9gEHkwjfkqwe1X5FJQjn8nKPyA"""
60
+ )
61
+ # THEGRAPH_ENDPOINT = (
62
+ # "https://api.studio.thegraph.com/query/78829/mech-predict/version/latest"
63
+ # )
64
+ MECH_SUBGRAPH_URL = Template(
65
+ """https://gateway.thegraph.com/api/${subgraph_api_key}/subgraphs/id/4YGoX3iXUni1NBhWJS5xyKcntrAzssfytJK7PQxxQk5g"""
66
+ )
67
 
68
  SUBGRAPH_API_KEY = os.environ.get("SUBGRAPH_API_KEY", None)
69
  RPC = os.environ.get("RPC", None)
scripts/web3_utils.py CHANGED
@@ -12,7 +12,7 @@ from tqdm import tqdm
12
  from web3 import Web3
13
  from typing import Any, Optional
14
  from web3.types import BlockParams
15
- from utils import JSON_DATA_DIR, DATA_DIR, SUBGRAPH_API_KEY, to_content
16
  from queries import conditional_tokens_gc_user_query, omen_xdai_trades_query
17
  import pandas as pd
18
 
@@ -30,6 +30,9 @@ N_RPC_RETRIES = 100
30
  RPC_POLL_INTERVAL = 0.05
31
  # IPFS_POLL_INTERVAL = 0.05 # low speed
32
  IPFS_POLL_INTERVAL = 0.2 # high speed
 
 
 
33
 
34
  headers = {
35
  "Accept": "application/json, multipart/mixed",
@@ -156,9 +159,7 @@ def updating_timestamps(rpc: str, tools_filename: str):
156
 
157
  def query_conditional_tokens_gc_subgraph(creator: str) -> dict[str, Any]:
158
  """Query the subgraph."""
159
- SUBGRAPH_URL = Template(
160
- """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/7s9rGBffUTL8kDZuxvvpuc46v44iuDarbrADBFw5uVp2"""
161
- )
162
  subgraph = SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
163
  all_results: dict[str, Any] = {"data": {"user": {"userPositions": []}}}
164
  userPositions_id_gt = ""
@@ -200,9 +201,7 @@ def query_omen_xdai_subgraph(
200
  fpmm_to_timestamp: float,
201
  ) -> dict[str, Any]:
202
  """Query the subgraph."""
203
- OMEN_SUBGRAPH_URL = Template(
204
- """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/9fUVQpFwzpdWS9bq5WkAnmKbNNcoBwatMR4yZq81pbbz"""
205
- )
206
  omen_subgraph = OMEN_SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
207
  print(f"omen_subgraph = {omen_subgraph}")
208
  grouped_results = defaultdict(list)
 
12
  from web3 import Web3
13
  from typing import Any, Optional
14
  from web3.types import BlockParams
15
+ from utils import JSON_DATA_DIR, DATA_DIR, SUBGRAPH_API_KEY, to_content, SUBGRAPH_URL
16
  from queries import conditional_tokens_gc_user_query, omen_xdai_trades_query
17
  import pandas as pd
18
 
 
30
  RPC_POLL_INTERVAL = 0.05
31
  # IPFS_POLL_INTERVAL = 0.05 # low speed
32
  IPFS_POLL_INTERVAL = 0.2 # high speed
33
+ OMEN_SUBGRAPH_URL = Template(
34
+ """https://gateway-arbitrum.network.thegraph.com/api/${subgraph_api_key}/subgraphs/id/9fUVQpFwzpdWS9bq5WkAnmKbNNcoBwatMR4yZq81pbbz"""
35
+ )
36
 
37
  headers = {
38
  "Accept": "application/json, multipart/mixed",
 
159
 
160
  def query_conditional_tokens_gc_subgraph(creator: str) -> dict[str, Any]:
161
  """Query the subgraph."""
162
+
 
 
163
  subgraph = SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
164
  all_results: dict[str, Any] = {"data": {"user": {"userPositions": []}}}
165
  userPositions_id_gt = ""
 
201
  fpmm_to_timestamp: float,
202
  ) -> dict[str, Any]:
203
  """Query the subgraph."""
204
+
 
 
205
  omen_subgraph = OMEN_SUBGRAPH_URL.substitute(subgraph_api_key=SUBGRAPH_API_KEY)
206
  print(f"omen_subgraph = {omen_subgraph}")
207
  grouped_results = defaultdict(list)
tabs/metrics.py CHANGED
@@ -187,13 +187,43 @@ def plot_trade_metrics(
187
  )
188
 
189
 
190
- def get_trade_metrics_text() -> gr.Markdown:
191
- metric_text = """
192
- ## Description of the graph
193
- These metrics are computed weekly. The statistical measures are:
194
- * min, max, 25th(q1), 50th(median) and 75th(q2) percentiles
195
- * the upper and lower fences to delimit possible outliers
196
- * the average values as the dotted lines
197
- """
198
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  return gr.Markdown(metric_text)
 
187
  )
188
 
189
 
190
+ def get_trade_metrics_text(trader_type: str = None) -> gr.Markdown:
191
+ if trader_type is None:
192
+ metric_text = """
193
+ ## Description of the graph
194
+ These metrics are computed weekly. The statistical measures are:
195
+ * min, max, 25th(q1), 50th(median) and 75th(q2) percentiles
196
+ * the upper and lower fences to delimit possible outliers
197
+ * the average values as the dotted lines
198
+ """
199
+ elif trader_type == "Olas":
200
+ metric_text = """
201
+ ## Definition of Olas trader
202
+ Agents using Mech, with a service ID and the corresponding safe in the registry
203
+ ## Description of the graph
204
+ These metrics are computed weekly. The statistical measures are:
205
+ * min, max, 25th(q1), 50th(median) and 75th(q2) percentiles
206
+ * the upper and lower fences to delimit possible outliers
207
+ * the average values as the dotted lines
208
+ """
209
+ elif trader_type == "non_Olas":
210
+ metric_text = """
211
+ ## Definition of non-Olas trader
212
+ Agents using Mech, with no service ID
213
+ ## Description of the graph
214
+ These metrics are computed weekly. The statistical measures are:
215
+ * min, max, 25th(q1), 50th(median) and 75th(q2) percentiles
216
+ * the upper and lower fences to delimit possible outliers
217
+ * the average values as the dotted lines
218
+ """
219
+ else: # Unclassified
220
+ metric_text = """
221
+ ## Definition of unclassified trader
222
+ Agents (safe/EOAs) not using Mechs
223
+ ## Description of the graph
224
+ These metrics are computed weekly. The statistical measures are:
225
+ * min, max, 25th(q1), 50th(median) and 75th(q2) percentiles
226
+ * the upper and lower fences to delimit possible outliers
227
+ * the average values as the dotted lines
228
+ """
229
  return gr.Markdown(metric_text)