This commit is contained in:
2026-04-25 23:43:03 +00:00
parent f5d8037594
commit 27227709e6
8 changed files with 2257 additions and 498 deletions

View File

@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "4cae6bf1",
"metadata": {},
"outputs": [],
@@ -14,7 +14,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 2,
"id": "f5040527",
"metadata": {},
"outputs": [
@@ -75,7 +75,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "5c23110d",
"metadata": {},
"outputs": [],
@@ -96,28 +96,28 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 4,
"id": "a866e9ca",
"metadata": {},
"outputs": [],
"source": [
"# df_binance = pd.read_sql(q_binance, con=engine)\n",
"df_coinbase = pd.read_sql(q_coinbase, con=engine)\n",
"df_rtds = pd.read_sql(q_rtds, con=engine)\n",
"# df_coinbase = pd.read_sql(q_coinbase, con=engine)\n",
"# df_rtds = pd.read_sql(q_rtds, con=engine)\n",
"df_clob = pd.read_sql(q_clob, con=engine)"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "954a3c3c",
"metadata": {},
"outputs": [],
"source": [
"# df_binance['timestamp_arrival'] = pd.to_datetime(df_binance['timestamp_arrival'], unit='ms')\n",
"df_coinbase['timestamp_arrival'] = pd.to_datetime(df_coinbase['timestamp_arrival'], unit='ms')\n",
"df_rtds['timestamp_arrival'] = pd.to_datetime(df_rtds['timestamp_arrival'], unit='ms')\n",
"df_clob['timestamp_arrival'] = pd.to_datetime(df_clob['timestamp_arrival'], unit='ms')"
"# df_coinbase['timestamp_arrival'] = pd.to_datetime(df_coinbase['timestamp_arrival'], unit='ms')\n",
"# df_rtds['timestamp_arrival'] = pd.to_datetime(df_rtds['timestamp_arrival'], unit='ms')\n",
"df_clob['timestamp_arrival_dt'] = pd.to_datetime(df_clob['timestamp_arrival'], unit='ms')"
]
},
{
@@ -225,19 +225,177 @@
},
{
"cell_type": "code",
"execution_count": null,
"id": "cd0b40d2",
"execution_count": 75,
"id": "85555ab4",
"metadata": {},
"outputs": [],
"source": [
"sql = text('''\n",
"OPTIMIZE TABLE binance_btcusd_trades;\n",
"''')\n",
"sql = text('''\n",
"SELECT \n",
" table_name, \n",
" data_length, \n",
" index_length, \n",
" data_free \n",
"FROM information_schema.tables;\n",
"''')"
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "a665c36f",
"metadata": {},
"outputs": [],
"source": [
"with engine.connect() as conn:\n",
" conn.execute(sql)\n",
" conn.commit()"
]
},
{
"cell_type": "code",
"execution_count": 76,
"id": "db71f3b0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"SUCCESS COPIED 326007 to binance_btcusd_trades to INTERSERVER_STORAGE\n"
]
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>TABLE_NAME</th>\n",
" <th>DATA_LENGTH</th>\n",
" <th>INDEX_LENGTH</th>\n",
" <th>DATA_FREE</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>innodb_table_stats</td>\n",
" <td>16384.0</td>\n",
" <td>0.0</td>\n",
" <td>4194304.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>innodb_index_stats</td>\n",
" <td>16384.0</td>\n",
" <td>0.0</td>\n",
" <td>4194304.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>CHARACTER_SETS</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>CHECK_CONSTRAINTS</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>COLLATIONS</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>342</th>\n",
" <td>user_stream_trades</td>\n",
" <td>81920.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>343</th>\n",
" <td>user_stream_orders</td>\n",
" <td>16384.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>344</th>\n",
" <td>executions_orders</td>\n",
" <td>16384.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>345</th>\n",
" <td>poly_btcusd_trades</td>\n",
" <td>37289984.0</td>\n",
" <td>0.0</td>\n",
" <td>4194304.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>346</th>\n",
" <td>binance_btcusd_trades</td>\n",
" <td>58294272.0</td>\n",
" <td>0.0</td>\n",
" <td>4194304.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>347 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" TABLE_NAME DATA_LENGTH INDEX_LENGTH DATA_FREE\n",
"0 innodb_table_stats 16384.0 0.0 4194304.0\n",
"1 innodb_index_stats 16384.0 0.0 4194304.0\n",
"2 CHARACTER_SETS 0.0 0.0 0.0\n",
"3 CHECK_CONSTRAINTS 0.0 0.0 0.0\n",
"4 COLLATIONS 0.0 0.0 0.0\n",
".. ... ... ... ...\n",
"342 user_stream_trades 81920.0 0.0 0.0\n",
"343 user_stream_orders 16384.0 0.0 0.0\n",
"344 executions_orders 16384.0 0.0 0.0\n",
"345 poly_btcusd_trades 37289984.0 0.0 4194304.0\n",
"346 binance_btcusd_trades 58294272.0 0.0 4194304.0\n",
"\n",
"[347 rows x 4 columns]"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
"source": [
"pd.read_sql(sql, con=engine)"
]
},
{
"cell_type": "code",
@@ -249,15 +407,420 @@
{
"cell_type": "code",
"execution_count": null,
"id": "b06c6a3e",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>timestamp_arrival</th>\n",
" <th>timestamp_msg</th>\n",
" <th>timestamp_value</th>\n",
" <th>price</th>\n",
" <th>qty</th>\n",
" <th>side_taker</th>\n",
" <th>up_or_down</th>\n",
" <th>timestamp_arrival_dt</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1775064793645</td>\n",
" <td>1775064793630</td>\n",
" <td>1775064793630</td>\n",
" <td>0.59</td>\n",
" <td>477.003500</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-01 17:33:13.645</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1775064793763</td>\n",
" <td>1775064793753</td>\n",
" <td>1775064793753</td>\n",
" <td>0.43</td>\n",
" <td>23.255812</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-01 17:33:13.763</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1775064793843</td>\n",
" <td>1775064793830</td>\n",
" <td>1775064793830</td>\n",
" <td>0.43</td>\n",
" <td>2.325580</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-01 17:33:13.843</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1775064793915</td>\n",
" <td>1775064793905</td>\n",
" <td>1775064793905</td>\n",
" <td>0.58</td>\n",
" <td>10.020000</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-01 17:33:13.915</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1775064794077</td>\n",
" <td>1775064794064</td>\n",
" <td>1775064794064</td>\n",
" <td>0.43</td>\n",
" <td>5.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-01 17:33:14.077</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>672629</th>\n",
" <td>1775158573032</td>\n",
" <td>1775158573022</td>\n",
" <td>1775158573022</td>\n",
" <td>0.37</td>\n",
" <td>3.243242</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:36:13.032</td>\n",
" </tr>\n",
" <tr>\n",
" <th>672630</th>\n",
" <td>1775158573316</td>\n",
" <td>1775158573304</td>\n",
" <td>1775158573304</td>\n",
" <td>0.64</td>\n",
" <td>15.625000</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:36:13.316</td>\n",
" </tr>\n",
" <tr>\n",
" <th>672631</th>\n",
" <td>1775158573365</td>\n",
" <td>1775158573352</td>\n",
" <td>1775158573352</td>\n",
" <td>0.64</td>\n",
" <td>8.200000</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:36:13.365</td>\n",
" </tr>\n",
" <tr>\n",
" <th>672632</th>\n",
" <td>1775158573672</td>\n",
" <td>1775158573661</td>\n",
" <td>1775158573661</td>\n",
" <td>0.37</td>\n",
" <td>200.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:36:13.672</td>\n",
" </tr>\n",
" <tr>\n",
" <th>672633</th>\n",
" <td>1775158573933</td>\n",
" <td>1775158573921</td>\n",
" <td>1775158573921</td>\n",
" <td>0.64</td>\n",
" <td>7.812500</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:36:13.933</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>672634 rows × 8 columns</p>\n",
"</div>"
],
"text/plain": [
" timestamp_arrival timestamp_msg timestamp_value price qty \\\n",
"0 1775064793645 1775064793630 1775064793630 0.59 477.003500 \n",
"1 1775064793763 1775064793753 1775064793753 0.43 23.255812 \n",
"2 1775064793843 1775064793830 1775064793830 0.43 2.325580 \n",
"3 1775064793915 1775064793905 1775064793905 0.58 10.020000 \n",
"4 1775064794077 1775064794064 1775064794064 0.43 5.000000 \n",
"... ... ... ... ... ... \n",
"672629 1775158573032 1775158573022 1775158573022 0.37 3.243242 \n",
"672630 1775158573316 1775158573304 1775158573304 0.64 15.625000 \n",
"672631 1775158573365 1775158573352 1775158573352 0.64 8.200000 \n",
"672632 1775158573672 1775158573661 1775158573661 0.37 200.000000 \n",
"672633 1775158573933 1775158573921 1775158573921 0.64 7.812500 \n",
"\n",
" side_taker up_or_down timestamp_arrival_dt \n",
"0 BUY UP 2026-04-01 17:33:13.645 \n",
"1 BUY DOWN 2026-04-01 17:33:13.763 \n",
"2 BUY DOWN 2026-04-01 17:33:13.843 \n",
"3 BUY UP 2026-04-01 17:33:13.915 \n",
"4 BUY DOWN 2026-04-01 17:33:14.077 \n",
"... ... ... ... \n",
"672629 BUY DOWN 2026-04-02 19:36:13.032 \n",
"672630 BUY UP 2026-04-02 19:36:13.316 \n",
"672631 BUY UP 2026-04-02 19:36:13.365 \n",
"672632 BUY DOWN 2026-04-02 19:36:13.672 \n",
"672633 BUY UP 2026-04-02 19:36:13.933 \n",
"\n",
"[672634 rows x 8 columns]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_clob"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "48b47799",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>timestamp_arrival</th>\n",
" <th>timestamp_msg</th>\n",
" <th>timestamp_value</th>\n",
" <th>price</th>\n",
" <th>qty</th>\n",
" <th>side_taker</th>\n",
" <th>up_or_down</th>\n",
" <th>timestamp_arrival_dt</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>657118</th>\n",
" <td>1775157300177</td>\n",
" <td>1775157300166</td>\n",
" <td>1775157300166</td>\n",
" <td>0.48</td>\n",
" <td>2.083332</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:15:00.177</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657119</th>\n",
" <td>1775157300554</td>\n",
" <td>1775157300540</td>\n",
" <td>1775157300540</td>\n",
" <td>0.47</td>\n",
" <td>6.000000</td>\n",
" <td>SELL</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:15:00.554</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657120</th>\n",
" <td>1775157300575</td>\n",
" <td>1775157300561</td>\n",
" <td>1775157300561</td>\n",
" <td>0.53</td>\n",
" <td>3.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:00.575</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657121</th>\n",
" <td>1775157300645</td>\n",
" <td>1775157300634</td>\n",
" <td>1775157300634</td>\n",
" <td>0.48</td>\n",
" <td>29.570000</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:15:00.645</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657122</th>\n",
" <td>1775157300689</td>\n",
" <td>1775157300677</td>\n",
" <td>1775157300677</td>\n",
" <td>0.50</td>\n",
" <td>20.000000</td>\n",
" <td>BUY</td>\n",
" <td>UP</td>\n",
" <td>2026-04-02 19:15:00.689</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657193</th>\n",
" <td>1775157304972</td>\n",
" <td>1775157304940</td>\n",
" <td>1775157304940</td>\n",
" <td>0.50</td>\n",
" <td>40.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:04.972</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657194</th>\n",
" <td>1775157304979</td>\n",
" <td>1775157304955</td>\n",
" <td>1775157304955</td>\n",
" <td>0.50</td>\n",
" <td>40.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:04.979</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657195</th>\n",
" <td>1775157304986</td>\n",
" <td>1775157304965</td>\n",
" <td>1775157304965</td>\n",
" <td>0.50</td>\n",
" <td>10.200000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:04.986</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657196</th>\n",
" <td>1775157304991</td>\n",
" <td>1775157304973</td>\n",
" <td>1775157304973</td>\n",
" <td>0.50</td>\n",
" <td>6.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:04.991</td>\n",
" </tr>\n",
" <tr>\n",
" <th>657197</th>\n",
" <td>1775157304999</td>\n",
" <td>1775157304988</td>\n",
" <td>1775157304988</td>\n",
" <td>0.50</td>\n",
" <td>40.000000</td>\n",
" <td>BUY</td>\n",
" <td>DOWN</td>\n",
" <td>2026-04-02 19:15:04.999</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>80 rows × 8 columns</p>\n",
"</div>"
],
"text/plain": [
" timestamp_arrival timestamp_msg timestamp_value price qty \\\n",
"657118 1775157300177 1775157300166 1775157300166 0.48 2.083332 \n",
"657119 1775157300554 1775157300540 1775157300540 0.47 6.000000 \n",
"657120 1775157300575 1775157300561 1775157300561 0.53 3.000000 \n",
"657121 1775157300645 1775157300634 1775157300634 0.48 29.570000 \n",
"657122 1775157300689 1775157300677 1775157300677 0.50 20.000000 \n",
"... ... ... ... ... ... \n",
"657193 1775157304972 1775157304940 1775157304940 0.50 40.000000 \n",
"657194 1775157304979 1775157304955 1775157304955 0.50 40.000000 \n",
"657195 1775157304986 1775157304965 1775157304965 0.50 10.200000 \n",
"657196 1775157304991 1775157304973 1775157304973 0.50 6.000000 \n",
"657197 1775157304999 1775157304988 1775157304988 0.50 40.000000 \n",
"\n",
" side_taker up_or_down timestamp_arrival_dt \n",
"657118 BUY UP 2026-04-02 19:15:00.177 \n",
"657119 SELL UP 2026-04-02 19:15:00.554 \n",
"657120 BUY DOWN 2026-04-02 19:15:00.575 \n",
"657121 BUY UP 2026-04-02 19:15:00.645 \n",
"657122 BUY UP 2026-04-02 19:15:00.689 \n",
"... ... ... ... \n",
"657193 BUY DOWN 2026-04-02 19:15:04.972 \n",
"657194 BUY DOWN 2026-04-02 19:15:04.979 \n",
"657195 BUY DOWN 2026-04-02 19:15:04.986 \n",
"657196 BUY DOWN 2026-04-02 19:15:04.991 \n",
"657197 BUY DOWN 2026-04-02 19:15:04.999 \n",
"\n",
"[80 rows x 8 columns]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_clob.loc[(df_clob['timestamp_arrival']>1775157300*1000)&(df_clob['timestamp_arrival']<1775157305*1000)]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad030f88",
"id": "e7aa7cfd",
"metadata": {},
"outputs": [],
"source": []
@@ -265,7 +828,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "cafc5060",
"id": "9bc2cecb",
"metadata": {},
"outputs": [],
"source": []
@@ -273,10 +836,21 @@
{
"cell_type": "code",
"execution_count": null,
"id": "734c2302",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "8a293522",
"metadata": {},
"outputs": [],
"source": [
"a"
]
},
{
"cell_type": "code",
"execution_count": null,

942
main copy.py Normal file
View File

@@ -0,0 +1,942 @@
import asyncio
import json
from dataclasses import dataclass
import logging
import math
import os
import time
from datetime import datetime, timezone
from typing import AsyncContextManager
import traceback
import numpy as np
import pandas as pd
import requests
import talib
import valkey
from dotenv import load_dotenv
from py_clob_client.clob_types import (
OrderArgs,
OrderType,
PartialCreateOrderOptions,
PostOrdersArgs,
BalanceAllowanceParams,
OpenOrderParams
)
from py_clob_client.order_builder.constants import BUY, SELL
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine
from functools import wraps
import modules.api as api
### Custom Order Args ###
@dataclass
class Custom_OrderArgs(OrderArgs):
max_price: float = 0.00
post_only: bool = False
### Database ###
CLIENT = None
CON: AsyncContextManager | None = None
VAL_KEY = None
### Logging ###
load_dotenv()
LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Polymarket_5min_Algo.log'
### ALGO CONFIG / CONSTANTS ###
SLOPE_YES_THRESH = 0.01 # In Percent % Chg (e.g. 0.02 == 0.02%)
ENDTIME_BUFFER_SEC = 30 # Stop trading, cancel all open orders and exit positions this many seconds before mkt settles.
TGT_PX_INDEX_DIFF_THRESH = 0.05 # In Percent % Chg (e.g. 0.02 == 0.02%)
DEFAULT_ORDER_SIZE = 5 # In USDe
MIN_ORDER_SIZE = 5 # In USDe
TGT_PROFIT_CENTS = 0.03
# CHASE_TO_BUY_CENTS = 0.05
MAX_ALLOWED_POLY_PX = 0.90
### GLOBALS ###
ORDER_LOCK = 0
SLUG_END_TIME = 0
FREE_CASH: float = 0
POLY_BINANCE = {}
POLY_REF = {}
POLY_CLOB = {}
POLY_CLOB_DOWN = {}
USER_TRADES = {}
USER_ORDERS = {}
SLOPE_HIST = []
LOCAL_ACTIVE_ORDERS = []
LOCAL_TOKEN_BALANCES = {}
# LOCAL_ACTIVE_POSITIONS = []
ACTIVE_BALANCES_EXIST = False ### REMOVE
### Decorators ###
def async_timeit(func):
@wraps(func)
async def wrapper(*args, **kwargs):
start_time = time.perf_counter()
try:
return await func(*args, **kwargs)
finally:
end_time = time.perf_counter()
total_time = (end_time - start_time)*1000
print(f"Function '{func.__name__}' executed in {total_time:.4f} ms")
return wrapper
### Database Funcs ###
# @async_timeit
async def create_executions_orders_table(
CON: AsyncContextManager,
engine: str = 'mysql', # mysql | duckdb
) -> None:
if CON is None:
logging.info("NO DB CONNECTION, SKIPPING Create Statements")
else:
if engine == 'mysql':
logging.info('Creating Table if Does Not Exist: executions_orders')
await CON.execute(text("""
CREATE TABLE IF NOT EXISTS executions_orders (
timestamp_sent BIGINT,
token_id VARCHAR(100),
limit_price DOUBLE,
size DOUBLE,
side VARCHAR(8),
order_type VARCHAR(8),
post_only BOOL,
resp_errorMsg VARCHAR(100),
resp_orderID VARCHAR(100),
resp_takingAmount DOUBLE,
resp_makingAmount DOUBLE,
resp_status VARCHAR(20),
resp_success BOOL
);
"""))
await CON.commit()
else:
raise ValueError('Only MySQL engine is implemented')
# @async_timeit
async def insert_executions_orders_table(
timestamp_sent: int,
token_id: str,
limit_price: float,
size: float,
side: str,
order_type: str,
post_only: bool,
resp_errorMsg: str,
resp_orderID: str,
resp_takingAmount: float,
resp_makingAmount: float,
resp_status: str,
resp_success: bool,
CON: AsyncContextManager,
engine: str = 'mysql', # mysql | duckdb
) -> None:
params={
'timestamp_sent': timestamp_sent,
'token_id': token_id,
'limit_price': limit_price,
'size': size,
'side': side,
'order_type': order_type,
'post_only': post_only,
'resp_errorMsg': resp_errorMsg,
'resp_orderID': resp_orderID,
'resp_takingAmount': resp_takingAmount,
'resp_makingAmount': resp_makingAmount,
'resp_status': resp_status,
'resp_success': resp_success,
}
if CON is None:
logging.info("NO DB CONNECTION, SKIPPING Insert Statements")
else:
if engine == 'mysql':
await CON.execute(text("""
INSERT INTO executions_orders
(
timestamp_sent,
token_id,
limit_price,
size,
side,
order_type,
post_only,
resp_errorMsg,
resp_orderID,
resp_takingAmount,
resp_makingAmount,
resp_status,
resp_success
)
VALUES
(
:timestamp_sent,
:token_id,
:limit_price,
:size,
:side,
:order_type,
:post_only,
:resp_errorMsg,
:resp_orderID,
:resp_takingAmount,
:resp_makingAmount,
:resp_status,
:resp_success
)
"""),
parameters=params
)
await CON.commit()
else:
raise ValueError('Only MySQL engine is implemented')
### Functions ###
# @async_timeit
def upsert_list_of_dicts_by_id(list_of_dicts, new_dict, id='id'):
for index, item in enumerate(list_of_dicts):
if item.get(id) == new_dict.get(id):
list_of_dicts[index] = new_dict
return list_of_dicts
list_of_dicts.append(new_dict)
return list_of_dicts
# @async_timeit
async def slope_decision() -> list[bool, str]:
hist_trades = np.array(POLY_BINANCE.get('hist_trades', []))
if ( np.max(hist_trades[:, 0] )*1000 ) - ( np.min(hist_trades[:, 0])*1000 ) < 5:
logging.info('Max - Min Trade In History is < 5 Seconds Apart')
return False, ''
last_px = POLY_BINANCE['value']
last_px_ts = POLY_BINANCE['timestamp_value']
ts_min_1_sec = last_px_ts - 1000
price_min_1_sec_index = (np.abs(hist_trades[:, 0] - ts_min_1_sec)).argmin()
price_min_1_sec = hist_trades[:, 1][price_min_1_sec_index]
ts_min_5_sec = last_px_ts - 5000
price_min_5_sec_index = (np.abs(hist_trades[:, 0] - ts_min_5_sec)).argmin()
price_min_5_sec = hist_trades[:, 1][price_min_5_sec_index]
slope = (last_px - price_min_1_sec) / price_min_1_sec
slope_5 = (last_px - price_min_5_sec) / price_min_5_sec
SLOPE_HIST.append(slope)
# print(f'Avg Binance: {np.mean(hist_trades[:, 1])}')
# print(f'Len Hist : {len(hist_trades[:, 1])}')
# print(f'First Hist : {pd.to_datetime(np.min(hist_trades[:, 0]), unit='ms')}')
# print(f'Latest Hist: {pd.to_datetime(np.max(hist_trades[:, 0]), unit='ms')}')
# print(f'Slope Hist Avg: {np.mean(SLOPE_HIST):.4%}')
# print(f'Slope Hist Max: {np.max(SLOPE_HIST):.4%}')
# print(f'Slope Hist Std: {np.std(SLOPE_HIST):.4%}')
slope_1_buy = abs(slope) >= ( SLOPE_YES_THRESH / 100)
slope_5_buy = abs(slope_5) >= ( SLOPE_YES_THRESH / 100)
print(f'SLOPE_1: {slope:.4%} == {slope_1_buy}; SLOPE_5: {slope_5:.4%} == {slope_5_buy};')
### DECISION ###
if slope_1_buy and slope_5_buy:
print(f'🤑🤑🤑🤑🤑🤑🤑🤑🤑🤑 Slope: {slope_5:.4%};')
side = 'UP' if slope > 0.00 else 'DOWN'
return True, side
else:
return False, ''
# @async_timeit
async def cancel_all_orders(CLIENT):
logging.info('Attempting to Cancel All Orders')
cxl_resp = CLIENT.cancel_all()
if bool(cxl_resp.get('not_canceled', True)):
logging.warning(f'*** Cancel Request FAILED, trying again and shutting down: {cxl_resp}')
cxl_resp = CLIENT.cancel_all()
raise Exception('*** Cancel Request FAILED')
logging.info(f'Cancel Successful: {cxl_resp}')
# @async_timeit
async def cancel_single_order_by_id(CLIENT, order_id):
global LOCAL_ACTIVE_ORDERS
logging.info(f'Attempting to Cancel Single Order: {order_id}')
cxl_resp = CLIENT.cancel(order_id=order_id)
for idx, o in enumerate(LOCAL_ACTIVE_ORDERS):
if o.get('orderID') == order_id:
if bool(cxl_resp.get('not_canceled', True)):
if cxl_resp.get('not_canceled', {}).get(order_id, None) == "matched orders can't be canceled":
# LOCAL_ACTIVE_ORDERS[idx]['status'] = 'MATCHED'
local_local = LOCAL_ACTIVE_ORDERS.copy()
local_local = local_local[idx]
local_local['status'] = 'MATCHED'
LOCAL_ACTIVE_ORDERS = upsert_list_of_dicts_by_id(LOCAL_ACTIVE_ORDERS, local_local)
logging.info(f'Cancel request failed b/c already matched: {cxl_resp}')
return True
elif cxl_resp.get('not_canceled', {}).get(order_id, None) == "order can't be found - already canceled or matched":
logging.info(f'Cancel request failed b/c already matched or cancelled: {cxl_resp}')
# GET ORDER STATUS
order_status = CLIENT.get_orders(
OpenOrderParams(id=o['orderID'])
)[0]['status'].upper()
logging.info(f'Fetched status from CLOB: {order_status} for order: {o['orderID']}')
if order_status == 'MATCHED':
logging.info('Order is MATCHED')
return True
elif order_status == 'CANCELED':
logging.info('Order is CANCELED')
LOCAL_ACTIVE_ORDERS.pop(idx)
return False
else:
raise ValueError(f'ORDER CXL FAILED AND ORDER STILL SHOWS AS LIVE: {cxl_resp}; STATUS: {order_status}; ID: {o.get('orderID')}')
else:
logging.warning(f'*** Cancel Request FAILED, shutting down: {cxl_resp}')
raise Exception('*** Cancel Request FAILED - SHUTDONW')
else:
LOCAL_ACTIVE_ORDERS.pop(idx)
logging.info(f'Cancel Successful: {cxl_resp}')
return False
# @async_timeit
async def flatten_open_positions(CLIENT, token_id_up, token_id_down):
up = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
down = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_down)
logging.info('*********FLATTENING*********')
logging.info(f'UP BALANCE = {up}')
logging.info(f'DOWN BALANCE = {down}')
### Submit orders to flatten outstanding balances ###
if abs(up) > MIN_ORDER_SIZE:
logging.info(f'Flattening Up Position: {up}')
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id_up,
price=float(POLY_CLOB['price'])-0.05,
size=up,
side=SELL,
)]
)
if abs(down) > MIN_ORDER_SIZE:
logging.info(f'Flattening Down Position: {down}')
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id_down,
price=float(POLY_CLOB_DOWN['price'])-0.05,
size=down,
side=SELL,
)]
)
logging.info('**************************')
# @async_timeit
async def get_balance_by_token_id(CLIENT, token_id):
collateral = CLIENT.get_balance_allowance(
BalanceAllowanceParams(
asset_type='CONDITIONAL',
token_id=token_id,
)
)
balance = float(collateral['balance']) / 1_000_000
balance = balance if balance > 4.99 else 0.00
return balance
# @async_timeit
async def get_usde_balance(CLIENT):
collateral = CLIENT.get_balance_allowance(
BalanceAllowanceParams(
asset_type='COLLATERAL'
)
)
return int(collateral['balance']) / 1_000_000
@async_timeit
async def check_for_open_positions(CLIENT, token_id_up, token_id_down):
global LOCAL_TOKEN_BALANCES
if token_id_up is None or token_id_down is None:
logging.critical('Token Id is None, Exiting')
raise ValueError('Token Id is None, Exiting')
# return False
up = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
down = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_down)
LOCAL_TOKEN_BALANCES = {
token_id_up: up if up else 0,
token_id_down: down if down else 0,
}
logging.info(f'LOCAL_TOKEN_BALANCES: {LOCAL_TOKEN_BALANCES}')
if ( abs(up) > 0 ) or ( abs(down) > 0 ):
return True
else:
return False
@async_timeit
async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size: float | str, neg_risk: bool) -> list[dict]: # Returns order response dict
global LOCAL_ACTIVE_ORDERS
global LOCAL_TOKEN_BALANCES
orders = []
for oa in OrderArgs_list:
orders.append(
PostOrdersArgs(
order=CLIENT.create_order(
order_args=oa,
options=PartialCreateOrderOptions(
tick_size=str(tick_size),
neg_risk=neg_risk
),
),
orderType=OrderType.GTC,
postOnly=oa.post_only,
),
)
### POST
response = CLIENT.post_orders(orders)
for idx, d in enumerate(response):
if d['errorMsg'] == '':
d['token_id'] = OrderArgs_list[idx].token_id
if d['token_id'] == POLY_CLOB['token_id_up']:
d['outcome'] = "UP"
elif d['token_id'] == POLY_CLOB['token_id_down']:
d['outcome'] = "DOWN"
else:
d['outcome'] = "UNKNOWN"
raise ValueError(f'UNKNOWN outcome for order: {d}')
d['price'] = OrderArgs_list[idx].price
d['max_price'] = OrderArgs_list[idx].max_price
d['size'] = OrderArgs_list[idx].size
d['side'] = str(OrderArgs_list[idx].side).upper()
if d['status'].upper() =='MATCHED':
### Order Immediately Matched, Can Put in Offsetting Order Depending on State ###
print('******** ORDER APPEND TO LOCAL - MATCHED ********* ')
LOCAL_ACTIVE_ORDERS.append(d)
elif d['status'].upper() == 'CONFIRMED':
current_balance = float(LOCAL_TOKEN_BALANCES.get(d['token_id'], 0.00))
if d['side'] == 'BUY':
size = float(d['size'])
else:
size = float(d['size']) * -1
LOCAL_TOKEN_BALANCES[d['token_id']] = current_balance + size
print('******** TRADE FILLED, BAL UPDATED ********* ')
else:
print('******** ORDER APPEND TO LOCAL - LIVE ********* ')
LOCAL_ACTIVE_ORDERS.append(d)
elif d['errorMsg'] == "invalid post-only order: order crosses book":
await cancel_all_orders(CLIENT=CLIENT)
logging.info(f'invalid post-only order: order crosses book. posted: {OrderArgs_list[idx].price}')
else:
await cancel_all_orders(CLIENT=CLIENT)
raise ValueError(f'Order entry failed: {d}')
logging.info(f'Order Posted Resp: {response}')
print(f'Order Posted Resp: {response}')
return response
### Routes ###
async def no_orders(entry_or_exit: str = 'ENTRY'):
global ORDER_LOCK
### Check for Price Bands ###
up_px = float(POLY_CLOB.get('price', 0))
down_px = float(POLY_CLOB_DOWN.get('price', 0))
if entry_or_exit == 'ENTRY':
if (up_px > MAX_ALLOWED_POLY_PX) or (down_px > MAX_ALLOWED_POLY_PX):
logging.info(f'Outside max allowed px: {MAX_ALLOWED_POLY_PX}')
return False
if entry_or_exit == 'ENTRY':
### Check for Index vs. Target Px ###
tgt_px = float(POLY_CLOB.get('target_price', 0))
ref_px = float(POLY_REF.get('value'))
tgt_px_diff_to_index = ( abs( tgt_px - ref_px ) / tgt_px)
if tgt_px_diff_to_index > (TGT_PX_INDEX_DIFF_THRESH / 100):
logging.info(f'Tgt Diff to Index Outside Limit ({TGT_PX_INDEX_DIFF_THRESH}%); Diff {tgt_px_diff_to_index:.4%}; Index: {ref_px:.2f}; Tgt: {tgt_px:.2f}')
return False
### Check Slope ###
slope_bool, slope_side = await slope_decision()
if not slope_bool:
logging.info('Failed Slope Check')
return False
token_id_up = POLY_CLOB.get('token_id_up', None)
token_id_down = POLY_CLOB.get('token_id_down', None)
### Order Entry ###
if slope_side == 'UP':
if entry_or_exit == 'ENTRY':
side = BUY
size = DEFAULT_ORDER_SIZE
up_px = up_px + 0.01
down_px = down_px - TGT_PROFIT_CENTS
up_post_only = False
down_post_only = False # T
else: # entry_or_exit == 'EXIT'
side = SELL
size = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
up_px = up_px + TGT_PROFIT_CENTS
down_px = down_px - 0.01
up_post_only = False # T
down_post_only = False
else: # slope_side == 'DOWN'
if entry_or_exit == 'ENTRY':
side = BUY
size = DEFAULT_ORDER_SIZE
up_px = up_px - TGT_PROFIT_CENTS
down_px = down_px + 0.01
up_post_only = False # T
down_post_only = False
else:
side = SELL
size = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
up_px = up_px - 0.01
down_px = down_px + TGT_PROFIT_CENTS
up_post_only = False
down_post_only = False # T
buy_up_leg = Custom_OrderArgs(
token_id=token_id_up,
price=up_px,
size=size,
side=side,
max_price = 0.99,
post_only=up_post_only
)
buy_down_leg = Custom_OrderArgs(
token_id=token_id_down,
price=down_px,
size=size,
side=side,
max_price = 0.99,
post_only=down_post_only
)
order_list = [buy_up_leg, buy_down_leg]
### ADD CHECK FOR MKT MOVED AWAY FROM OPPORTNITY ###
if ORDER_LOCK:
logging.info(f'BUY ORDER BLOCKED BY LOCK: {order_list}')
else:
logging.info(f'Attempting BUY Order {order_list}')
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = order_list
)
ORDER_LOCK = ORDER_LOCK + 1
async def active_orders_no_positions_route():
global LOCAL_ACTIVE_ORDERS
if len(LOCAL_ACTIVE_ORDERS) > 2:
logging.critical('More than two active orders, shutting down')
await kill_algo()
b_c = 0
s_c = 0
active_buy_up = False
active_buy_down = False
active_sell_up = False
active_sell_down = False
for o in LOCAL_ACTIVE_ORDERS:
if o['side'] == 'BUY':
if o['token_id']==POLY_CLOB['token_id_up']:
active_buy_up = True
else: # o['token_id']==POLY_CLOB['token_id_down']
active_buy_down = True
b_c = b_c + 1
elif o['side'] == 'SELL':
if o['token_id']==POLY_CLOB['token_id_up']:
active_sell_up = True
else: # o['token_id']==POLY_CLOB['token_id_down']
active_sell_down = True
s_c = s_c + 1
if (b_c > 2) or (s_c > 2):
logging.critical(f'More than two active buys or more than two active sells: b_c {b_c}; s_c{s_c}')
await kill_algo()
for o in LOCAL_ACTIVE_ORDERS:
logging.info(f'Working on order ({o['side']}): {o['orderID']}')
if o.get('status').upper() == 'MATCHED':
# logging.info('Order is matched, awaiting confirm or kickback')
if active_buy_up and active_buy_down:
logging.info('BUY UP AND BUY DOWN ACTIVE/MATCHED - WAITING FOR CONFIRMS')
continue
logging.info('Order is matched, ordering inverse side')
order_matched=True
elif o.get('status').upper() == 'FAILED':
order_matched=True
raise ValueError(f'Trade FAILED after matching: {o}')
elif o.get('status').upper() == 'RETRYING':
order_matched=True
raise ValueError(f'Trade RETRYING after matching: {o}')
else:
order_matched = False
orig_px = float(o['price'])
orig_size = float(o['size'])
### BUY
if o['side'] == 'BUY':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
else:
clob_px = float(POLY_CLOB_DOWN['price'])
if (clob_px >= orig_px) or order_matched:
if (clob_px >= orig_px):
logging.info(f"Market px: ({clob_px} is above buy order px: {orig_px:.2f})")
if (o.get('max_price', 0) > clob_px) or order_matched:
if (o.get('max_price', 0) > clob_px):
logging.info(f"Market px: ({clob_px} has moved too far away from original target, cancelling and resetting algo: {o.get('max_price', 0) :.2f})")
if not order_matched:
order_matched = await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
if order_matched:
o['status'] = 'MATCHED'
if order_matched and ( active_buy_up and active_buy_down ):
logging.info('BUY UP AND BUY DOWN MATCHED - WAITING FOR CONFIRMS (IN LOOP)')
continue
else:
token_id = o['token_id']
px = clob_px+0.01
max_price = o['max_price']
post_only = False
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id,
price=px,
size=orig_size,
side=BUY,
max_price=max_price,
post_only=post_only
)]
)
else:
await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
### SELL
elif o['side'] == 'SELL':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
else:
clob_px = float(POLY_CLOB_DOWN['price'])
if (clob_px <= orig_px) or order_matched:
if (clob_px <= orig_px):
logging.info(f"Market px: ({clob_px} is below sell order px: {orig_px:.2f})")
if not order_matched:
order_matched = await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
if order_matched:
o['status'] = 'MATCHED'
if order_matched and ( active_buy_up and active_buy_down ):
logging.info('SELL UP AND SELL DOWN MATCHED - WAITING FOR CONFIRMS (IN LOOP)')
continue
if not order_matched:
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=o['token_id'],
price=orig_px-0.01,
size=orig_size,
side=SELL,
max_price = 0.00
)]
)
else:
await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
async def no_orders_active_positions_route():
'''
Succesful Buy, now neeed to take profit and exit
'''
global LOCAL_TOKEN_BALANCES
OrderArgs_list = []
logging.warning(f'LOCAL_TOKEN_BALANCES: {LOCAL_TOKEN_BALANCES}')
for k, v in LOCAL_TOKEN_BALANCES.items():
size = await get_balance_by_token_id(CLIENT=CLIENT, token_id=k)
if size >= MIN_ORDER_SIZE:
if POLY_CLOB['token_id_up'] == k:
clob_px = float(POLY_CLOB['price'])
else:
clob_px = float(POLY_CLOB_DOWN['price'])
OrderArgs_list.append(
Custom_OrderArgs(
token_id=k,
price=clob_px + TGT_PROFIT_CENTS,
size=size,
side='SELL',
)
)
else:
LOCAL_TOKEN_BALANCES[k] = 0.00
logging.info(f'Wants to flatten small amount, skipping: {v}')
if OrderArgs_list:
logging.info(f'Posting orders to close: {OrderArgs_list}')
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = OrderArgs_list
)
async def active_orders_active_positions_route():
pass
async def kill_algo(msg: str = 'No kill msg provided'):
logging.info('Killing algo...')
await cancel_all_orders(CLIENT=CLIENT)
await flatten_open_positions(
CLIENT=CLIENT,
token_id_up = POLY_CLOB.get('token_id_up', None),
token_id_down = POLY_CLOB.get('token_id_down', None),
)
logging.info(f'...algo killed: {msg}')
raise Exception(f'Algo Killed: {msg}')
async def run_algo():
global POLY_BINANCE
global POLY_REF
global POLY_CLOB
global POLY_CLOB_DOWN
global USER_TRADES
global USER_ORDERS
global SLOPE_HIST
global ACTIVE_BALANCES_EXIST
global LOCAL_ACTIVE_ORDERS
global LOCAL_TOKEN_BALANCES
# global LOCAL_ACTIVE_POSITIONS
print(f'token_id_up: {POLY_CLOB.get('token_id_up', None)}')
print(f'token_id_down: {POLY_CLOB.get('token_id_down', None)}')
POLY_CLOB = json.loads(VAL_KEY.get('poly_5min_btcusd'))
### Check for missing target px (Poly 5min Target BTC Px Target) ###
if POLY_CLOB.get('target_price', 0) <= 1.00:
kill_algo('')
ACTIVE_BALANCES_EXIST = await check_for_open_positions(
CLIENT=CLIENT,
token_id_up=POLY_CLOB.get('token_id_up', None),
token_id_down=POLY_CLOB.get('token_id_down', None),
)
try:
while True:
loop_start = time.time()
print('__________Start___________')
POLY_BINANCE = json.loads(VAL_KEY.get('poly_binance_btcusd'))
POLY_REF = json.loads(VAL_KEY.get('poly_rtds_cl_btcusd'))
POLY_CLOB = json.loads(VAL_KEY.get('poly_5min_btcusd'))
POLY_CLOB_DOWN = json.loads(VAL_KEY.get('poly_5min_btcusd_down'))
USER_TRADES = VAL_KEY.get('poly_user_trades')
USER_TRADES = json.loads(USER_TRADES) if USER_TRADES is not None else []
USER_ORDERS = VAL_KEY.get('poly_user_orders')
USER_ORDERS = json.loads(USER_ORDERS) if USER_ORDERS is not None else []
### Manage Local vs User Stream Orders ###
# print(f'LOCAL_ACTIVE_ORDERS: {LOCAL_ACTIVE_ORDERS}')
# print(f'USER_TRADES: {USER_TRADES}')
print(f'Len of Active Orders/Matched: {len(LOCAL_ACTIVE_ORDERS)}; User Trades: {len(USER_TRADES)}')
for idx, o in enumerate(LOCAL_ACTIVE_ORDERS):
user_order = next((item for item in USER_ORDERS if item["id"] == o['orderID']), None)
user_trade = next( ( item for item in USER_TRADES if ( o['orderID'] == item['taker_order_id'] ) or ( o["orderID"] == json.loads(item['maker_orders'])[0]['order_id'] ) ), None )
### ^ ASSUMPTION BROKEN - MANY IN THIS LIST SO CANT ASSUME FIRST MAKER
print(f'*****USER TRADE: {user_trade}')
if user_trade is not None:
trade_status = str(user_trade['status']).upper()
logging.info(f'Updated Trade Status: {o['status']} --> {trade_status}; {o['orderID']}')
if trade_status == 'CONFIRMED':
LOCAL_ACTIVE_ORDERS.pop(idx)
token_id = user_trade['asset_id']
current_balance = float(LOCAL_TOKEN_BALANCES.get(token_id, 0.00))
if user_trade['side'] == 'BUY':
size = float(user_trade['size'])
else:
size = float(user_trade['size']) * -1
LOCAL_TOKEN_BALANCES[token_id] = current_balance + size
# px = user_trade['price']
# LOCAL_ACTIVE_POSITIONS.append({
# 'token_id': token_id,
# 'order_id': o['orderID'],
# 'associate_trades': user_order['associate_trades'],
# 'size_matched': user_order['size_matched'],
# 'price': px,
# 'timestamp_value': user_order['timestamp'],
# })
logging.info('Order FILLED!')
elif trade_status == 'MATCHED':
logging.info(f'Order Matched...awaiting confirm: {trade_status}')
elif trade_status == 'MINED':
logging.info(f'Order Mined ...awaiting confirm: {trade_status}')
else:
logging.info(f'Trade status but not filled: trade= {user_trade}; order={o}')
elif user_order is not None:
order_status = str(user_order['status']).upper()
o['status'] = order_status
logging.info(f'Updated Order Status: {o['status']} --> {order_status}; {o['orderID']}')
if order_status == 'MATCHED':
logging.info('Order MATCHED, awaiting confirm')
elif order_status == 'CANCELED':
LOCAL_ACTIVE_ORDERS.pop(idx)
logging.info('Order Canceled')
else:
logging.info('Order Live')
token_id_up = POLY_CLOB.get('token_id_up', 0)
token_id_down = POLY_CLOB.get('token_id_down', 0)
if (token_id_up is None) or (token_id_down is None):
print('Missing Token Ids for Market, sleeping 1 sec and retrying...')
time.sleep(1)
ACTIVE_BALANCES_EXIST = {}
continue
else:
if (LOCAL_TOKEN_BALANCES.get(token_id_up) is None):
LOCAL_TOKEN_BALANCES[token_id_up] = 0.00
if (LOCAL_TOKEN_BALANCES.get(token_id_down) is None):
LOCAL_TOKEN_BALANCES[token_id_down] = 0.00
ACTIVE_BALANCES_EXIST = (LOCAL_TOKEN_BALANCES.get(token_id_up) > 0) or (LOCAL_TOKEN_BALANCES.get(token_id_down) > 0)
### Check for Endtime Buffer ###
if ENDTIME_BUFFER_SEC > POLY_CLOB.get('sec_remaining', 0):
if LOCAL_ACTIVE_ORDERS:
print('buffer zone - orders cancel')
await cancel_all_orders(CLIENT=CLIENT)
if ACTIVE_BALANCES_EXIST:
print('buffer zone - flatten positions')
await flatten_open_positions(
CLIENT=CLIENT,
token_id_up = POLY_CLOB.get('token_id_up', None),
token_id_down = POLY_CLOB.get('token_id_down', None),
)
print('buffer zone, sleeping until next session')
time.sleep(1)
continue
### Execution Route ###
if not(LOCAL_ACTIVE_ORDERS) and not(ACTIVE_BALANCES_EXIST): # No Orders, No Positions
print('ROUTE: no_orders_no_positions_route')
await no_orders(entry_or_exit='ENTRY')
### Open Orders Route ###
elif LOCAL_ACTIVE_ORDERS and not(ACTIVE_BALANCES_EXIST): # Orders, No Positions
print('ROUTE: active_orders_no_positions_route')
# await active_orders_no_positions_route()
### Open Positions Route ###
elif not(LOCAL_ACTIVE_ORDERS) and ACTIVE_BALANCES_EXIST: # No Orders, Positions
print('ROUTE: no_orders_active_positions_route')
# await no_orders(entry_or_exit='EXIT')
### Open Orders and Open Positions Route ###
else:
print('ROUTE: active_orders_active_positions_route - BETA')
# await active_orders_no_positions_route() # Orders and Positions
print(f'__________________________ (Algo Engine ms: {(time.time() - loop_start)*1000})')
time.sleep(1)
except KeyboardInterrupt:
print('...algo stopped')
await cancel_all_orders(CLIENT=CLIENT)
except Exception as e:
logging.critical(f'*** ALGO ENGINE CRASHED: {e}')
logging.error(traceback.format_exc())
await cancel_all_orders(CLIENT=CLIENT)
async def main():
global CLIENT
global VAL_KEY
global CON
CLIENT = api.create_client()
VAL_KEY = valkey.Valkey(host='localhost', port=6379, db=0, decode_responses=True)
engine = create_async_engine('mysql+asyncmy://root:pwd@localhost/polymarket')
async with engine.connect() as CON:
await create_executions_orders_table(CON=CON)
await run_algo()
if __name__ == '__main__':
START_TIME = round(datetime.now().timestamp()*1000)
logging.info(f'Log FilePath: {LOG_FILEPATH}')
logging.basicConfig(
force=True,
filename=LOG_FILEPATH,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
filemode='w'
)
logging.info(f"STARTED: {START_TIME}")
asyncio.run(main())

