rosacastillo
commited on
Commit
·
285f2a6
1
Parent(s):
b3b7123
updating week format starting on Monday, new staking contracts and new weekly data
Browse files- data/all_trades_profitability.parquet +2 -2
- data/daily_info.parquet +2 -2
- data/error_by_markets.parquet +2 -2
- data/invalid_trades.parquet +2 -2
- data/service_map.pkl +2 -2
- data/service_map_bak.pkl +3 -0
- data/tools_accuracy.csv +2 -2
- data/unknown_traders.parquet +2 -2
- data/winning_df.parquet +2 -2
- notebooks/markets_analysis.ipynb +711 -15
- notebooks/weekly_analysis.ipynb +2 -2
- scripts/cleaning_old_info.py +14 -6
- scripts/cloud_storage.py +14 -5
- scripts/daily_data.py +4 -0
- scripts/get_mech_info.py +1 -1
- scripts/gnosis_timestamps.py +3 -1
- scripts/markets.py +14 -5
- scripts/profitability.py +79 -5
- scripts/pull_data.py +28 -6
- scripts/staking.py +97 -7
- scripts/tools_metrics.py +3 -1
- scripts/web3_utils.py +5 -2
- tabs/tool_win.py +3 -1
- tabs/trades.py +3 -1
data/all_trades_profitability.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6256840b7a7704aa5618fd5a4fed41b9444bbf80ea1dcaae068715026c8d52b0
|
3 |
+
size 8218375
|
data/daily_info.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f3d8ec77951dad3d522c90ea0009c15e5ab717c3f34624b4f0d205ad58cfa16e
|
3 |
+
size 1054780
|
data/error_by_markets.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:9dff09a27b7b5ac4a527d679c446627c6ca4fb2653c6bc50e818d79e29e3c1be
|
3 |
+
size 12928
|
data/invalid_trades.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:099e999dc46d4a2d7086838f3645475aecf27fa88331a8b2d5fd4c9937f1ad81
|
3 |
+
size 782151
|
data/service_map.pkl
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:32d288a076f719a659159ffdb2bca3f132c3efe3f62ee0412c11e8094c36ffc8
|
3 |
+
size 164076
|
data/service_map_bak.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:93ac540e1bcd347a48b9978b87443ae64af0f8b0a4daff305c4ad99cd0959a73
|
3 |
+
size 90766
|
data/tools_accuracy.csv
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:bb5a70b32e6a7dbd75c7924a2fa887612bf7523a62f6710f2e2397cdc3664fa2
|
3 |
+
size 1100
|
data/unknown_traders.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:1633afc5d408263251ae5290e1f45972abaf0d3f0358ab880604de8a0baae559
|
3 |
+
size 283140
|
data/winning_df.parquet
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f394838074669231dc3f8dc46167bb05019ae12eb798933e99b2c2de9b9a2c1f
|
3 |
+
size 12636
|
notebooks/markets_analysis.ipynb
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
-
"execution_count":
|
6 |
"metadata": {},
|
7 |
"outputs": [],
|
8 |
"source": [
|
@@ -15,32 +15,67 @@
|
|
15 |
},
|
16 |
{
|
17 |
"cell_type": "code",
|
18 |
-
"execution_count":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
"metadata": {},
|
20 |
"outputs": [
|
21 |
{
|
22 |
-
"
|
23 |
-
"
|
24 |
-
"
|
25 |
-
|
26 |
-
"\
|
27 |
-
"
|
28 |
-
"
|
29 |
-
"\
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
]
|
31 |
}
|
32 |
],
|
33 |
"source": [
|
34 |
-
"
|
35 |
]
|
36 |
},
|
37 |
{
|
38 |
"cell_type": "code",
|
39 |
-
"execution_count":
|
40 |
"metadata": {},
|
41 |
"outputs": [],
|
42 |
"source": [
|
43 |
-
"
|
44 |
]
|
45 |
},
|
46 |
{
|
@@ -54,7 +89,7 @@
|
|
54 |
},
|
55 |
{
|
56 |
"cell_type": "code",
|
57 |
-
"execution_count":
|
58 |
"metadata": {},
|
59 |
"outputs": [],
|
60 |
"source": [
|
@@ -72,13 +107,674 @@
|
|
72 |
},
|
73 |
{
|
74 |
"cell_type": "code",
|
75 |
-
"execution_count":
|
76 |
"metadata": {},
|
77 |
"outputs": [],
|
78 |
"source": [
|
79 |
"new_trades = pd.read_parquet(\"../tmp/new_fpmmTrades.parquet\")"
|
80 |
]
|
81 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
{
|
83 |
"cell_type": "code",
|
84 |
"execution_count": 9,
|
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
"metadata": {},
|
7 |
"outputs": [],
|
8 |
"source": [
|
|
|
15 |
},
|
16 |
{
|
17 |
"cell_type": "code",
|
18 |
+
"execution_count": 12,
|
19 |
+
"metadata": {},
|
20 |
+
"outputs": [],
|
21 |
+
"source": [
|
22 |
+
"missing_df = pd.read_parquet(\"../data/missing_fpmmTrades.parquet\")"
|
23 |
+
]
|
24 |
+
},
|
25 |
+
{
|
26 |
+
"cell_type": "code",
|
27 |
+
"execution_count": 13,
|
28 |
"metadata": {},
|
29 |
"outputs": [
|
30 |
{
|
31 |
+
"name": "stdout",
|
32 |
+
"output_type": "stream",
|
33 |
+
"text": [
|
34 |
+
"<class 'pandas.core.frame.DataFrame'>\n",
|
35 |
+
"RangeIndex: 24121 entries, 0 to 24120\n",
|
36 |
+
"Data columns (total 24 columns):\n",
|
37 |
+
" # Column Non-Null Count Dtype \n",
|
38 |
+
"--- ------ -------------- ----- \n",
|
39 |
+
" 0 collateralAmount 24121 non-null object\n",
|
40 |
+
" 1 collateralAmountUSD 24121 non-null object\n",
|
41 |
+
" 2 collateralToken 24121 non-null object\n",
|
42 |
+
" 3 creationTimestamp 24121 non-null object\n",
|
43 |
+
" 4 trader_address 24121 non-null object\n",
|
44 |
+
" 5 feeAmount 24121 non-null object\n",
|
45 |
+
" 6 id 24121 non-null object\n",
|
46 |
+
" 7 oldOutcomeTokenMarginalPrice 24121 non-null object\n",
|
47 |
+
" 8 outcomeIndex 24121 non-null object\n",
|
48 |
+
" 9 outcomeTokenMarginalPrice 24121 non-null object\n",
|
49 |
+
" 10 outcomeTokensTraded 24121 non-null object\n",
|
50 |
+
" 11 title 24121 non-null object\n",
|
51 |
+
" 12 transactionHash 24121 non-null object\n",
|
52 |
+
" 13 type 24121 non-null object\n",
|
53 |
+
" 14 market_creator 24121 non-null object\n",
|
54 |
+
" 15 fpmm.answerFinalizedTimestamp 22553 non-null object\n",
|
55 |
+
" 16 fpmm.arbitrationOccurred 24121 non-null bool \n",
|
56 |
+
" 17 fpmm.currentAnswer 22553 non-null object\n",
|
57 |
+
" 18 fpmm.id 24121 non-null object\n",
|
58 |
+
" 19 fpmm.isPendingArbitration 24121 non-null bool \n",
|
59 |
+
" 20 fpmm.openingTimestamp 24121 non-null object\n",
|
60 |
+
" 21 fpmm.outcomes 24121 non-null object\n",
|
61 |
+
" 22 fpmm.title 24121 non-null object\n",
|
62 |
+
" 23 fpmm.condition.id 24121 non-null object\n",
|
63 |
+
"dtypes: bool(2), object(22)\n",
|
64 |
+
"memory usage: 4.1+ MB\n"
|
65 |
]
|
66 |
}
|
67 |
],
|
68 |
"source": [
|
69 |
+
"missing_df.info()"
|
70 |
]
|
71 |
},
|
72 |
{
|
73 |
"cell_type": "code",
|
74 |
+
"execution_count": 26,
|
75 |
"metadata": {},
|
76 |
"outputs": [],
|
77 |
"source": [
|
78 |
+
"old_markets_df = pd.read_parquet(\"../data/old_fpmmTrades.parquet\")"
|
79 |
]
|
80 |
},
|
81 |
{
|
|
|
89 |
},
|
90 |
{
|
91 |
"cell_type": "code",
|
92 |
+
"execution_count": 35,
|
93 |
"metadata": {},
|
94 |
"outputs": [],
|
95 |
"source": [
|
|
|
107 |
},
|
108 |
{
|
109 |
"cell_type": "code",
|
110 |
+
"execution_count": 23,
|
111 |
"metadata": {},
|
112 |
"outputs": [],
|
113 |
"source": [
|
114 |
"new_trades = pd.read_parquet(\"../tmp/new_fpmmTrades.parquet\")"
|
115 |
]
|
116 |
},
|
117 |
+
{
|
118 |
+
"cell_type": "code",
|
119 |
+
"execution_count": 15,
|
120 |
+
"metadata": {},
|
121 |
+
"outputs": [
|
122 |
+
{
|
123 |
+
"data": {
|
124 |
+
"text/plain": [
|
125 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
126 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
127 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
128 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
129 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
130 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
131 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
132 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
133 |
+
" 'fpmm.condition.id'],\n",
|
134 |
+
" dtype='object')"
|
135 |
+
]
|
136 |
+
},
|
137 |
+
"execution_count": 15,
|
138 |
+
"metadata": {},
|
139 |
+
"output_type": "execute_result"
|
140 |
+
}
|
141 |
+
],
|
142 |
+
"source": [
|
143 |
+
"new_trades.columns"
|
144 |
+
]
|
145 |
+
},
|
146 |
+
{
|
147 |
+
"cell_type": "code",
|
148 |
+
"execution_count": 36,
|
149 |
+
"metadata": {},
|
150 |
+
"outputs": [],
|
151 |
+
"source": [
|
152 |
+
"from datetime import datetime, timezone\n",
|
153 |
+
"def transform_to_datetime(x):\n",
|
154 |
+
" return datetime.fromtimestamp(int(x), tz=timezone.utc)\n"
|
155 |
+
]
|
156 |
+
},
|
157 |
+
{
|
158 |
+
"cell_type": "code",
|
159 |
+
"execution_count": 17,
|
160 |
+
"metadata": {},
|
161 |
+
"outputs": [],
|
162 |
+
"source": [
|
163 |
+
"new_trades[\"creationTimestamp\"] = new_trades[\"creationTimestamp\"].apply(\n",
|
164 |
+
" lambda x: transform_to_datetime(x)\n",
|
165 |
+
")"
|
166 |
+
]
|
167 |
+
},
|
168 |
+
{
|
169 |
+
"cell_type": "code",
|
170 |
+
"execution_count": 37,
|
171 |
+
"metadata": {},
|
172 |
+
"outputs": [],
|
173 |
+
"source": [
|
174 |
+
"def add_creation_date(df):\n",
|
175 |
+
" try:\n",
|
176 |
+
" df[\"creationTimestamp\"] = df[\"creationTimestamp\"].apply(\n",
|
177 |
+
" lambda x: transform_to_datetime(x)\n",
|
178 |
+
" )\n",
|
179 |
+
" except Exception:\n",
|
180 |
+
" print(\"Ignore\")\n",
|
181 |
+
" df[\"creation_timestamp\"] = pd.to_datetime(df[\"creationTimestamp\"])\n",
|
182 |
+
" df[\"creation_date\"] = df[\"creation_timestamp\"].dt.date\n",
|
183 |
+
" df[\"creation_date\"] = pd.to_datetime(df[\"creation_date\"])\n",
|
184 |
+
" return df"
|
185 |
+
]
|
186 |
+
},
|
187 |
+
{
|
188 |
+
"cell_type": "code",
|
189 |
+
"execution_count": 27,
|
190 |
+
"metadata": {},
|
191 |
+
"outputs": [
|
192 |
+
{
|
193 |
+
"name": "stdout",
|
194 |
+
"output_type": "stream",
|
195 |
+
"text": [
|
196 |
+
"Ignore\n"
|
197 |
+
]
|
198 |
+
},
|
199 |
+
{
|
200 |
+
"data": {
|
201 |
+
"text/plain": [
|
202 |
+
"Timestamp('2025-01-14 00:00:00')"
|
203 |
+
]
|
204 |
+
},
|
205 |
+
"execution_count": 27,
|
206 |
+
"metadata": {},
|
207 |
+
"output_type": "execute_result"
|
208 |
+
}
|
209 |
+
],
|
210 |
+
"source": [
|
211 |
+
"old_markets_df = add_creation_date(old_markets_df)\n",
|
212 |
+
"max(old_markets_df.creation_date)"
|
213 |
+
]
|
214 |
+
},
|
215 |
+
{
|
216 |
+
"cell_type": "code",
|
217 |
+
"execution_count": 38,
|
218 |
+
"metadata": {},
|
219 |
+
"outputs": [
|
220 |
+
{
|
221 |
+
"name": "stdout",
|
222 |
+
"output_type": "stream",
|
223 |
+
"text": [
|
224 |
+
"Ignore\n"
|
225 |
+
]
|
226 |
+
},
|
227 |
+
{
|
228 |
+
"data": {
|
229 |
+
"text/plain": [
|
230 |
+
"Timestamp('2025-01-16 00:00:00')"
|
231 |
+
]
|
232 |
+
},
|
233 |
+
"execution_count": 38,
|
234 |
+
"metadata": {},
|
235 |
+
"output_type": "execute_result"
|
236 |
+
}
|
237 |
+
],
|
238 |
+
"source": [
|
239 |
+
"trades_data = add_creation_date(trades_data)\n",
|
240 |
+
"max(trades_data.creation_date)"
|
241 |
+
]
|
242 |
+
},
|
243 |
+
{
|
244 |
+
"cell_type": "code",
|
245 |
+
"execution_count": 39,
|
246 |
+
"metadata": {},
|
247 |
+
"outputs": [
|
248 |
+
{
|
249 |
+
"data": {
|
250 |
+
"text/plain": [
|
251 |
+
"Timestamp('2024-11-14 00:00:00')"
|
252 |
+
]
|
253 |
+
},
|
254 |
+
"execution_count": 39,
|
255 |
+
"metadata": {},
|
256 |
+
"output_type": "execute_result"
|
257 |
+
}
|
258 |
+
],
|
259 |
+
"source": [
|
260 |
+
"min(trades_data.creation_date)"
|
261 |
+
]
|
262 |
+
},
|
263 |
+
{
|
264 |
+
"cell_type": "code",
|
265 |
+
"execution_count": 24,
|
266 |
+
"metadata": {},
|
267 |
+
"outputs": [
|
268 |
+
{
|
269 |
+
"data": {
|
270 |
+
"text/plain": [
|
271 |
+
"Timestamp('2025-01-14 00:00:00')"
|
272 |
+
]
|
273 |
+
},
|
274 |
+
"execution_count": 24,
|
275 |
+
"metadata": {},
|
276 |
+
"output_type": "execute_result"
|
277 |
+
}
|
278 |
+
],
|
279 |
+
"source": [
|
280 |
+
"new_trades = add_creation_date(new_trades)\n",
|
281 |
+
"max(new_trades.creation_date)"
|
282 |
+
]
|
283 |
+
},
|
284 |
+
{
|
285 |
+
"cell_type": "code",
|
286 |
+
"execution_count": 25,
|
287 |
+
"metadata": {},
|
288 |
+
"outputs": [
|
289 |
+
{
|
290 |
+
"data": {
|
291 |
+
"text/plain": [
|
292 |
+
"Timestamp('2025-01-11 00:00:00')"
|
293 |
+
]
|
294 |
+
},
|
295 |
+
"execution_count": 25,
|
296 |
+
"metadata": {},
|
297 |
+
"output_type": "execute_result"
|
298 |
+
}
|
299 |
+
],
|
300 |
+
"source": [
|
301 |
+
"min(new_trades.creation_date)"
|
302 |
+
]
|
303 |
+
},
|
304 |
+
{
|
305 |
+
"cell_type": "code",
|
306 |
+
"execution_count": 28,
|
307 |
+
"metadata": {},
|
308 |
+
"outputs": [
|
309 |
+
{
|
310 |
+
"name": "stdout",
|
311 |
+
"output_type": "stream",
|
312 |
+
"text": [
|
313 |
+
"Transformation not needed\n",
|
314 |
+
"Transformation not needed\n",
|
315 |
+
"Initial length before removing duplicates in fpmmTrades= 165530\n"
|
316 |
+
]
|
317 |
+
}
|
318 |
+
],
|
319 |
+
"source": [
|
320 |
+
"# lowercase and strip creator_address\n",
|
321 |
+
"new_trades[\"trader_address\"] = (\n",
|
322 |
+
" new_trades[\"trader_address\"].str.lower().str.strip()\n",
|
323 |
+
")\n",
|
324 |
+
"# ensure creationTimestamp compatibility\n",
|
325 |
+
"try:\n",
|
326 |
+
" new_trades[\"creationTimestamp\"] = new_trades[\"creationTimestamp\"].apply(\n",
|
327 |
+
" lambda x: transform_to_datetime(x)\n",
|
328 |
+
" )\n",
|
329 |
+
"\n",
|
330 |
+
"except Exception as e:\n",
|
331 |
+
" print(f\"Transformation not needed\")\n",
|
332 |
+
"try:\n",
|
333 |
+
" old_markets_df[\"creationTimestamp\"] = old_markets_df[\"creationTimestamp\"].apply(\n",
|
334 |
+
" lambda x: transform_to_datetime(x)\n",
|
335 |
+
" )\n",
|
336 |
+
"except Exception as e:\n",
|
337 |
+
" print(f\"Transformation not needed\")\n",
|
338 |
+
"\n",
|
339 |
+
"# merge two dataframes\n",
|
340 |
+
"merge_df = pd.concat([old_markets_df, new_trades], ignore_index=True)\n",
|
341 |
+
"# avoid numpy objects\n",
|
342 |
+
"merge_df[\"fpmm.arbitrationOccurred\"] = merge_df[\"fpmm.arbitrationOccurred\"].astype(\n",
|
343 |
+
" bool\n",
|
344 |
+
")\n",
|
345 |
+
"merge_df[\"fpmm.isPendingArbitration\"] = merge_df[\n",
|
346 |
+
" \"fpmm.isPendingArbitration\"\n",
|
347 |
+
"].astype(bool)\n",
|
348 |
+
"\n",
|
349 |
+
"# Check for duplicates\n",
|
350 |
+
"print(f\"Initial length before removing duplicates in fpmmTrades= {len(merge_df)}\")\n",
|
351 |
+
"\n",
|
352 |
+
"# Remove duplicates\n",
|
353 |
+
"# fpmm.outcomes is a numpy array\n",
|
354 |
+
"merge_df.drop_duplicates(\"id\", keep=\"last\", inplace=True)"
|
355 |
+
]
|
356 |
+
},
|
357 |
+
{
|
358 |
+
"cell_type": "code",
|
359 |
+
"execution_count": 29,
|
360 |
+
"metadata": {},
|
361 |
+
"outputs": [
|
362 |
+
{
|
363 |
+
"data": {
|
364 |
+
"text/plain": [
|
365 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
366 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
367 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
368 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
369 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
370 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
371 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
372 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
373 |
+
" 'fpmm.condition.id', 'creation_timestamp', 'creation_date'],\n",
|
374 |
+
" dtype='object')"
|
375 |
+
]
|
376 |
+
},
|
377 |
+
"execution_count": 29,
|
378 |
+
"metadata": {},
|
379 |
+
"output_type": "execute_result"
|
380 |
+
}
|
381 |
+
],
|
382 |
+
"source": [
|
383 |
+
"merge_df.columns"
|
384 |
+
]
|
385 |
+
},
|
386 |
+
{
|
387 |
+
"cell_type": "code",
|
388 |
+
"execution_count": 30,
|
389 |
+
"metadata": {},
|
390 |
+
"outputs": [
|
391 |
+
{
|
392 |
+
"data": {
|
393 |
+
"text/plain": [
|
394 |
+
"Timestamp('2025-01-14 00:00:00')"
|
395 |
+
]
|
396 |
+
},
|
397 |
+
"execution_count": 30,
|
398 |
+
"metadata": {},
|
399 |
+
"output_type": "execute_result"
|
400 |
+
}
|
401 |
+
],
|
402 |
+
"source": [
|
403 |
+
"max(merge_df.creation_date)"
|
404 |
+
]
|
405 |
+
},
|
406 |
+
{
|
407 |
+
"cell_type": "code",
|
408 |
+
"execution_count": 31,
|
409 |
+
"metadata": {},
|
410 |
+
"outputs": [],
|
411 |
+
"source": [
|
412 |
+
"cutoff_date=\"2024-11-13\"\n",
|
413 |
+
"min_date_utc = pd.to_datetime(cutoff_date, format=\"%Y-%m-%d\", utc=True)"
|
414 |
+
]
|
415 |
+
},
|
416 |
+
{
|
417 |
+
"cell_type": "code",
|
418 |
+
"execution_count": 32,
|
419 |
+
"metadata": {},
|
420 |
+
"outputs": [
|
421 |
+
{
|
422 |
+
"name": "stdout",
|
423 |
+
"output_type": "stream",
|
424 |
+
"text": [
|
425 |
+
"length before filtering 161781\n",
|
426 |
+
"length after filtering 160426\n"
|
427 |
+
]
|
428 |
+
}
|
429 |
+
],
|
430 |
+
"source": [
|
431 |
+
"merge_df[\"creation_timestamp\"] = pd.to_datetime(\n",
|
432 |
+
" merge_df[\"creation_timestamp\"], utc=True\n",
|
433 |
+
")\n",
|
434 |
+
"\n",
|
435 |
+
"print(f\"length before filtering {len(merge_df)}\")\n",
|
436 |
+
"merge_df = merge_df.loc[merge_df[\"creation_timestamp\"] > min_date_utc]\n",
|
437 |
+
"print(f\"length after filtering {len(merge_df)}\")\n"
|
438 |
+
]
|
439 |
+
},
|
440 |
+
{
|
441 |
+
"cell_type": "code",
|
442 |
+
"execution_count": 33,
|
443 |
+
"metadata": {},
|
444 |
+
"outputs": [
|
445 |
+
{
|
446 |
+
"data": {
|
447 |
+
"text/plain": [
|
448 |
+
"Timestamp('2025-01-14 00:00:00')"
|
449 |
+
]
|
450 |
+
},
|
451 |
+
"execution_count": 33,
|
452 |
+
"metadata": {},
|
453 |
+
"output_type": "execute_result"
|
454 |
+
}
|
455 |
+
],
|
456 |
+
"source": [
|
457 |
+
"max(merge_df.creation_date)"
|
458 |
+
]
|
459 |
+
},
|
460 |
+
{
|
461 |
+
"cell_type": "code",
|
462 |
+
"execution_count": 34,
|
463 |
+
"metadata": {},
|
464 |
+
"outputs": [],
|
465 |
+
"source": [
|
466 |
+
"merge_df.to_parquet(\"../tmp/fpmmTrades.parquet\", index=False)"
|
467 |
+
]
|
468 |
+
},
|
469 |
+
{
|
470 |
+
"cell_type": "code",
|
471 |
+
"execution_count": 15,
|
472 |
+
"metadata": {},
|
473 |
+
"outputs": [
|
474 |
+
{
|
475 |
+
"data": {
|
476 |
+
"text/plain": [
|
477 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
478 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
479 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
480 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
481 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
482 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
483 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
484 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
485 |
+
" 'fpmm.condition.id', 'creation_timestamp', 'creation_date'],\n",
|
486 |
+
" dtype='object')"
|
487 |
+
]
|
488 |
+
},
|
489 |
+
"execution_count": 15,
|
490 |
+
"metadata": {},
|
491 |
+
"output_type": "execute_result"
|
492 |
+
}
|
493 |
+
],
|
494 |
+
"source": [
|
495 |
+
"missing_df = add_creation_date(missing_df)\n",
|
496 |
+
"missing_df.columns"
|
497 |
+
]
|
498 |
+
},
|
499 |
+
{
|
500 |
+
"cell_type": "code",
|
501 |
+
"execution_count": 16,
|
502 |
+
"metadata": {},
|
503 |
+
"outputs": [
|
504 |
+
{
|
505 |
+
"data": {
|
506 |
+
"text/plain": [
|
507 |
+
"<Axes: xlabel='Count', ylabel='creation_date'>"
|
508 |
+
]
|
509 |
+
},
|
510 |
+
"execution_count": 16,
|
511 |
+
"metadata": {},
|
512 |
+
"output_type": "execute_result"
|
513 |
+
},
|
514 |
+
{
|
515 |
+
"data": {
|
516 |
+
"image/png": "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",
|
517 |
+
"text/plain": [
|
518 |
+
"<Figure size 640x480 with 1 Axes>"
|
519 |
+
]
|
520 |
+
},
|
521 |
+
"metadata": {},
|
522 |
+
"output_type": "display_data"
|
523 |
+
}
|
524 |
+
],
|
525 |
+
"source": [
|
526 |
+
"import seaborn as sns\n",
|
527 |
+
"\n",
|
528 |
+
"sns.histplot(missing_df, y=\"creation_date\")"
|
529 |
+
]
|
530 |
+
},
|
531 |
+
{
|
532 |
+
"cell_type": "code",
|
533 |
+
"execution_count": 40,
|
534 |
+
"metadata": {},
|
535 |
+
"outputs": [
|
536 |
+
{
|
537 |
+
"data": {
|
538 |
+
"text/plain": [
|
539 |
+
"<Axes: xlabel='Count', ylabel='creation_date'>"
|
540 |
+
]
|
541 |
+
},
|
542 |
+
"execution_count": 40,
|
543 |
+
"metadata": {},
|
544 |
+
"output_type": "execute_result"
|
545 |
+
},
|
546 |
+
{
|
547 |
+
"data": {
|
548 |
+
"image/png": "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",
|
549 |
+
"text/plain": [
|
550 |
+
"<Figure size 640x480 with 1 Axes>"
|
551 |
+
]
|
552 |
+
},
|
553 |
+
"metadata": {},
|
554 |
+
"output_type": "display_data"
|
555 |
+
}
|
556 |
+
],
|
557 |
+
"source": [
|
558 |
+
"sns.histplot(trades_data, y=\"creation_date\")"
|
559 |
+
]
|
560 |
+
},
|
561 |
+
{
|
562 |
+
"cell_type": "code",
|
563 |
+
"execution_count": 19,
|
564 |
+
"metadata": {},
|
565 |
+
"outputs": [],
|
566 |
+
"source": [
|
567 |
+
"def add_extra_columns(new_trades):\n",
|
568 |
+
" new_trades[\"creation_timestamp\"] = pd.to_datetime(new_trades[\"creationTimestamp\"])\n",
|
569 |
+
" new_trades[\"creation_date\"] = new_trades[\"creation_timestamp\"].dt.date\n",
|
570 |
+
" new_trades[\"creation_date\"] = pd.to_datetime(new_trades[\"creation_date\"])"
|
571 |
+
]
|
572 |
+
},
|
573 |
+
{
|
574 |
+
"cell_type": "code",
|
575 |
+
"execution_count": null,
|
576 |
+
"metadata": {},
|
577 |
+
"outputs": [],
|
578 |
+
"source": [
|
579 |
+
"add_extra_columns(new_trades=new_trades)"
|
580 |
+
]
|
581 |
+
},
|
582 |
+
{
|
583 |
+
"cell_type": "code",
|
584 |
+
"execution_count": 9,
|
585 |
+
"metadata": {},
|
586 |
+
"outputs": [
|
587 |
+
{
|
588 |
+
"data": {
|
589 |
+
"text/plain": [
|
590 |
+
"Timestamp('2025-01-13 00:00:00')"
|
591 |
+
]
|
592 |
+
},
|
593 |
+
"execution_count": 9,
|
594 |
+
"metadata": {},
|
595 |
+
"output_type": "execute_result"
|
596 |
+
}
|
597 |
+
],
|
598 |
+
"source": [
|
599 |
+
"max(new_trades.creation_date)"
|
600 |
+
]
|
601 |
+
},
|
602 |
+
{
|
603 |
+
"cell_type": "code",
|
604 |
+
"execution_count": 12,
|
605 |
+
"metadata": {},
|
606 |
+
"outputs": [
|
607 |
+
{
|
608 |
+
"data": {
|
609 |
+
"text/plain": [
|
610 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
611 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
612 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
613 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
614 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
615 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
616 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
617 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
618 |
+
" 'fpmm.condition.id', 'creation_timestamp', 'creation_date'],\n",
|
619 |
+
" dtype='object')"
|
620 |
+
]
|
621 |
+
},
|
622 |
+
"execution_count": 12,
|
623 |
+
"metadata": {},
|
624 |
+
"output_type": "execute_result"
|
625 |
+
}
|
626 |
+
],
|
627 |
+
"source": [
|
628 |
+
"new_trades.columns"
|
629 |
+
]
|
630 |
+
},
|
631 |
+
{
|
632 |
+
"cell_type": "code",
|
633 |
+
"execution_count": 23,
|
634 |
+
"metadata": {},
|
635 |
+
"outputs": [
|
636 |
+
{
|
637 |
+
"name": "stdout",
|
638 |
+
"output_type": "stream",
|
639 |
+
"text": [
|
640 |
+
"Transformation not needed\n",
|
641 |
+
"Initial length before removing duplicates in fpmmTrades= 137851\n",
|
642 |
+
"Final length after removing duplicates in fpmmTrades= 137851\n"
|
643 |
+
]
|
644 |
+
}
|
645 |
+
],
|
646 |
+
"source": [
|
647 |
+
"old_trades_df = pd.read_parquet(\"../tmp/fpmmTrades.parquet\")\n",
|
648 |
+
"\n",
|
649 |
+
"\n",
|
650 |
+
"# lowercase and strip creator_address\n",
|
651 |
+
"new_trades[\"trader_address\"] = (\n",
|
652 |
+
" new_trades[\"trader_address\"].str.lower().str.strip()\n",
|
653 |
+
")\n",
|
654 |
+
"\n",
|
655 |
+
"\n",
|
656 |
+
"try:\n",
|
657 |
+
" old_trades_df[\"creationTimestamp\"] = old_trades_df[\"creationTimestamp\"].apply(\n",
|
658 |
+
" lambda x: transform_to_datetime(x)\n",
|
659 |
+
" )\n",
|
660 |
+
"except Exception as e:\n",
|
661 |
+
" print(f\"Transformation not needed\")\n",
|
662 |
+
"\n",
|
663 |
+
"# merge two dataframes\n",
|
664 |
+
"merge_df = pd.concat([old_trades_df, new_trades], ignore_index=True)\n",
|
665 |
+
"# avoid numpy objects\n",
|
666 |
+
"merge_df[\"fpmm.arbitrationOccurred\"] = merge_df[\"fpmm.arbitrationOccurred\"].astype(\n",
|
667 |
+
" bool\n",
|
668 |
+
")\n",
|
669 |
+
"merge_df[\"fpmm.isPendingArbitration\"] = merge_df[\n",
|
670 |
+
" \"fpmm.isPendingArbitration\"\n",
|
671 |
+
"].astype(bool)\n",
|
672 |
+
"\n",
|
673 |
+
"# Check for duplicates\n",
|
674 |
+
"print(f\"Initial length before removing duplicates in fpmmTrades= {len(merge_df)}\")\n",
|
675 |
+
"\n",
|
676 |
+
"# Remove duplicates\n",
|
677 |
+
"# fpmm.outcomes is a numpy array\n",
|
678 |
+
"merge_df.drop_duplicates(\"id\", keep=\"last\", inplace=True)\n",
|
679 |
+
"print(f\"Final length after removing duplicates in fpmmTrades= {len(merge_df)}\")"
|
680 |
+
]
|
681 |
+
},
|
682 |
+
{
|
683 |
+
"cell_type": "code",
|
684 |
+
"execution_count": 24,
|
685 |
+
"metadata": {},
|
686 |
+
"outputs": [],
|
687 |
+
"source": [
|
688 |
+
"merge_df.to_parquet(\"../tmp/fpmmTrades.parquet\", index=False)"
|
689 |
+
]
|
690 |
+
},
|
691 |
+
{
|
692 |
+
"cell_type": "code",
|
693 |
+
"execution_count": 13,
|
694 |
+
"metadata": {},
|
695 |
+
"outputs": [
|
696 |
+
{
|
697 |
+
"data": {
|
698 |
+
"text/plain": [
|
699 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
700 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
701 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
702 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
703 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
704 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
705 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
706 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
707 |
+
" 'fpmm.condition.id', 'creation_timestamp', 'creation_date'],\n",
|
708 |
+
" dtype='object')"
|
709 |
+
]
|
710 |
+
},
|
711 |
+
"execution_count": 13,
|
712 |
+
"metadata": {},
|
713 |
+
"output_type": "execute_result"
|
714 |
+
}
|
715 |
+
],
|
716 |
+
"source": [
|
717 |
+
"old_trades_df.columns"
|
718 |
+
]
|
719 |
+
},
|
720 |
+
{
|
721 |
+
"cell_type": "code",
|
722 |
+
"execution_count": 20,
|
723 |
+
"metadata": {},
|
724 |
+
"outputs": [],
|
725 |
+
"source": [
|
726 |
+
"add_extra_columns(new_trades=merge_df)"
|
727 |
+
]
|
728 |
+
},
|
729 |
+
{
|
730 |
+
"cell_type": "code",
|
731 |
+
"execution_count": 21,
|
732 |
+
"metadata": {},
|
733 |
+
"outputs": [
|
734 |
+
{
|
735 |
+
"data": {
|
736 |
+
"text/plain": [
|
737 |
+
"Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n",
|
738 |
+
" 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n",
|
739 |
+
" 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n",
|
740 |
+
" 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n",
|
741 |
+
" 'transactionHash', 'type', 'market_creator',\n",
|
742 |
+
" 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n",
|
743 |
+
" 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n",
|
744 |
+
" 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n",
|
745 |
+
" 'fpmm.condition.id', 'creation_timestamp', 'creation_date'],\n",
|
746 |
+
" dtype='object')"
|
747 |
+
]
|
748 |
+
},
|
749 |
+
"execution_count": 21,
|
750 |
+
"metadata": {},
|
751 |
+
"output_type": "execute_result"
|
752 |
+
}
|
753 |
+
],
|
754 |
+
"source": [
|
755 |
+
"merge_df.columns"
|
756 |
+
]
|
757 |
+
},
|
758 |
+
{
|
759 |
+
"cell_type": "code",
|
760 |
+
"execution_count": 22,
|
761 |
+
"metadata": {},
|
762 |
+
"outputs": [
|
763 |
+
{
|
764 |
+
"data": {
|
765 |
+
"text/plain": [
|
766 |
+
"Timestamp('2025-01-13 00:00:00')"
|
767 |
+
]
|
768 |
+
},
|
769 |
+
"execution_count": 22,
|
770 |
+
"metadata": {},
|
771 |
+
"output_type": "execute_result"
|
772 |
+
}
|
773 |
+
],
|
774 |
+
"source": [
|
775 |
+
"max(merge_df.creation_date)"
|
776 |
+
]
|
777 |
+
},
|
778 |
{
|
779 |
"cell_type": "code",
|
780 |
"execution_count": 9,
|
notebooks/weekly_analysis.ipynb
CHANGED
@@ -4676,7 +4676,7 @@
|
|
4676 |
],
|
4677 |
"metadata": {
|
4678 |
"kernelspec": {
|
4679 |
-
"display_name": "
|
4680 |
"language": "python",
|
4681 |
"name": "python3"
|
4682 |
},
|
@@ -4690,7 +4690,7 @@
|
|
4690 |
"name": "python",
|
4691 |
"nbconvert_exporter": "python",
|
4692 |
"pygments_lexer": "ipython3",
|
4693 |
-
"version": "3.12.
|
4694 |
},
|
4695 |
"orig_nbformat": 4
|
4696 |
},
|
|
|
4676 |
],
|
4677 |
"metadata": {
|
4678 |
"kernelspec": {
|
4679 |
+
"display_name": "Python 3",
|
4680 |
"language": "python",
|
4681 |
"name": "python3"
|
4682 |
},
|
|
|
4690 |
"name": "python",
|
4691 |
"nbconvert_exporter": "python",
|
4692 |
"pygments_lexer": "ipython3",
|
4693 |
+
"version": "3.12.3"
|
4694 |
},
|
4695 |
"orig_nbformat": 4
|
4696 |
},
|
scripts/cleaning_old_info.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import pandas as pd
|
2 |
-
from utils import DATA_DIR, TMP_DIR
|
3 |
|
4 |
|
5 |
def clean_old_data_from_parquet_files(cutoff_date: str):
|
@@ -9,7 +9,7 @@ def clean_old_data_from_parquet_files(cutoff_date: str):
|
|
9 |
|
10 |
# clean tools.parquet
|
11 |
try:
|
12 |
-
tools = pd.read_parquet(
|
13 |
|
14 |
# make sure creator_address is in the columns
|
15 |
assert "trader_address" in tools.columns, "trader_address column not found"
|
@@ -22,7 +22,7 @@ def clean_old_data_from_parquet_files(cutoff_date: str):
|
|
22 |
print(f"length before filtering {len(tools)}")
|
23 |
tools = tools.loc[tools["request_time"] > min_date_utc]
|
24 |
print(f"length after filtering {len(tools)}")
|
25 |
-
tools.to_parquet(
|
26 |
|
27 |
except Exception as e:
|
28 |
print(f"Error cleaning tools file {e}")
|
@@ -53,11 +53,11 @@ def clean_old_data_from_parquet_files(cutoff_date: str):
|
|
53 |
unknown_traders["creation_timestamp"], utc=True
|
54 |
)
|
55 |
|
56 |
-
print(f"length before filtering {len(unknown_traders)}")
|
57 |
unknown_traders = unknown_traders.loc[
|
58 |
unknown_traders["creation_timestamp"] > min_date_utc
|
59 |
]
|
60 |
-
print(f"length after filtering {len(unknown_traders)}")
|
61 |
unknown_traders.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
62 |
|
63 |
except Exception as e:
|
@@ -66,7 +66,15 @@ def clean_old_data_from_parquet_files(cutoff_date: str):
|
|
66 |
# clean fpmmTrades.parquet
|
67 |
try:
|
68 |
fpmmTrades = pd.read_parquet(TMP_DIR / "fpmmTrades.parquet")
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
fpmmTrades["creation_timestamp"] = pd.to_datetime(
|
71 |
fpmmTrades["creation_timestamp"], utc=True
|
72 |
)
|
|
|
1 |
import pandas as pd
|
2 |
+
from utils import DATA_DIR, TMP_DIR, transform_to_datetime
|
3 |
|
4 |
|
5 |
def clean_old_data_from_parquet_files(cutoff_date: str):
|
|
|
9 |
|
10 |
# clean tools.parquet
|
11 |
try:
|
12 |
+
tools = pd.read_parquet(TMP_DIR / "tools.parquet")
|
13 |
|
14 |
# make sure creator_address is in the columns
|
15 |
assert "trader_address" in tools.columns, "trader_address column not found"
|
|
|
22 |
print(f"length before filtering {len(tools)}")
|
23 |
tools = tools.loc[tools["request_time"] > min_date_utc]
|
24 |
print(f"length after filtering {len(tools)}")
|
25 |
+
tools.to_parquet(TMP_DIR / "tools.parquet", index=False)
|
26 |
|
27 |
except Exception as e:
|
28 |
print(f"Error cleaning tools file {e}")
|
|
|
53 |
unknown_traders["creation_timestamp"], utc=True
|
54 |
)
|
55 |
|
56 |
+
print(f"length unknown traders before filtering {len(unknown_traders)}")
|
57 |
unknown_traders = unknown_traders.loc[
|
58 |
unknown_traders["creation_timestamp"] > min_date_utc
|
59 |
]
|
60 |
+
print(f"length unknown traders after filtering {len(unknown_traders)}")
|
61 |
unknown_traders.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
62 |
|
63 |
except Exception as e:
|
|
|
66 |
# clean fpmmTrades.parquet
|
67 |
try:
|
68 |
fpmmTrades = pd.read_parquet(TMP_DIR / "fpmmTrades.parquet")
|
69 |
+
try:
|
70 |
+
fpmmTrades["creationTimestamp"] = fpmmTrades["creationTimestamp"].apply(
|
71 |
+
lambda x: transform_to_datetime(x)
|
72 |
+
)
|
73 |
+
except Exception as e:
|
74 |
+
print(f"Transformation not needed")
|
75 |
+
fpmmTrades["creation_timestamp"] = pd.to_datetime(
|
76 |
+
fpmmTrades["creationTimestamp"]
|
77 |
+
)
|
78 |
fpmmTrades["creation_timestamp"] = pd.to_datetime(
|
79 |
fpmmTrades["creation_timestamp"], utc=True
|
80 |
)
|
scripts/cloud_storage.py
CHANGED
@@ -23,7 +23,7 @@ def initialize_client():
|
|
23 |
return client
|
24 |
|
25 |
|
26 |
-
def upload_file(client, filename: str, file_path: str):
|
27 |
"""Upload a file to the bucket"""
|
28 |
try:
|
29 |
OBJECT_NAME = FOLDER_NAME + "/" + filename
|
@@ -34,8 +34,10 @@ def upload_file(client, filename: str, file_path: str):
|
|
34 |
BUCKET_NAME, OBJECT_NAME, file_path, part_size=10 * 1024 * 1024
|
35 |
) # 10MB parts
|
36 |
print(f"File '{file_path}' uploaded as '{OBJECT_NAME}'.")
|
|
|
37 |
except S3Error as err:
|
38 |
print(f"Error uploading file: {err}")
|
|
|
39 |
|
40 |
|
41 |
def download_file(client, filename: str, file_path: str):
|
@@ -48,11 +50,16 @@ def download_file(client, filename: str, file_path: str):
|
|
48 |
print(f"Error downloading file: {err}")
|
49 |
|
50 |
|
51 |
-
def load_historical_file(client, filename: str):
|
52 |
"""Function to load one file into the cloud storage"""
|
53 |
file_path = filename
|
54 |
file_path = HIST_DIR / filename
|
55 |
-
upload_file(client, filename, file_path)
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
|
58 |
def process_historical_files(client):
|
@@ -63,8 +70,10 @@ def process_historical_files(client):
|
|
63 |
# Check if file is a parquet file
|
64 |
if filename.endswith(".parquet"):
|
65 |
try:
|
66 |
-
load_historical_file(client, filename)
|
67 |
-
|
|
|
|
|
68 |
except Exception as e:
|
69 |
print(f"Error processing {filename}: {str(e)}")
|
70 |
|
|
|
23 |
return client
|
24 |
|
25 |
|
26 |
+
def upload_file(client, filename: str, file_path: str) -> bool:
|
27 |
"""Upload a file to the bucket"""
|
28 |
try:
|
29 |
OBJECT_NAME = FOLDER_NAME + "/" + filename
|
|
|
34 |
BUCKET_NAME, OBJECT_NAME, file_path, part_size=10 * 1024 * 1024
|
35 |
) # 10MB parts
|
36 |
print(f"File '{file_path}' uploaded as '{OBJECT_NAME}'.")
|
37 |
+
return True
|
38 |
except S3Error as err:
|
39 |
print(f"Error uploading file: {err}")
|
40 |
+
return False
|
41 |
|
42 |
|
43 |
def download_file(client, filename: str, file_path: str):
|
|
|
50 |
print(f"Error downloading file: {err}")
|
51 |
|
52 |
|
53 |
+
def load_historical_file(client, filename: str) -> bool:
|
54 |
"""Function to load one file into the cloud storage"""
|
55 |
file_path = filename
|
56 |
file_path = HIST_DIR / filename
|
57 |
+
return upload_file(client, filename, file_path)
|
58 |
+
|
59 |
+
|
60 |
+
def upload_historical_file(filename: str):
|
61 |
+
client = initialize_client()
|
62 |
+
load_historical_file(client=client, filename=filename)
|
63 |
|
64 |
|
65 |
def process_historical_files(client):
|
|
|
70 |
# Check if file is a parquet file
|
71 |
if filename.endswith(".parquet"):
|
72 |
try:
|
73 |
+
if load_historical_file(client, filename):
|
74 |
+
print(f"Successfully processed {filename}")
|
75 |
+
else:
|
76 |
+
print("Error loading the files")
|
77 |
except Exception as e:
|
78 |
print(f"Error processing {filename}: {str(e)}")
|
79 |
|
scripts/daily_data.py
CHANGED
@@ -11,6 +11,7 @@ from nr_mech_calls import (
|
|
11 |
transform_to_datetime,
|
12 |
)
|
13 |
from markets import check_current_week_data
|
|
|
14 |
|
15 |
logging.basicConfig(level=logging.INFO)
|
16 |
|
@@ -51,6 +52,9 @@ def prepare_live_metrics(
|
|
51 |
# save into a separate file
|
52 |
all_trades_df.to_parquet(DATA_DIR / "daily_info.parquet", index=False)
|
53 |
|
|
|
|
|
|
|
54 |
|
55 |
if __name__ == "__main__":
|
56 |
prepare_live_metrics()
|
|
|
11 |
transform_to_datetime,
|
12 |
)
|
13 |
from markets import check_current_week_data
|
14 |
+
from staking import generate_retention_activity_file
|
15 |
|
16 |
logging.basicConfig(level=logging.INFO)
|
17 |
|
|
|
52 |
# save into a separate file
|
53 |
all_trades_df.to_parquet(DATA_DIR / "daily_info.parquet", index=False)
|
54 |
|
55 |
+
# prepare the retention info file
|
56 |
+
generate_retention_activity_file()
|
57 |
+
|
58 |
|
59 |
if __name__ == "__main__":
|
60 |
prepare_live_metrics()
|
scripts/get_mech_info.py
CHANGED
@@ -316,7 +316,7 @@ def get_mech_events_since_last_run(logger):
|
|
316 |
try:
|
317 |
all_trades = pd.read_parquet(DATA_DIR / "all_trades_profitability.parquet")
|
318 |
latest_timestamp = max(all_trades.creation_timestamp)
|
319 |
-
# cutoff_date = "2024-12-
|
320 |
# latest_timestamp = pd.Timestamp(
|
321 |
# datetime.strptime(cutoff_date, "%Y-%m-%d")
|
322 |
# ).tz_localize("UTC")
|
|
|
316 |
try:
|
317 |
all_trades = pd.read_parquet(DATA_DIR / "all_trades_profitability.parquet")
|
318 |
latest_timestamp = max(all_trades.creation_timestamp)
|
319 |
+
# cutoff_date = "2024-12-22"
|
320 |
# latest_timestamp = pd.Timestamp(
|
321 |
# datetime.strptime(cutoff_date, "%Y-%m-%d")
|
322 |
# ).tz_localize("UTC")
|
scripts/gnosis_timestamps.py
CHANGED
@@ -137,7 +137,9 @@ def compute_request_time(tools_df: pd.DataFrame) -> pd.DataFrame:
|
|
137 |
tools_df["request_time"]
|
138 |
).dt.strftime("%Y-%m")
|
139 |
tools_df["request_month_year_week"] = (
|
140 |
-
pd.to_datetime(tools_df["request_time"])
|
|
|
|
|
141 |
)
|
142 |
# Update t_map with new timestamps
|
143 |
new_timestamps = (
|
|
|
137 |
tools_df["request_time"]
|
138 |
).dt.strftime("%Y-%m")
|
139 |
tools_df["request_month_year_week"] = (
|
140 |
+
pd.to_datetime(tools_df["request_time"])
|
141 |
+
.dt.to_period("W")
|
142 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
143 |
)
|
144 |
# Update t_map with new timestamps
|
145 |
new_timestamps = (
|
scripts/markets.py
CHANGED
@@ -156,15 +156,19 @@ def transform_fpmmTrades(df: pd.DataFrame) -> pd.DataFrame:
|
|
156 |
return df
|
157 |
|
158 |
|
159 |
-
def create_fpmmTrades(
|
|
|
|
|
|
|
160 |
"""Create fpmmTrades for all trades."""
|
|
|
161 |
# Quickstart trades
|
162 |
qs_trades_json = query_omen_xdai_subgraph(
|
163 |
trader_category="quickstart",
|
164 |
from_timestamp=from_timestamp,
|
165 |
-
to_timestamp=
|
166 |
fpmm_from_timestamp=from_timestamp,
|
167 |
-
fpmm_to_timestamp=
|
168 |
)
|
169 |
|
170 |
print(f"length of the qs_trades_json dataset {len(qs_trades_json)}")
|
@@ -175,6 +179,7 @@ def create_fpmmTrades(rpc: str, from_timestamp: float = DEFAULT_FROM_TIMESTAMP):
|
|
175 |
qs_df = transform_fpmmTrades(qs_df)
|
176 |
|
177 |
# Pearl trades
|
|
|
178 |
pearl_trades_json = query_omen_xdai_subgraph(
|
179 |
trader_category="pearl",
|
180 |
from_timestamp=from_timestamp,
|
@@ -335,10 +340,14 @@ def add_market_creator(tools: pd.DataFrame) -> None:
|
|
335 |
return tools
|
336 |
|
337 |
|
338 |
-
def fpmmTrades_etl(
|
|
|
|
|
339 |
print("Generating the trades file")
|
340 |
try:
|
341 |
-
fpmmTrades = create_fpmmTrades(
|
|
|
|
|
342 |
except FileNotFoundError:
|
343 |
print(f"Error creating {trades_filename} file .")
|
344 |
|
|
|
156 |
return df
|
157 |
|
158 |
|
159 |
+
def create_fpmmTrades(
|
160 |
+
from_timestamp: int = DEFAULT_FROM_TIMESTAMP,
|
161 |
+
to_timestamp: int = DEFAULT_TO_TIMESTAMP,
|
162 |
+
):
|
163 |
"""Create fpmmTrades for all trades."""
|
164 |
+
print("Getting trades from Quickstart markets")
|
165 |
# Quickstart trades
|
166 |
qs_trades_json = query_omen_xdai_subgraph(
|
167 |
trader_category="quickstart",
|
168 |
from_timestamp=from_timestamp,
|
169 |
+
to_timestamp=to_timestamp,
|
170 |
fpmm_from_timestamp=from_timestamp,
|
171 |
+
fpmm_to_timestamp=to_timestamp,
|
172 |
)
|
173 |
|
174 |
print(f"length of the qs_trades_json dataset {len(qs_trades_json)}")
|
|
|
179 |
qs_df = transform_fpmmTrades(qs_df)
|
180 |
|
181 |
# Pearl trades
|
182 |
+
print("Getting trades from Pearl markets")
|
183 |
pearl_trades_json = query_omen_xdai_subgraph(
|
184 |
trader_category="pearl",
|
185 |
from_timestamp=from_timestamp,
|
|
|
340 |
return tools
|
341 |
|
342 |
|
343 |
+
def fpmmTrades_etl(
|
344 |
+
trades_filename: str, from_timestamp: int, to_timestamp: int = DEFAULT_TO_TIMESTAMP
|
345 |
+
) -> None:
|
346 |
print("Generating the trades file")
|
347 |
try:
|
348 |
+
fpmmTrades = create_fpmmTrades(
|
349 |
+
from_timestamp=from_timestamp, to_timestamp=to_timestamp
|
350 |
+
)
|
351 |
except FileNotFoundError:
|
352 |
print(f"Error creating {trades_filename} file .")
|
353 |
|
scripts/profitability.py
CHANGED
@@ -146,7 +146,7 @@ def prepare_profitalibity_data(
|
|
146 |
|
147 |
# Check if tools.parquet is in the same directory
|
148 |
try:
|
149 |
-
#
|
150 |
tools = pd.read_parquet(DATA_DIR / tools_filename)
|
151 |
|
152 |
# make sure creator_address is in the columns
|
@@ -165,7 +165,7 @@ def prepare_profitalibity_data(
|
|
165 |
return
|
166 |
|
167 |
# Check if fpmmTrades.parquet is in the same directory
|
168 |
-
print("Reading the trades file")
|
169 |
try:
|
170 |
fpmmTrades = pd.read_parquet(DATA_DIR / trades_filename)
|
171 |
except FileNotFoundError:
|
@@ -413,10 +413,8 @@ def run_profitability_analysis(
|
|
413 |
|
414 |
all_trades_df = all_trades_df.loc[all_trades_df["is_invalid"] == False]
|
415 |
|
416 |
-
# add staking labels
|
417 |
all_trades_df = label_trades_by_staking(trades_df=all_trades_df)
|
418 |
|
419 |
-
# create the unknown traders dataset
|
420 |
print("Creating unknown traders dataset")
|
421 |
unknown_traders_df, all_trades_df = create_unknown_traders_df(
|
422 |
trades_df=all_trades_df
|
@@ -424,9 +422,10 @@ def run_profitability_analysis(
|
|
424 |
# merge with previous unknown traders dataset
|
425 |
previous_unknown_traders = pd.read_parquet(DATA_DIR / "unknown_traders.parquet")
|
426 |
|
427 |
-
unknown_traders_df = pd.concat(
|
428 |
[unknown_traders_df, previous_unknown_traders], ignore_index=True
|
429 |
)
|
|
|
430 |
unknown_traders_df.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
431 |
|
432 |
# save to parquet
|
@@ -437,6 +436,81 @@ def run_profitability_analysis(
|
|
437 |
return all_trades_df
|
438 |
|
439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
440 |
if __name__ == "__main__":
|
441 |
# updating the whole fpmmTrades parquet file instead of just the new ones
|
442 |
# trade_mech_calls = pd.read_parquet(TMP_DIR / "result_df.parquet")
|
|
|
146 |
|
147 |
# Check if tools.parquet is in the same directory
|
148 |
try:
|
149 |
+
# tools parquet file
|
150 |
tools = pd.read_parquet(DATA_DIR / tools_filename)
|
151 |
|
152 |
# make sure creator_address is in the columns
|
|
|
165 |
return
|
166 |
|
167 |
# Check if fpmmTrades.parquet is in the same directory
|
168 |
+
print("Reading the new trades file")
|
169 |
try:
|
170 |
fpmmTrades = pd.read_parquet(DATA_DIR / trades_filename)
|
171 |
except FileNotFoundError:
|
|
|
413 |
|
414 |
all_trades_df = all_trades_df.loc[all_trades_df["is_invalid"] == False]
|
415 |
|
|
|
416 |
all_trades_df = label_trades_by_staking(trades_df=all_trades_df)
|
417 |
|
|
|
418 |
print("Creating unknown traders dataset")
|
419 |
unknown_traders_df, all_trades_df = create_unknown_traders_df(
|
420 |
trades_df=all_trades_df
|
|
|
422 |
# merge with previous unknown traders dataset
|
423 |
previous_unknown_traders = pd.read_parquet(DATA_DIR / "unknown_traders.parquet")
|
424 |
|
425 |
+
unknown_traders_df: pd.DataFrame = pd.concat(
|
426 |
[unknown_traders_df, previous_unknown_traders], ignore_index=True
|
427 |
)
|
428 |
+
unknown_traders_df.drop_duplicates("trade_id", keep="last", inplace=True)
|
429 |
unknown_traders_df.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
430 |
|
431 |
# save to parquet
|
|
|
436 |
return all_trades_df
|
437 |
|
438 |
|
439 |
+
def add_trades_profitability(trades_filename: str):
|
440 |
+
print("Reading the trades file")
|
441 |
+
try:
|
442 |
+
fpmmTrades = pd.read_parquet(DATA_DIR / trades_filename)
|
443 |
+
except FileNotFoundError:
|
444 |
+
print(f"Error reading {trades_filename} file .")
|
445 |
+
|
446 |
+
# make sure trader_address is in the columns
|
447 |
+
assert "trader_address" in fpmmTrades.columns, "trader_address column not found"
|
448 |
+
|
449 |
+
# lowercase and strip creator_address
|
450 |
+
fpmmTrades["trader_address"] = fpmmTrades["trader_address"].str.lower().str.strip()
|
451 |
+
|
452 |
+
print("Reading tools parquet file")
|
453 |
+
tools = pd.read_parquet(TMP_DIR / "tools.parquet")
|
454 |
+
|
455 |
+
try:
|
456 |
+
fpmmTrades["creationTimestamp"] = fpmmTrades["creationTimestamp"].apply(
|
457 |
+
lambda x: transform_to_datetime(x)
|
458 |
+
)
|
459 |
+
except Exception as e:
|
460 |
+
print(f"Transformation not needed")
|
461 |
+
|
462 |
+
print("Computing the estimated mech calls dataset")
|
463 |
+
trade_mech_calls = compute_mech_calls_based_on_timestamps(
|
464 |
+
fpmmTrades=fpmmTrades, tools=tools
|
465 |
+
)
|
466 |
+
print(trade_mech_calls.total_mech_calls.describe())
|
467 |
+
print("Analysing trades...")
|
468 |
+
all_trades_df = analyse_all_traders(fpmmTrades, trade_mech_calls)
|
469 |
+
|
470 |
+
# debugging purposes
|
471 |
+
all_trades_df.to_parquet(JSON_DATA_DIR / "missing_trades_df.parquet", index=False)
|
472 |
+
# filter invalid markets. Condition: "is_invalid" is True
|
473 |
+
print("Checking invalid trades")
|
474 |
+
invalid_trades = all_trades_df.loc[all_trades_df["is_invalid"] == True]
|
475 |
+
if len(invalid_trades) > 0:
|
476 |
+
try:
|
477 |
+
print("Merging invalid trades parquet file")
|
478 |
+
old_invalid_trades = pd.read_parquet(DATA_DIR / "invalid_trades.parquet")
|
479 |
+
merge_df = pd.concat(
|
480 |
+
[old_invalid_trades, invalid_trades], ignore_index=True
|
481 |
+
)
|
482 |
+
invalid_trades = merge_df.drop_duplicates("trade_id")
|
483 |
+
except Exception as e:
|
484 |
+
print(f"Error updating the invalid trades parquet {e}")
|
485 |
+
invalid_trades.to_parquet(DATA_DIR / "invalid_trades.parquet", index=False)
|
486 |
+
all_trades_df = all_trades_df.loc[all_trades_df["is_invalid"] == False]
|
487 |
+
|
488 |
+
print("Adding staking labels")
|
489 |
+
all_trades_df = label_trades_by_staking(trades_df=all_trades_df)
|
490 |
+
print("Creating unknown traders dataset")
|
491 |
+
unknown_traders_df, all_trades_df = create_unknown_traders_df(
|
492 |
+
trades_df=all_trades_df
|
493 |
+
)
|
494 |
+
if len(unknown_traders_df) > 0:
|
495 |
+
print("Merging unknown traders info")
|
496 |
+
# merge with previous unknown traders dataset
|
497 |
+
previous_unknown_traders = pd.read_parquet(DATA_DIR / "unknown_traders.parquet")
|
498 |
+
|
499 |
+
unknown_traders_df: pd.DataFrame = pd.concat(
|
500 |
+
[unknown_traders_df, previous_unknown_traders], ignore_index=True
|
501 |
+
)
|
502 |
+
unknown_traders_df.drop_duplicates("trade_id", keep="last", inplace=True)
|
503 |
+
unknown_traders_df.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
504 |
+
|
505 |
+
print("merge with previous all_trades_profitability")
|
506 |
+
old_trades = pd.read_parquet(DATA_DIR / "all_trades_profitability.parquet")
|
507 |
+
all_trades_df: pd.DataFrame = pd.concat(
|
508 |
+
[all_trades_df, old_trades], ignore_index=True
|
509 |
+
)
|
510 |
+
all_trades_df.drop_duplicates("trade_id", keep="last", inplace=True)
|
511 |
+
all_trades_df.to_parquet(DATA_DIR / "all_trades_profitability.parquet", index=False)
|
512 |
+
|
513 |
+
|
514 |
if __name__ == "__main__":
|
515 |
# updating the whole fpmmTrades parquet file instead of just the new ones
|
516 |
# trade_mech_calls = pd.read_parquet(TMP_DIR / "result_df.parquet")
|
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
|
7 |
from utils import (
|
8 |
get_question,
|
9 |
current_answer,
|
@@ -22,7 +22,7 @@ from update_tools_accuracy import compute_tools_accuracy
|
|
22 |
from cleaning_old_info import clean_old_data_from_parquet_files
|
23 |
from web3_utils import updating_timestamps
|
24 |
from manage_space_files import move_files
|
25 |
-
from cloud_storage import
|
26 |
from tools_metrics import compute_tools_based_datasets
|
27 |
|
28 |
|
@@ -64,7 +64,7 @@ def save_historical_data():
|
|
64 |
filename = f"tools_{timestamp}.parquet"
|
65 |
tools.to_parquet(HIST_DIR / filename, index=False)
|
66 |
# save into cloud storage
|
67 |
-
|
68 |
except Exception as e:
|
69 |
print(f"Error saving tools file in the historical folder {e}")
|
70 |
|
@@ -73,7 +73,7 @@ def save_historical_data():
|
|
73 |
filename = f"all_trades_profitability_{timestamp}.parquet"
|
74 |
all_trades.to_parquet(HIST_DIR / filename, index=False)
|
75 |
# save into cloud storage
|
76 |
-
|
77 |
|
78 |
except Exception as e:
|
79 |
print(
|
@@ -101,7 +101,6 @@ def only_new_weekly_analysis():
|
|
101 |
|
102 |
# FpmmTrades ETL
|
103 |
fpmmTrades_etl(
|
104 |
-
rpc=rpc,
|
105 |
trades_filename="new_fpmmTrades.parquet",
|
106 |
from_timestamp=int(latest_timestamp.timestamp()),
|
107 |
)
|
@@ -132,7 +131,7 @@ def only_new_weekly_analysis():
|
|
132 |
|
133 |
save_historical_data()
|
134 |
try:
|
135 |
-
clean_old_data_from_parquet_files("2024-11-
|
136 |
except Exception as e:
|
137 |
print("Error cleaning the oldest information from parquet files")
|
138 |
print(f"reason = {e}")
|
@@ -143,5 +142,28 @@ def only_new_weekly_analysis():
|
|
143 |
logging.info("Weekly analysis files generated and saved")
|
144 |
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
if __name__ == "__main__":
|
147 |
only_new_weekly_analysis()
|
|
|
|
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, add_trades_profitability
|
7 |
from utils import (
|
8 |
get_question,
|
9 |
current_answer,
|
|
|
22 |
from cleaning_old_info import clean_old_data_from_parquet_files
|
23 |
from web3_utils import updating_timestamps
|
24 |
from manage_space_files import move_files
|
25 |
+
from cloud_storage import upload_historical_file
|
26 |
from tools_metrics import compute_tools_based_datasets
|
27 |
|
28 |
|
|
|
64 |
filename = f"tools_{timestamp}.parquet"
|
65 |
tools.to_parquet(HIST_DIR / filename, index=False)
|
66 |
# save into cloud storage
|
67 |
+
upload_historical_file(filename)
|
68 |
except Exception as e:
|
69 |
print(f"Error saving tools file in the historical folder {e}")
|
70 |
|
|
|
73 |
filename = f"all_trades_profitability_{timestamp}.parquet"
|
74 |
all_trades.to_parquet(HIST_DIR / filename, index=False)
|
75 |
# save into cloud storage
|
76 |
+
upload_historical_file(filename)
|
77 |
|
78 |
except Exception as e:
|
79 |
print(
|
|
|
101 |
|
102 |
# FpmmTrades ETL
|
103 |
fpmmTrades_etl(
|
|
|
104 |
trades_filename="new_fpmmTrades.parquet",
|
105 |
from_timestamp=int(latest_timestamp.timestamp()),
|
106 |
)
|
|
|
131 |
|
132 |
save_historical_data()
|
133 |
try:
|
134 |
+
clean_old_data_from_parquet_files("2024-11-19")
|
135 |
except Exception as e:
|
136 |
print("Error cleaning the oldest information from parquet files")
|
137 |
print(f"reason = {e}")
|
|
|
142 |
logging.info("Weekly analysis files generated and saved")
|
143 |
|
144 |
|
145 |
+
def restoring_trades_data(from_date: str, to_date: str):
|
146 |
+
# Convert the string to datetime64[ns, UTC]
|
147 |
+
min_date_utc = pd.to_datetime(from_date, format="%Y-%m-%d", utc=True)
|
148 |
+
max_date_utc = pd.to_datetime(to_date, format="%Y-%m-%d", utc=True)
|
149 |
+
logging.info("Running markets ETL")
|
150 |
+
mkt_etl(MARKETS_FILENAME)
|
151 |
+
logging.info("Markets ETL completed")
|
152 |
+
|
153 |
+
fpmmTrades_etl(
|
154 |
+
trades_filename="missing_fpmmTrades.parquet",
|
155 |
+
from_timestamp=int(min_date_utc.timestamp()),
|
156 |
+
to_timestamp=int(max_date_utc.timestamp()),
|
157 |
+
)
|
158 |
+
|
159 |
+
# merge with the old file
|
160 |
+
print("Merging with previous fpmmTrades file")
|
161 |
+
update_fpmmTrades_parquet(trades_filename="missing_fpmmTrades.parquet")
|
162 |
+
|
163 |
+
# adding tools information
|
164 |
+
add_trades_profitability(trades_filename="missing_fpmmTrades.parquet")
|
165 |
+
|
166 |
+
|
167 |
if __name__ == "__main__":
|
168 |
only_new_weekly_analysis()
|
169 |
+
# restoring_trades_data("2024-12-28", "2025-01-07")
|
scripts/staking.py
CHANGED
@@ -22,13 +22,27 @@ STAKING_PROGRAMS_QS = {
|
|
22 |
"quickstart_beta_expert": "0x5344B7DD311e5d3DdDd46A4f71481bD7b05AAA3e",
|
23 |
"quickstart_beta_expert_2": "0xb964e44c126410df341ae04B13aB10A985fE3513",
|
24 |
"quickstart_beta_expert_3": "0x80faD33Cadb5F53f9D29F02Db97D682E8b101618",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
STAKING_PROGRAMS_PEARL = {
|
28 |
"pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A",
|
29 |
"pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d",
|
30 |
"pearl_beta_2": "0x1c2F82413666d2a3fD8bC337b0268e62dDF67434",
|
|
|
|
|
|
|
31 |
}
|
|
|
|
|
32 |
SERVICE_REGISTRY_ADDRESS = "0x9338b5153AE39BB89f50468E608eD9d764B755fD"
|
33 |
|
34 |
|
@@ -94,6 +108,8 @@ def get_service_data(service_registry: Any, service_id: int) -> dict:
|
|
94 |
state = data[-1]
|
95 |
# print(f"address = {address}")
|
96 |
# print(f"state={state}")
|
|
|
|
|
97 |
if address != "0x0000000000000000000000000000000000000000":
|
98 |
tmp_map[service_id] = {
|
99 |
"safe_address": address,
|
@@ -103,7 +119,7 @@ def get_service_data(service_registry: Any, service_id: int) -> dict:
|
|
103 |
return tmp_map
|
104 |
|
105 |
|
106 |
-
def update_service_map(start: int = 1, end: int =
|
107 |
if os.path.exists(DATA_DIR / "service_map.pkl"):
|
108 |
with open(DATA_DIR / "service_map.pkl", "rb") as f:
|
109 |
service_map = pickle.load(f)
|
@@ -197,11 +213,85 @@ def label_trades_by_staking(trades_df: pd.DataFrame, start: int = None) -> None:
|
|
197 |
return trades_df
|
198 |
|
199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
if __name__ == "__main__":
|
201 |
# create_service_map()
|
202 |
-
trades_df = pd.read_parquet(TMP_DIR / "all_trades_df.parquet")
|
203 |
-
trades_df = trades_df.loc[trades_df["is_invalid"] == False]
|
204 |
-
|
205 |
-
trades_df = label_trades_by_staking(trades_df=trades_df, start=8)
|
206 |
-
print(trades_df.staking.value_counts())
|
207 |
-
trades_df.to_parquet(TMP_DIR / "result_staking.parquet", index=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
"quickstart_beta_expert": "0x5344B7DD311e5d3DdDd46A4f71481bD7b05AAA3e",
|
23 |
"quickstart_beta_expert_2": "0xb964e44c126410df341ae04B13aB10A985fE3513",
|
24 |
"quickstart_beta_expert_3": "0x80faD33Cadb5F53f9D29F02Db97D682E8b101618",
|
25 |
+
"quickstart_beta_expert_4": "0xaD9d891134443B443D7F30013c7e14Fe27F2E029",
|
26 |
+
"quickstart_beta_expert_5": "0xE56dF1E563De1B10715cB313D514af350D207212",
|
27 |
+
"quickstart_beta_expert_6": "0x2546214aEE7eEa4bEE7689C81231017CA231Dc93",
|
28 |
+
"quickstart_beta_expert_7": "0xD7A3C8b975f71030135f1a66e9e23164d54fF455",
|
29 |
+
"quickstart_beta_expert_8": "0x356C108D49C5eebd21c84c04E9162de41933030c",
|
30 |
+
"quickstart_beta_expert_9": "0x17dBAe44BC5618Cc254055b386A29576b4F87015",
|
31 |
+
"quickstart_beta_expert_10": "0xB0ef657b8302bd2c74B6E6D9B2b4b39145b19c6f",
|
32 |
+
"quickstart_beta_expert_11": "0x3112c1613eAC3dBAE3D4E38CeF023eb9E2C91CF7",
|
33 |
+
"quickstart_beta_expert_12": "0xF4a75F476801B3fBB2e7093aCDcc3576593Cc1fc",
|
34 |
}
|
35 |
|
36 |
STAKING_PROGRAMS_PEARL = {
|
37 |
"pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A",
|
38 |
"pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d",
|
39 |
"pearl_beta_2": "0x1c2F82413666d2a3fD8bC337b0268e62dDF67434",
|
40 |
+
"pearl_beta_3": "0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1",
|
41 |
+
"pearl_beta_4": "0x3052451e1eAee78e62E169AfdF6288F8791F2918",
|
42 |
+
"pearl_beta_5": "0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4",
|
43 |
}
|
44 |
+
|
45 |
+
|
46 |
SERVICE_REGISTRY_ADDRESS = "0x9338b5153AE39BB89f50468E608eD9d764B755fD"
|
47 |
|
48 |
|
|
|
108 |
state = data[-1]
|
109 |
# print(f"address = {address}")
|
110 |
# print(f"state={state}")
|
111 |
+
# PEARL trade
|
112 |
+
|
113 |
if address != "0x0000000000000000000000000000000000000000":
|
114 |
tmp_map[service_id] = {
|
115 |
"safe_address": address,
|
|
|
119 |
return tmp_map
|
120 |
|
121 |
|
122 |
+
def update_service_map(start: int = 1, end: int = 2000):
|
123 |
if os.path.exists(DATA_DIR / "service_map.pkl"):
|
124 |
with open(DATA_DIR / "service_map.pkl", "rb") as f:
|
125 |
service_map = pickle.load(f)
|
|
|
213 |
return trades_df
|
214 |
|
215 |
|
216 |
+
def generate_retention_activity_file():
|
217 |
+
tools = pd.read_parquet(TMP_DIR / "tools.parquet")
|
218 |
+
tools["request_time"] = pd.to_datetime(tools["request_time"])
|
219 |
+
tools["request_date"] = tools["request_time"].dt.date
|
220 |
+
tools = tools.sort_values(by="request_time", ascending=True)
|
221 |
+
reduced_tools_df = tools[
|
222 |
+
["trader_address", "request_time", "market_creator", "request_date"]
|
223 |
+
]
|
224 |
+
print(f"length of reduced tools before labeling = {len(reduced_tools_df)}")
|
225 |
+
reduced_tools_df = label_trades_by_staking(trades_df=reduced_tools_df)
|
226 |
+
print(f"length of reduced tools after labeling = {len(reduced_tools_df)}")
|
227 |
+
reduced_tools_df = reduced_tools_df.sort_values(by="request_time", ascending=True)
|
228 |
+
reduced_tools_df["month_year_week"] = (
|
229 |
+
pd.to_datetime(tools["request_time"])
|
230 |
+
.dt.to_period("W")
|
231 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
232 |
+
)
|
233 |
+
reduced_tools_df.to_parquet(TMP_DIR / "retention_activity.parquet")
|
234 |
+
return True
|
235 |
+
|
236 |
+
|
237 |
+
def check_list_addresses(address_list: list):
|
238 |
+
with open(DATA_DIR / "service_map.pkl", "rb") as f:
|
239 |
+
service_map = pickle.load(f)
|
240 |
+
# check if it is part of any service id on the map
|
241 |
+
mapping = {}
|
242 |
+
print(f"length of service map={len(service_map)}")
|
243 |
+
keys = service_map.keys()
|
244 |
+
last_key = max(keys)
|
245 |
+
|
246 |
+
print(f"last service key = {last_key}")
|
247 |
+
update_service_map(start=last_key)
|
248 |
+
found_key = -1
|
249 |
+
for trader_address in address_list:
|
250 |
+
for key, value in service_map.items():
|
251 |
+
if value["safe_address"].lower() == trader_address.lower():
|
252 |
+
# found a service
|
253 |
+
found_key = key
|
254 |
+
mapping[trader_address] = "Olas"
|
255 |
+
|
256 |
+
if found_key == -1:
|
257 |
+
mapping[trader_address] = "non_Olas"
|
258 |
+
print("mapping")
|
259 |
+
print(mapping)
|
260 |
+
|
261 |
+
|
262 |
+
def check_service_map():
|
263 |
+
with open(DATA_DIR / "service_map.pkl", "rb") as f:
|
264 |
+
service_map = pickle.load(f)
|
265 |
+
# check if it is part of any service id on the map
|
266 |
+
mapping = {}
|
267 |
+
print(f"length of service map={len(service_map)}")
|
268 |
+
keys = service_map.keys()
|
269 |
+
last_key = max(keys)
|
270 |
+
print(f"last key ={last_key}")
|
271 |
+
missing_keys = 0
|
272 |
+
for i in range(1, last_key):
|
273 |
+
if i not in keys:
|
274 |
+
missing_keys += 1
|
275 |
+
print(f"missing key = {i}")
|
276 |
+
print(f"total missing keys = {missing_keys}")
|
277 |
+
|
278 |
+
|
279 |
if __name__ == "__main__":
|
280 |
# create_service_map()
|
281 |
+
# trades_df = pd.read_parquet(TMP_DIR / "all_trades_df.parquet")
|
282 |
+
# trades_df = trades_df.loc[trades_df["is_invalid"] == False]
|
283 |
+
|
284 |
+
# trades_df = label_trades_by_staking(trades_df=trades_df, start=8)
|
285 |
+
# print(trades_df.staking.value_counts())
|
286 |
+
# trades_df.to_parquet(TMP_DIR / "result_staking.parquet", index=False)
|
287 |
+
# generate_retention_activity_file()
|
288 |
+
a_list = [
|
289 |
+
"0x027592700fafc4db3221bb662d7bdc7f546a2bb5",
|
290 |
+
"0x0845f4ad01a2f41da618848c7a9e56b64377965e",
|
291 |
+
]
|
292 |
+
# check_list_addresses(address_list=a_list)
|
293 |
+
# update_service_map()
|
294 |
+
# check_service_map()
|
295 |
+
unknown_traders = pd.read_parquet(DATA_DIR / "unknown_traders.parquet")
|
296 |
+
unknown_traders = label_trades_by_staking(trades_df=unknown_traders)
|
297 |
+
unknown_traders.to_parquet(DATA_DIR / "unknown_traders.parquet", index=False)
|
scripts/tools_metrics.py
CHANGED
@@ -61,7 +61,9 @@ def prepare_tools(tools: pd.DataFrame) -> pd.DataFrame:
|
|
61 |
tools = tools.sort_values(by="request_time", ascending=True)
|
62 |
|
63 |
tools["request_month_year_week"] = (
|
64 |
-
pd.to_datetime(tools["request_time"])
|
|
|
|
|
65 |
)
|
66 |
# preparing the tools graph
|
67 |
# adding the total
|
|
|
61 |
tools = tools.sort_values(by="request_time", ascending=True)
|
62 |
|
63 |
tools["request_month_year_week"] = (
|
64 |
+
pd.to_datetime(tools["request_time"])
|
65 |
+
.dt.to_period("W")
|
66 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
67 |
)
|
68 |
# preparing the tools graph
|
69 |
# adding the total
|
scripts/web3_utils.py
CHANGED
@@ -132,7 +132,9 @@ def updating_timestamps(rpc: str, tools_filename: str):
|
|
132 |
"%Y-%m"
|
133 |
)
|
134 |
tools["request_month_year_week"] = (
|
135 |
-
pd.to_datetime(tools["request_time"])
|
|
|
|
|
136 |
)
|
137 |
|
138 |
# Save the tools data after the updates on the content
|
@@ -178,7 +180,7 @@ def query_conditional_tokens_gc_subgraph(creator: str) -> dict[str, Any]:
|
|
178 |
userPositions_id_gt=userPositions_id_gt,
|
179 |
)
|
180 |
content_json = {"query": query}
|
181 |
-
print("sending query to subgraph")
|
182 |
res = requests.post(subgraph, headers=headers, json=content_json)
|
183 |
result_json = res.json()
|
184 |
# print(f"result = {result_json}")
|
@@ -229,6 +231,7 @@ def query_omen_xdai_subgraph(
|
|
229 |
first=QUERY_BATCH_SIZE,
|
230 |
id_gt=id_gt,
|
231 |
)
|
|
|
232 |
content_json = to_content(query)
|
233 |
|
234 |
res = requests.post(omen_subgraph, headers=headers, json=content_json)
|
|
|
132 |
"%Y-%m"
|
133 |
)
|
134 |
tools["request_month_year_week"] = (
|
135 |
+
pd.to_datetime(tools["request_time"])
|
136 |
+
.dt.to_period("W")
|
137 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
138 |
)
|
139 |
|
140 |
# Save the tools data after the updates on the content
|
|
|
180 |
userPositions_id_gt=userPositions_id_gt,
|
181 |
)
|
182 |
content_json = {"query": query}
|
183 |
+
# print("sending query to subgraph")
|
184 |
res = requests.post(subgraph, headers=headers, json=content_json)
|
185 |
result_json = res.json()
|
186 |
# print(f"result = {result_json}")
|
|
|
231 |
first=QUERY_BATCH_SIZE,
|
232 |
id_gt=id_gt,
|
233 |
)
|
234 |
+
print(f"omen query={query}")
|
235 |
content_json = to_content(query)
|
236 |
|
237 |
res = requests.post(omen_subgraph, headers=headers, json=content_json)
|
tabs/tool_win.py
CHANGED
@@ -14,7 +14,9 @@ def prepare_tools(tools: pd.DataFrame) -> pd.DataFrame:
|
|
14 |
tools = tools.sort_values(by="request_time", ascending=True)
|
15 |
|
16 |
tools["request_month_year_week"] = (
|
17 |
-
pd.to_datetime(tools["request_time"])
|
|
|
|
|
18 |
)
|
19 |
# preparing the tools graph
|
20 |
# adding the total
|
|
|
14 |
tools = tools.sort_values(by="request_time", ascending=True)
|
15 |
|
16 |
tools["request_month_year_week"] = (
|
17 |
+
pd.to_datetime(tools["request_time"])
|
18 |
+
.dt.to_period("W")
|
19 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
20 |
)
|
21 |
# preparing the tools graph
|
22 |
# adding the total
|
tabs/trades.py
CHANGED
@@ -21,7 +21,9 @@ def prepare_trades(trades_df: pd.DataFrame) -> pd.DataFrame:
|
|
21 |
trades_df["creation_timestamp"].dt.to_period("M").astype(str)
|
22 |
)
|
23 |
trades_df["month_year_week"] = (
|
24 |
-
trades_df["creation_timestamp"]
|
|
|
|
|
25 |
)
|
26 |
trades_df["winning_trade"] = trades_df["winning_trade"].astype(int)
|
27 |
return trades_df
|
|
|
21 |
trades_df["creation_timestamp"].dt.to_period("M").astype(str)
|
22 |
)
|
23 |
trades_df["month_year_week"] = (
|
24 |
+
trades_df["creation_timestamp"]
|
25 |
+
.dt.to_period("W")
|
26 |
+
.dt.start_time.dt.strftime("%b-%d-%Y")
|
27 |
)
|
28 |
trades_df["winning_trade"] = trades_df["winning_trade"].astype(int)
|
29 |
return trades_df
|