931
main.py

File diff suppressed because it is too large Load Diff

2
ng.py
View File

@@ -21,7 +21,7 @@ RH_PAIR = 'USD'
DEFAULT_TO_DARKMODE: bool = True
ALLOW_BODY_SCROLL: bool = True
LOOKBACK: int = 60
LOOKBACK_RT_TV_MAX_POINTS: int = 300
LOOKBACK_RT_TV_MAX_POINTS: int = 3000
REFRESH_INTERVAL_SEC: int = 10
REFRESH_INTERVAL_RT_SEC: int = 1/30

View File

@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 134,
"execution_count": 1,
"id": "c0bfb3b5",
"metadata": {},
"outputs": [],
@@ -15,13 +15,13 @@
"import json\n",
"from dataclasses import dataclass\n",
"\n",
"from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs, PartialCreateOrderOptions, BalanceAllowanceParams\n",
"from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs, PartialCreateOrderOptions, BalanceAllowanceParams, OpenOrderParams\n",
"from py_clob_client.order_builder.constants import BUY, SELL\n"
]
},
{
"cell_type": "code",
"execution_count": 135,
"execution_count": 2,
"id": "7d7dc787",
"metadata": {},
"outputs": [],
@@ -49,17 +49,17 @@
},
{
"cell_type": "code",
"execution_count": 136,
"execution_count": 3,
"id": "c3e07e21",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Timestamp('2026-03-31 05:45:00')"
"Timestamp('2026-04-04 05:15:00')"
]
},
"execution_count": 136,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
@@ -74,74 +74,74 @@
},
{
"cell_type": "code",
"execution_count": 137,
"execution_count": 4,
"id": "10671da4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'id': '1787714',\n",
" 'question': 'Bitcoin Up or Down - March 31, 1:45AM-1:50AM ET',\n",
" 'conditionId': '0xd1773b412dacad884c202a7b14f0197918b1e22028ce2b5737fbd659bbe150f0',\n",
" 'slug': 'btc-updown-5m-1774935900',\n",
"{'id': '1840714',\n",
" 'question': 'Bitcoin Up or Down - April 4, 1:15AM-1:20AM ET',\n",
" 'conditionId': '0xa71ed436d160cc45bf182b9004e0c10b16322ea1b41375182b747c2629223ecc',\n",
" 'slug': 'btc-updown-5m-1775279700',\n",
" 'resolutionSource': 'https://data.chain.link/streams/btc-usd',\n",
" 'endDate': '2026-03-31T05:50:00Z',\n",
" 'liquidity': '12631.9812',\n",
" 'startDate': '2026-03-30T05:53:51.811773Z',\n",
" 'endDate': '2026-04-04T05:20:00Z',\n",
" 'liquidity': '19009.3694',\n",
" 'startDate': '2026-04-03T05:23:41.149918Z',\n",
" 'image': 'https://polymarket-upload.s3.us-east-2.amazonaws.com/BTC+fullsize.png',\n",
" 'icon': 'https://polymarket-upload.s3.us-east-2.amazonaws.com/BTC+fullsize.png',\n",
" 'description': 'This market will resolve to \"Up\" if the Bitcoin price at the end of the time range specified in the title is greater than or equal to the price at the beginning of that range. Otherwise, it will resolve to \"Down\".\\nThe resolution source for this market is information from Chainlink, specifically the BTC/USD data stream available at https://data.chain.link/streams/btc-usd.\\nPlease note that this market is about the price according to Chainlink data stream BTC/USD, not according to other sources or spot markets.',\n",
" 'outcomes': '[\"Up\", \"Down\"]',\n",
" 'outcomePrices': '[\"0.875\", \"0.125\"]',\n",
" 'volume': '94249.88157999996',\n",
" 'outcomePrices': '[\"0.505\", \"0.495\"]',\n",
" 'volume': '1149.1770909999996',\n",
" 'active': True,\n",
" 'closed': False,\n",
" 'marketMakerAddress': '',\n",
" 'createdAt': '2026-03-30T05:52:34.18484Z',\n",
" 'updatedAt': '2026-03-31T05:48:51.799961Z',\n",
" 'createdAt': '2026-04-03T05:22:26.236646Z',\n",
" 'updatedAt': '2026-04-04T05:14:58.886334Z',\n",
" 'new': False,\n",
" 'featured': False,\n",
" 'archived': False,\n",
" 'restricted': True,\n",
" 'groupItemThreshold': '0',\n",
" 'questionID': '0x33d208062bed0d8fcf68d2f3899e528f103ad7e7763efc763f71c065ea6c842c',\n",
" 'questionID': '0x1f7b9fd2711422d90794895b99edcb93a81246afd56b08ee4736c9b57565f8f7',\n",
" 'enableOrderBook': True,\n",
" 'orderPriceMinTickSize': 0.01,\n",
" 'orderMinSize': 5,\n",
" 'volumeNum': 94249.88157999996,\n",
" 'liquidityNum': 12631.9812,\n",
" 'endDateIso': '2026-03-31',\n",
" 'startDateIso': '2026-03-30',\n",
" 'volumeNum': 1149.1770909999996,\n",
" 'liquidityNum': 19009.3694,\n",
" 'endDateIso': '2026-04-04',\n",
" 'startDateIso': '2026-04-03',\n",
" 'hasReviewedDates': True,\n",
" 'volume24hr': 93644.03624199987,\n",
" 'volume1wk': 93644.03624199987,\n",
" 'volume1mo': 93644.03624199987,\n",
" 'volume1yr': 93644.03624199987,\n",
" 'clobTokenIds': '[\"13157292356296687506747919717798752029699544499054519087985411865141996614822\", \"70507961363566124468475538524172170043725846352735387705515911177933084557518\"]',\n",
" 'volume24hrClob': 93644.03624199987,\n",
" 'volume1wkClob': 93644.03624199987,\n",
" 'volume1moClob': 93644.03624199987,\n",
" 'volume1yrClob': 93644.03624199987,\n",
" 'volumeClob': 94249.88157999996,\n",
" 'liquidityClob': 12631.9812,\n",
" 'volume24hr': 1149.1770909999998,\n",
" 'volume1wk': 1149.1770909999998,\n",
" 'volume1mo': 1149.1770909999998,\n",
" 'volume1yr': 1149.1770909999998,\n",
" 'clobTokenIds': '[\"111612048087962925846397645788043113901565915142888535086349545305985085081594\", \"12874695654084258339187997850118078073676562138805309130550135898707856234061\"]',\n",
" 'volume24hrClob': 1149.1770909999998,\n",
" 'volume1wkClob': 1149.1770909999998,\n",
" 'volume1moClob': 1149.1770909999998,\n",
" 'volume1yrClob': 1149.1770909999998,\n",
" 'volumeClob': 1149.1770909999996,\n",
" 'liquidityClob': 19009.3694,\n",
" 'makerBaseFee': 1000,\n",
" 'takerBaseFee': 1000,\n",
" 'acceptingOrders': True,\n",
" 'negRisk': False,\n",
" 'ready': False,\n",
" 'funded': False,\n",
" 'acceptingOrdersTimestamp': '2026-03-30T05:52:46Z',\n",
" 'acceptingOrdersTimestamp': '2026-04-03T05:22:35Z',\n",
" 'cyom': False,\n",
" 'competitive': 0.8767123287671234,\n",
" 'competitive': 0.9999750006249843,\n",
" 'pagerDutyNotificationEnabled': False,\n",
" 'approved': True,\n",
" 'rewardsMinSize': 50,\n",
" 'rewardsMaxSpread': 4.5,\n",
" 'spread': 0.01,\n",
" 'lastTradePrice': 0.89,\n",
" 'bestBid': 0.87,\n",
" 'bestAsk': 0.88,\n",
" 'lastTradePrice': 0.51,\n",
" 'bestBid': 0.5,\n",
" 'bestAsk': 0.51,\n",
" 'automaticallyActive': True,\n",
" 'clearBookOnStart': False,\n",
" 'showGmpSeries': False,\n",
@@ -152,7 +152,7 @@
" 'pendingDeployment': False,\n",
" 'deploying': False,\n",
" 'rfqEnabled': False,\n",
" 'eventStartTime': '2026-03-31T05:45:00Z',\n",
" 'eventStartTime': '2026-04-04T05:15:00Z',\n",
" 'holdingRewardsEnabled': False,\n",
" 'feesEnabled': True,\n",
" 'requiresTranslation': False,\n",
@@ -164,7 +164,7 @@
" 'rebateRate': 0.2}}"
]
},
"execution_count": 137,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
@@ -175,22 +175,22 @@
},
{
"cell_type": "code",
"execution_count": 132,
"execution_count": 5,
"id": "5ba43ffc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'Up': '29663568421665501825278796284809925893978140634751674792176179244450686939029',\n",
" 'Down': '17234806616394620691850452772328817031586809400835664344689152810552758258009',\n",
"{'Up': '111612048087962925846397645788043113901565915142888535086349545305985085081594',\n",
" 'Down': '12874695654084258339187997850118078073676562138805309130550135898707856234061',\n",
" 'isActive': False,\n",
" 'MinTickSize': 0.01,\n",
" 'isNegRisk': False,\n",
" 'ConditionId': '0x1778b4a38f2ce99260f9d3d0d78729d37fbd24439e06e6c92aad429439e0f7b2'}"
" 'ConditionId': '0xa71ed436d160cc45bf182b9004e0c10b16322ea1b41375182b747c2629223ecc'}"
]
},
"execution_count": 132,
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -201,7 +201,7 @@
},
{
"cell_type": "code",
"execution_count": 124,
"execution_count": 6,
"id": "5d356d3b",
"metadata": {},
"outputs": [
@@ -210,7 +210,7 @@
"output_type": "stream",
"text": [
"creating client...\n",
"You've made 55 trades\n",
"You've made 297 trades\n",
"client created successfully!\n"
]
}
@@ -221,17 +221,51 @@
},
{
"cell_type": "code",
"execution_count": 128,
"execution_count": null,
"id": "22eb81de",
"metadata": {},
"outputs": [],
"source": [
"# Filtered by market\n",
"order_status = client.get_orders(\n",
" OpenOrderParams(id=\"0x9249ce4a8bc67de355b487b00eaa6ce25c1b451867f9350672b25eaa1de08494\")\n",
")[0]['status']"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "fb3b8151",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'CANCELED'"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"order"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "de5ccc3a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"7.6829"
"0.0"
]
},
"execution_count": 128,
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
@@ -366,11 +400,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
"[{'errorMsg': '', 'orderID': '0x575c43f35b1f5e3e01779df5293d987dc81a347a4e09423a856ecb45555e30cb', 'takingAmount': '', 'makingAmount': '', 'status': 'live', 'success': True}]\n"
"[{'errorMsg': '', 'orderID': '0x0c701329ddd7881505648c5ebdd03cd6f86ae3a70b0cf150bcb53946e043e6bf', 'takingAmount': '', 'makingAmount': '', 'status': 'live', 'success': True}]\n"
]
}
],
"source": [
"%%time\n",
"### POST \n",
"response = client.post_orders([\n",
" PostOrdersArgs(\n",
@@ -1465,25 +1500,100 @@
},
{
"cell_type": "code",
"execution_count": 1,
"id": "56b8e1cc",
"execution_count": 35,
"id": "4d524867",
"metadata": {},
"outputs": [],
"source": [
"o = {'type': 'TRADE', 'id': '1de1c277-d281-4be5-a388-305beb95e713', 'taker_order_id': '0xc77331796ad40133a2b4d9a387c10d326c180ad1195306240416150e337f0376', 'market': '0x1cdd4f44f73da702120f02962bf02a2599a7573a39b05ac8ca12a24301542e3e', 'asset_id': '108194336731497303295771496985972597853032131719077291707737599874190461476381', 'side': 'BUY', 'size': '5', 'fee_rate_bps': '1000', 'price': '0.7', 'status': 'CONFIRMED', 'match_time': '1775025187', 'last_update': '1775025253', 'outcome': 'Up', 'owner': '00e5d36c-6c46-77e1-a436-0f0a4bfbfdd8', 'trade_owner': '00e5d36c-6c46-77e1-a436-0f0a4bfbfdd8', 'maker_address': '0xb2967A7e578E700E27611238B7F762BdADC72CcB', 'transaction_hash': '0x3654fac56e1548bcc14d01ce4888ea0c3cec29d553009e054fc67088ece5f5b3', 'bucket_index': 0, 'maker_orders': [{'order_id': '0xb9a39a5e8082846bfdd92d33fba5112466b939ad7f33b76905982549767acf0a', 'owner': '70dd335a-6089-6022-6726-565c7480b291', 'maker_address': '0x010138da36CF100c00a5A59C8643E4A4A55DF19C', 'matched_amount': '5', 'price': '0.3', 'fee_rate_bps': '1000', 'asset_id': '26175835004768067043908573558643253609047604517388456461023977022509795794691', 'outcome': 'Down', 'outcome_index': 0, 'side': 'BUY'}], 'trader_side': 'TAKER', 'timestamp': '1775025253290', 'event_type': 'trade'}"
"o = {'orderID': '0xaebd4053bd167eb7a7fc48ae29036829582787a73d8cc7b8b1afa7294c474972',\n",
" 'owner': '00e5d36c-6c46-77e1-a436-0f0a4bfbfdd8',\n",
" 'market': '0xf856ff89eb9ed2ab393a1bbc496b5db539b4d7f9cec91202b13c97379e9e58d6',\n",
" 'asset_id': '39378292107289994981363071337831788209917841322683175778910172170676449806535',\n",
" 'side': 'BUY',\n",
" 'order_owner': '00e5d36c-6c46-77e1-a436-0f0a4bfbfdd8',\n",
" 'original_size': '10',\n",
" 'size_matched': '0',\n",
" 'price': '0.2',\n",
" 'associate_trades': [],\n",
" 'outcome': 'Up',\n",
" 'type': 'CANCELLATION',\n",
" 'created_at': '1774818626',\n",
" 'expiration': '0',\n",
" 'order_type': 'GTC',\n",
" 'status': 'CANCELED',\n",
" 'maker_address': '0xb2967A7e578E700E27611238B7F762BdADC72CcB',\n",
" 'timestamp': '1774818630291',\n",
" 'event_type': 'order'}"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "43a68ee8",
"metadata": {},
"outputs": [],
"source": [
"ut = {'trade_side':'MAKER', 'taker_order_id': None, 'maker_orders': [{\"side\": \"BUY\", \"owner\": \"f44394d9-7782-e5e5-af99-dd515edd7fd9\", \"price\": \"0.44\", \"outcome\": \"Up\", \"asset_id\": \"55598909213399021321632159985071802901933471635502091907595118948537230110477\", \"order_id\": \"0x7eed6fa75cd49680b738e1563fc9e5dc0f7095c8a7dd3ee1a496c01f4ad2f610\", \"fee_rate_bps\": \"1000\", \"maker_address\": \"0xE29042f5D913DCC4015aaB3455C13C58514CA33F\", \"outcome_index\": 0, \"matched_amount\": \"15.25\"}, {\"side\": \"BUY\", \"owner\": \"520cb8f0-a71b-1c49-8dd6-751e682ee7f8\", \"price\": \"0.44\", \"outcome\": \"Up\", \"asset_id\": \"55598909213399021321632159985071802901933471635502091907595118948537230110477\", \"order_id\": \"0xf7c0a9e322fbf232dce6290f36bbe5e484ccec7fda599ddeb98867f241df6e37\", \"fee_rate_bps\": \"1000\", \"maker_address\": \"0x74a6364297292774c7f9a16B925207E77eEE262D\", \"outcome_index\": 0, \"matched_amount\": \"5\"}, {\"side\": \"BUY\", \"owner\": \"ae0f07ea-bcbe-3d54-6841-f220e89794ae\", \"price\": \"0.44\", \"outcome\": \"Up\", \"asset_id\": \"55598909213399021321632159985071802901933471635502091907595118948537230110477\", \"order_id\": \"0xe321494520de4737980a15160bfae94cb48791a2dc978aa843e7a8504e815771\", \"fee_rate_bps\": \"1000\", \"maker_address\": \"0xDba9C86F8d20ac73BcBf4dedaA6ADbd26A0a1303\", \"outcome_index\": 0, \"matched_amount\": \"5\"}, {\"side\": \"BUY\", \"owner\": \"00e5d36c-6c46-77e1-a436-0f0a4bfbfdd8\", \"price\": \"0.44\", \"outcome\": \"Up\", \"asset_id\": \"55598909213399021321632159985071802901933471635502091907595118948537230110477\", \"order_id\": \"0xaebd4053bd167eb7a7fc48ae29036829582787a73d8cc7b8b1afa7294c474972\", \"fee_rate_bps\": \"1000\", \"maker_address\": \"0xb2967A7e578E700E27611238B7F762BdADC72CcB\", \"outcome_index\": 0, \"matched_amount\": \"4.75\"}]}"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "ae50f082",
"metadata": {},
"outputs": [],
"source": [
"USER_TRADES = [ut]\n",
"user_trade = next( ( item for item in USER_TRADES if ( o['orderID'] == item['taker_order_id'] ) or ( o[\"orderID\"] == item['maker_orders'][0]['order_id'] ) ), None )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae50f082",
"id": "11c111eb",
"metadata": {},
"outputs": [],
"source": [
"USER_TRADES = [o]\n",
"user_trade = next( ( item for item in USER_TRADES if ( o['orderID'] == item['taker_order_id'] ) or ( o[\"orderID\"] == item['maker_orders'][0]['order_id'] ) ), None )"
"for t in USER_TRADES:\n",
" if t['trade_side']=='MAKER':\n",
" pass\n",
" elif t['taker_order_id'] == o[\"orderID\"]:\n",
" pass\n"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "de38feda",
"metadata": {},
"outputs": [],
"source": [
"user_trade"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "67b7b730",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "d15d92d3",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,

View File

@@ -36,7 +36,7 @@ LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Polymarket_Binance_Trades.log'
### Globals ###
WSS_URL = "wss://stream.binance.com:9443/ws/BTCUSDT@aggTrade"
HIST_TRADES = np.empty((0, 3))
HIST_TRADES_LOOKBACK_SEC = 5
HIST_TRADES_LOOKBACK_SEC = 6
### Database Funcs ###
async def create_rtds_btcusd_table(
@@ -132,7 +132,8 @@ async def binance_trades_stream():
last_px = float(data['p'])
qty = float(data['q'])
# print(f'🤑 BTC Binance Last Px: {last_px:_.4f}; TS: {pd.to_datetime(data['T'], unit='ms')}')
HIST_TRADES = np.append(HIST_TRADES, np.array([[timestamp_value, last_px, qty]]), axis=0)
# HIST_TRADES = np.append(HIST_TRADES, np.array([[timestamp_value, last_px, qty]]), axis=0)
HIST_TRADES = np.append(HIST_TRADES, np.array([[ts_arrival, last_px, qty]]), axis=0)
hist_trades_lookback_ts_ms = round(datetime.now().timestamp() - HIST_TRADES_LOOKBACK_SEC)*1000
HIST_TRADES = HIST_TRADES[HIST_TRADES[:, 0] >= hist_trades_lookback_ts_ms]
VAL_KEY_OBJ = json.dumps({

View File

@@ -13,6 +13,7 @@ from typing import AsyncContextManager
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import text
import valkey
import time
import os
from dotenv import load_dotenv
@@ -27,7 +28,7 @@ VAL_KEY = None
### Logging ###
load_dotenv()
LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Polymarket_5min.log'
LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Polymarket_CLOB.log'
WSS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
SLUG_END_TIME = 0
@@ -67,10 +68,10 @@ def get_mkt_details_by_slug(slug: str) -> dict[str, str, str]: # {'Up' : 123, 'D
d['ConditionId'] = market['conditionId']
d['EndDateTime'] = market['endDate']
# d['Liquidity'] = market['liquidity']
d['LiquidityClob'] = market['liquidityClob']
d['VolumeNum'] = market['volumeNum']
d['Volume24hr'] = market['volume24hr']
print(market)
# d['LiquidityClob'] = market['liquidityClob']
# d['VolumeNum'] = market['volumeNum']
# d['Volume24hr'] = market['volume24hr']
logging.info(f'MARKET CHANGED: {market}')
return d, market
@@ -197,6 +198,7 @@ async def polymarket_stream():
sec_remaining = SLUG_END_TIME - round(datetime.now().timestamp())
if sec_remaining <= 0:
time.sleep(0.1)
ref_data = json.loads(VAL_KEY.get('poly_rtds_cl_btcusd'))
TARGET_PX = float(ref_data['value'])
HIST_TRADES = np.empty((0, 2))
@@ -316,15 +318,15 @@ async def polymarket_stream():
continue
elif event_type == "market_resolved":
print(f"Received: {event_type}")
print(data)
# print(data)
continue
elif event_type == "tick_size_change": # may want for CLOB order routing
print(f"Received: {event_type}")
print(data)
# print(data)
continue
else:
print(f"*********** REC UNMAPPED EVENT: {event_type}")
print(data)
# print(data)
continue
elif isinstance(data, dict):
continue

View File

@@ -246,7 +246,7 @@ async def insert_user_orders_table(
### Helpers ###
def live_orders_only(orders: list[dict]) -> list[dict]:
return [d for d in orders if d.get('status')=='LIVE']
return [d for d in orders if d.get('status') in ['LIVE','MATCHED']]
def upsert_list_of_dicts_by_id(list_of_dicts, new_dict):
for index, item in enumerate(list_of_dicts):
@@ -284,7 +284,6 @@ async def polymarket_stream():
await websocket.send(json.dumps(subscribe_msg))
print("Subscribed to User Data")
try:
async for message in websocket:
ts_arrival = round(datetime.now().timestamp()*1000)
@@ -294,8 +293,8 @@ async def polymarket_stream():
await websocket.send(json.dumps({}))
print('SENT HEARTBEAT PING')
continue
data['timestamp_arrival'] = ts_arrival
data['timestamp_arrival'] = ts_arrival
event_type = data.get('event_type', None)
match event_type:
case 'trade':
@@ -326,15 +325,15 @@ async def polymarket_stream():
LOOKBACK_MIN_TS_MS = ts_arrival-LOCAL_RECENT_TRADES_LOOKBACK_SEC*1000
LOCAL_RECENT_TRADES = [t for t in LOCAL_RECENT_TRADES if t.get('timestamp_arrival', 0) >= LOOKBACK_MIN_TS_MS]
# print("---------------------")
# print(LOCAL_RECENT_TRADES)
# print("---------------------")
VAL_KEY_OBJ = json.dumps(LOCAL_RECENT_TRADES)
# VAL_KEY.publish(VK_CHANNEL, VAL_KEY_OBJ)
logging.info("----------LOCAL_RECENT_TRADES-VK-----------")
logging.info(VAL_KEY_OBJ)
logging.info("-------------------------------------------")
VAL_KEY.set(VK_RECENT_TRADES, VAL_KEY_OBJ)
logging.info(f'User Trade Update: {data}')
# logging.info(f'User Trade Update: {data}')
### Insert into DB ###
await insert_user_trades_table(