diff --git a/data/PEV 3.11-10.26.xlsx b/data/PEV 3.11-10.26.xlsx
new file mode 100644
index 0000000..d7fae57
Binary files /dev/null and b/data/PEV 3.11-10.26.xlsx differ
diff --git a/pev_eda.ipynb b/pev_eda.ipynb
index 477f159..f6dbde9 100644
--- a/pev_eda.ipynb
+++ b/pev_eda.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@@ -14,87 +14,34 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
- "config_file_path = 'config\\mysql_config.json'\n",
- "mysql_config = MysqlConfig.parse_file(config_file_path)\n",
- "dao = Database(mysql_config)\n",
"\n",
- "# query\n",
- "select_query = \"SELECT * FROM bet.oddsjam_order where bet_status in ('won', 'lost');\"\n",
- "raw_data_list = dao.fetchall(query=select_query)\n",
- "order_data_list = [OddsJamOrder(**data).model_dump() for data in raw_data_list]"
+ "def get_oddsjam_order_data_from_db()->List:\n",
+ " config_file_path = 'config\\mysql_config.json'\n",
+ " mysql_config = MysqlConfig.parse_file(config_file_path)\n",
+ " dao = Database(mysql_config)\n",
+ "\n",
+ " select_query = \"SELECT * FROM bet.oddsjam_order where bet_status in ('won', 'lost');\"\n",
+ " raw_data_list = dao.fetchall(query=select_query)\n",
+ " order_data_list = [OddsJamOrder(**data).model_dump() for data in raw_data_list]\n",
+ "\n"
]
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{'id': 'edge:10012-40335-2024-08-31:1st_half_team_total:oud-heverlee_leuven_over_0_5:oud-heverlee_leuven_under_0_5',\n",
- " 'bet_id': 'edge:10012-40335-2024-08-31:1st_half_team_total:oud-heverlee_leuven_over_0_5:oud-heverlee_leuven_under_0_5',\n",
- " 'game_id': '10012-40335-2024-08-31',\n",
- " 'away_bet_name': 'Oud-Heverlee Leuven Under 0.5',\n",
- " 'home_bet_name': 'Oud-Heverlee Leuven Over 0.5',\n",
- " 'away_no_vig_price': 102.85,\n",
- " 'home_no_vig_price': -102.85,\n",
- " 'away_price': -110.0,\n",
- " 'home_price': -102.0,\n",
- " 'away_sportsbooks': ['FanDuel', 'DraftKings'],\n",
- " 'home_sportsbooks': ['Bovada'],\n",
- " 'is_live': False,\n",
- " 'in_game_status': None,\n",
- " 'period': None,\n",
- " 'clock': None,\n",
- " 'last_play': None,\n",
- " 'home_score': 0,\n",
- " 'away_score': 0,\n",
- " 'sport': 'Soccer',\n",
- " 'league': 'Belgium - Jupiler Pro League',\n",
- " 'market': '1st Half Team Total',\n",
- " 'market_width': 22.0,\n",
- " 'percentage': 0.41,\n",
- " 'start_date': datetime.datetime(2024, 9, 1, 2, 45),\n",
- " 'home_team': 'Oud-Heverlee Leuven',\n",
- " 'away_team': 'Royal Standard de Liège',\n",
- " 'timestamp': 1725109490.1882415,\n",
- " 'away_deep_link_map': '{\"FanDuel\": {\"urls\": {\"ios\": {\"url\": \"https://sportsbook.fanduel.com/addToBetslip?marketId=42.441130559&selectionId=7044483\", \"adds_to_slip\": true}, \"android\": {\"url\": \"https://sportsbook.fanduel.com/addToBetslip?marketId=42.441130559&selectionId=7044483\", \"adds_to_slip\": true}, \"desktop\": {\"url\": \"https://sportsbook.fanduel.com/addToBetslip?marketId=42.441130559&selectionId=7044483\", \"adds_to_slip\": true}}, \"mobile\": \"https://sportsbook.fanduel.com/addToBetslip?marketId=42.441130559&selectionId=7044483\", \"desktop\": \"https://sportsbook.fanduel.com/addToBetslip?marketId=42.441130559&selectionId=7044483\"}, \"DraftKings\": {\"urls\": {\"ios\": {\"url\": \"dksb://sb/addbet/0OU76429572U50_3\", \"adds_to_slip\": true}, \"android\": {\"url\": \"dksb://sb/addbet/0OU76429572U50_3\", \"adds_to_slip\": true}, \"desktop\": {\"url\": \"https://sportsbook.draftkings.com/event/30960358?outcomes=0OU76429572U50_3\", \"adds_to_slip\": true}}, \"mobile\": \"dksb://sb/addbet/0OU76429572U50_3\", \"desktop\": \"https://sportsbook.draftkings.com/event/30960358?outcomes=0OU76429572U50_3\"}}',\n",
- " 'home_deep_link_map': '{}',\n",
- " 'status': 'unplayed',\n",
- " 'away_edge_percent': None,\n",
- " 'bet_placed': False,\n",
- " 'same_market_bet_placed': False,\n",
- " 'same_game_bet_placed': False,\n",
- " 'away_rec_size': None,\n",
- " 'rec_size': 1,\n",
- " 'home_edge_percent': 0.41,\n",
- " 'order_status': 0,\n",
- " 'amount': None,\n",
- " 'create_time': '20240831211007',\n",
- " 'sportsbook_orderid': None,\n",
- " 'home_or_away': 'home',\n",
- " 'start_timestamp': 1725129900000,\n",
- " 'selected_sportsbook': 'Bovada',\n",
- " 'bet_status': 'won'}"
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "order_data_list[1]"
+ "simulation_data = get_oddsjam_order_data_from_db()"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
@@ -103,7 +50,7 @@
},
{
"cell_type": "code",
- "execution_count": 176,
+ "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@@ -124,14 +71,13 @@
},
{
"cell_type": "code",
- "execution_count": 153,
+ "execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def get_odds(row):\n",
" home_or_away = row['home_or_away']\n",
" price = row[f'{home_or_away}_price'] / 100\n",
- "\n",
" if price >= 0:\n",
" return price\n",
" else:\n",
@@ -140,7 +86,7 @@
},
{
"cell_type": "code",
- "execution_count": 154,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
@@ -149,16 +95,16 @@
},
{
"cell_type": "code",
- "execution_count": 144,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "3.4551825216755248"
+ "3.5232254542910955"
]
},
- "execution_count": 144,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
@@ -169,19 +115,19 @@
},
{
"cell_type": "code",
- "execution_count": 133,
+ "execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"bet_status\n",
- "lost 13439\n",
- "won 5902\n",
+ "lost 19316\n",
+ "won 8249\n",
"dtype: int64"
]
},
- "execution_count": 133,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
@@ -267,19 +213,19 @@
},
{
"cell_type": "code",
- "execution_count": 168,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"bet_status\n",
- "lost 932\n",
- "won 848\n",
+ "lost 1231\n",
+ "won 1080\n",
"dtype: int64"
]
},
- "execution_count": 168,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -384,71 +330,6 @@
"db_df[db_df['bet_status'] == 'lost']['odds2'].describe()"
]
},
- {
- "cell_type": "code",
- "execution_count": 116,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "count 19341.000000\n",
- "mean 392.987177\n",
- "std 1713.715890\n",
- "min 5.000000\n",
- "25% 33.000000\n",
- "50% 75.000000\n",
- "75% 244.000000\n",
- "max 49049.000000\n",
- "Name: market_width, dtype: float64"
- ]
- },
- "execution_count": 116,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "db_df['market_width'].describe()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 45,
- "metadata": {},
- "outputs": [],
- "source": [
- "lost_df = db_df[db_df['outcome'] == -1]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 49,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "count 13439.000000\n",
- "mean 517.244661\n",
- "std 2026.572578\n",
- "min 5.000000\n",
- "25% 40.000000\n",
- "50% 105.000000\n",
- "75% 348.000000\n",
- "max 49049.000000\n",
- "Name: market_width, dtype: float64"
- ]
- },
- "execution_count": 49,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "lost_df['market_width'].describe()"
- ]
- },
{
"cell_type": "code",
"execution_count": 19,
@@ -460,7 +341,1030 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "data_df = db_df.copy()\n",
+ "data_df = data_df[data_df['market_width'] <= 25]\n",
+ "data_df = data_df[data_df['market_width'] >= 20]\n",
+ "# data_df = data_df[data_df['selected_sportsbook'] == '1XBet']\n",
+ "data_df['investment'] = 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "odds_df = data_df.groupby('date').agg({'odds2': 'mean'}).reset_index()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.plotly.v1+json": {
+ "config": {
+ "plotlyServerURL": "https://plot.ly"
+ },
+ "data": [
+ {
+ "name": "lost",
+ "type": "bar",
+ "x": [
+ "2024-08-26T00:00:00",
+ "2024-08-27T00:00:00",
+ "2024-08-28T00:00:00",
+ "2024-08-29T00:00:00",
+ "2024-08-30T00:00:00",
+ "2024-08-31T00:00:00",
+ "2024-09-01T00:00:00",
+ "2024-09-02T00:00:00",
+ "2024-09-03T00:00:00",
+ "2024-09-04T00:00:00",
+ "2024-09-05T00:00:00"
+ ],
+ "y": [
+ 11,
+ 96,
+ 138,
+ 109,
+ 190,
+ 99,
+ 289,
+ 62,
+ 89,
+ 98,
+ 50
+ ],
+ "yaxis": "y"
+ },
+ {
+ "name": "won",
+ "type": "bar",
+ "x": [
+ "2024-08-26T00:00:00",
+ "2024-08-27T00:00:00",
+ "2024-08-28T00:00:00",
+ "2024-08-29T00:00:00",
+ "2024-08-30T00:00:00",
+ "2024-08-31T00:00:00",
+ "2024-09-01T00:00:00",
+ "2024-09-02T00:00:00",
+ "2024-09-03T00:00:00",
+ "2024-09-04T00:00:00",
+ "2024-09-05T00:00:00"
+ ],
+ "y": [
+ 12,
+ 113,
+ 94,
+ 79,
+ 178,
+ 88,
+ 284,
+ 59,
+ 56,
+ 80,
+ 37
+ ],
+ "yaxis": "y"
+ },
+ {
+ "mode": "markers+lines",
+ "name": "平均赔率",
+ "type": "scatter",
+ "x": [
+ "2024-08-26T00:00:00",
+ "2024-08-27T00:00:00",
+ "2024-08-28T00:00:00",
+ "2024-08-29T00:00:00",
+ "2024-08-30T00:00:00",
+ "2024-08-31T00:00:00",
+ "2024-09-01T00:00:00",
+ "2024-09-02T00:00:00",
+ "2024-09-03T00:00:00",
+ "2024-09-04T00:00:00",
+ "2024-09-05T00:00:00"
+ ],
+ "y": [
+ 1.1965734109952426,
+ 1.2294773511597243,
+ 1.3513840696836157,
+ 1.209601147300343,
+ 1.1063211834713325,
+ 1.2904563185996685,
+ 1.0492181007177963,
+ 1.2070565768132386,
+ 1.154097538043856,
+ 1.1587947147909168,
+ 1.2470557464128864
+ ],
+ "yaxis": "y2"
+ }
+ ],
+ "layout": {
+ "barmode": "group",
+ "legend": {
+ "title": {
+ "text": "Variables"
+ }
+ },
+ "template": {
+ "data": {
+ "bar": [
+ {
+ "error_x": {
+ "color": "#2a3f5f"
+ },
+ "error_y": {
+ "color": "#2a3f5f"
+ },
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "bar"
+ }
+ ],
+ "barpolar": [
+ {
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "barpolar"
+ }
+ ],
+ "carpet": [
+ {
+ "aaxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "baxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "type": "carpet"
+ }
+ ],
+ "choropleth": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "choropleth"
+ }
+ ],
+ "contour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "contour"
+ }
+ ],
+ "contourcarpet": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "contourcarpet"
+ }
+ ],
+ "heatmap": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmap"
+ }
+ ],
+ "heatmapgl": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmapgl"
+ }
+ ],
+ "histogram": [
+ {
+ "marker": {
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "histogram"
+ }
+ ],
+ "histogram2d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2d"
+ }
+ ],
+ "histogram2dcontour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2dcontour"
+ }
+ ],
+ "mesh3d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "mesh3d"
+ }
+ ],
+ "parcoords": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "parcoords"
+ }
+ ],
+ "pie": [
+ {
+ "automargin": true,
+ "type": "pie"
+ }
+ ],
+ "scatter": [
+ {
+ "fillpattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ },
+ "type": "scatter"
+ }
+ ],
+ "scatter3d": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatter3d"
+ }
+ ],
+ "scattercarpet": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattercarpet"
+ }
+ ],
+ "scattergeo": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergeo"
+ }
+ ],
+ "scattergl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergl"
+ }
+ ],
+ "scattermapbox": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattermapbox"
+ }
+ ],
+ "scatterpolar": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolar"
+ }
+ ],
+ "scatterpolargl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolargl"
+ }
+ ],
+ "scatterternary": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterternary"
+ }
+ ],
+ "surface": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "surface"
+ }
+ ],
+ "table": [
+ {
+ "cells": {
+ "fill": {
+ "color": "#EBF0F8"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "header": {
+ "fill": {
+ "color": "#C8D4E3"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "type": "table"
+ }
+ ]
+ },
+ "layout": {
+ "annotationdefaults": {
+ "arrowcolor": "#2a3f5f",
+ "arrowhead": 0,
+ "arrowwidth": 1
+ },
+ "autotypenumbers": "strict",
+ "coloraxis": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "colorscale": {
+ "diverging": [
+ [
+ 0,
+ "#8e0152"
+ ],
+ [
+ 0.1,
+ "#c51b7d"
+ ],
+ [
+ 0.2,
+ "#de77ae"
+ ],
+ [
+ 0.3,
+ "#f1b6da"
+ ],
+ [
+ 0.4,
+ "#fde0ef"
+ ],
+ [
+ 0.5,
+ "#f7f7f7"
+ ],
+ [
+ 0.6,
+ "#e6f5d0"
+ ],
+ [
+ 0.7,
+ "#b8e186"
+ ],
+ [
+ 0.8,
+ "#7fbc41"
+ ],
+ [
+ 0.9,
+ "#4d9221"
+ ],
+ [
+ 1,
+ "#276419"
+ ]
+ ],
+ "sequential": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "sequentialminus": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ]
+ },
+ "colorway": [
+ "#636efa",
+ "#EF553B",
+ "#00cc96",
+ "#ab63fa",
+ "#FFA15A",
+ "#19d3f3",
+ "#FF6692",
+ "#B6E880",
+ "#FF97FF",
+ "#FECB52"
+ ],
+ "font": {
+ "color": "#2a3f5f"
+ },
+ "geo": {
+ "bgcolor": "white",
+ "lakecolor": "white",
+ "landcolor": "#E5ECF6",
+ "showlakes": true,
+ "showland": true,
+ "subunitcolor": "white"
+ },
+ "hoverlabel": {
+ "align": "left"
+ },
+ "hovermode": "closest",
+ "mapbox": {
+ "style": "light"
+ },
+ "paper_bgcolor": "white",
+ "plot_bgcolor": "#E5ECF6",
+ "polar": {
+ "angularaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "radialaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "scene": {
+ "xaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "yaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "zaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ }
+ },
+ "shapedefaults": {
+ "line": {
+ "color": "#2a3f5f"
+ }
+ },
+ "ternary": {
+ "aaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "baxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "caxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "title": {
+ "x": 0.05
+ },
+ "xaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ },
+ "yaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ }
+ }
+ },
+ "title": {
+ "text": "Comparison of Two Variables Across Categories"
+ },
+ "xaxis": {
+ "title": {
+ "text": "日期"
+ }
+ },
+ "yaxis": {
+ "title": {
+ "text": "金额"
+ }
+ },
+ "yaxis2": {
+ "overlaying": "y",
+ "side": "right",
+ "title": {
+ "text": "收益率"
+ }
+ }
+ }
+ }
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "\n",
+ "\n",
+ "df = pd.pivot_table(data_df, index=['date'], columns=['bet_status'], aggfunc='size', fill_value=0).reset_index()\n",
+ "df = df.sort_values(by='date')\n",
+ "date_x = df['date'].tolist()\n",
+ "# 创建Plotly图形对象\n",
+ "fig = go.Figure()\n",
+ "\n",
+ "cols = df.columns[1:]\n",
+ "for col in cols:\n",
+ " y_data = df[col].tolist()\n",
+ " # 添加第一个变量的数据\n",
+ " fig.add_trace(go.Bar(\n",
+ " x=date_x,\n",
+ " y=y_data,\n",
+ " name=col,\n",
+ " # marker_color='indianred' # 设置颜色\n",
+ " yaxis='y1'\n",
+ " ))\n",
+ "\n",
+ "fig.add_trace(go.Scatter(\n",
+ " x=odds_df['date'],\n",
+ " y=odds_df['odds2'],\n",
+ " mode='markers+lines',\n",
+ " name='平均赔率',\n",
+ " yaxis='y2'\n",
+ "))\n",
+ "\n",
+ "# 更新布局\n",
+ "fig.update_layout(\n",
+ " barmode='group', # 将柱状图设置为并排显示\n",
+ " title='Comparison of Two Variables Across Categories',\n",
+ " xaxis=dict(title='日期'),\n",
+ " yaxis=dict(title='金额'),\n",
+ " yaxis2=dict(title='收益率', overlaying='y', side='right'),\n",
+ " legend_title='Variables'\n",
+ ")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
"metadata": {},
"outputs": [
{
@@ -484,414 +1388,540 @@
" \n",
" \n",
" \n",
" \n",
" \n",
- " away_team \n",
- " best_price_away_name \n",
- " best_price_away_odd \n",
- " best_price_away_odd_books_new \n",
- " best_price_home_name \n",
- " best_price_home_odd \n",
- " best_price_home_odd_books_new \n",
- " home_team \n",
- " league \n",
- " market \n",
- " sport \n",
- " date \n",
- " weighted_price_away_odd \n",
- " weighted_price_home_odd \n",
- " handicap to go \n",
+ " id \n",
+ " bet_id \n",
+ " game_id \n",
+ " away_bet_name \n",
+ " home_bet_name \n",
+ " away_no_vig_price \n",
+ " home_no_vig_price \n",
+ " away_price \n",
+ " home_price \n",
+ " away_sportsbooks \n",
+ " ... \n",
+ " sportsbook_orderid \n",
+ " home_or_away \n",
+ " start_timestamp \n",
+ " selected_sportsbook \n",
+ " bet_status \n",
" outcome \n",
- " odds US \n",
- " odds EU \n",
" benefit \n",
+ " date \n",
+ " odds2 \n",
+ " investment \n",
"
37469 rows × 19 columns
\n", + "10 rows × 50 columns
\n", "" ], "text/plain": [ - " away_team best_price_away_name \\\n", - "0 FC Augsburg Under 4.5 \n", - "1 FC Augsburg FC Bayern Munich Under 3.5 \n", - "2 FC Augsburg FC Bayern Munich Under 1.5 \n", - "6 Liverpool Bournemouth Under 0.5 \n", - "8 FC Augsburg Under 3.5 \n", - "... ... ... \n", - "80358 New Orleans Pelicans Memphis Grizzlies +1.5 \n", - "80360 Dallas Mavericks San Antonio Spurs -0.5 \n", - "80361 Dallas Mavericks San Antonio Spurs +0.5 \n", - "80363 Portland Trail Blazers Los Angeles Clippers Under 60.5 \n", - "80365 Portland Trail Blazers Los Angeles Clippers -3.5 \n", + " id \\\n", + "1 edge:10012-40335-2024-08-31:1st_half_team_tota... \n", + "9 edge:10012-40335-2024-08-31:total_goals:over_2... \n", + "15 edge:10035-41288-2024-08-31:total_goals:over_2... \n", + "19 edge:10068-27381-24-35:point_spread:northweste... \n", + "25 edge:10068-27381-24-35:total_points:over_53_5:... \n", + "26 edge:10068-27381-24-35:total_points:over_53:un... \n", + "27 edge:10068-27381-24-35:total_points:over_54_5:... \n", + "28 edge:10068-27381-24-35:total_points:over_54:un... \n", + "30 edge:10068-27381-24-35:total_points:over_55:un... \n", + "32 edge:10068-27381-24-35:total_points:over_56:un... \n", "\n", - " best_price_away_odd best_price_away_odd_books_new \\\n", - "0 -150 OddsJam,William Hill,Caesars \n", - "1 -137 OddsJam \n", - "2 -135 DraftKings,10bet,DraftKings (Tennessee) \n", - "6 132 FanDuel \n", - "8 141 OddsJam \n", - "... ... ... \n", - "80358 -143 TonyBet \n", - "80360 148 FanDuel \n", - "80361 128 FanDuel \n", - "80363 -116 Pinny,Pinnacle \n", - "80365 104 Unibet,BetRivers,betPARX \n", + " bet_id game_id \\\n", + "1 edge:10012-40335-2024-08-31:1st_half_team_tota... 10012-40335-2024-08-31 \n", + "9 edge:10012-40335-2024-08-31:total_goals:over_2... 10012-40335-2024-08-31 \n", + "15 edge:10035-41288-2024-08-31:total_goals:over_2... 10035-41288-2024-08-31 \n", + "19 edge:10068-27381-24-35:point_spread:northweste... 10068-27381-24-35 \n", + "25 edge:10068-27381-24-35:total_points:over_53_5:... 10068-27381-24-35 \n", + "26 edge:10068-27381-24-35:total_points:over_53:un... 10068-27381-24-35 \n", + "27 edge:10068-27381-24-35:total_points:over_54_5:... 10068-27381-24-35 \n", + "28 edge:10068-27381-24-35:total_points:over_54:un... 10068-27381-24-35 \n", + "30 edge:10068-27381-24-35:total_points:over_55:un... 10068-27381-24-35 \n", + "32 edge:10068-27381-24-35:total_points:over_56:un... 10068-27381-24-35 \n", "\n", - " best_price_home_name best_price_home_odd \\\n", - "0 Over 4.5 162 \n", - "1 FC Bayern Munich Over 3.5 146 \n", - "2 FC Bayern Munich Over 1.5 128 \n", - "6 Bournemouth Over 0.5 -137 \n", - "8 Over 3.5 -138 \n", - "... ... ... \n", - "80358 New Orleans Pelicans -1.5 135 \n", - "80360 Dallas Mavericks +0.5 -155 \n", - "80361 Dallas Mavericks -0.5 -132 \n", - "80363 Los Angeles Clippers Over 60.5 110 \n", - "80365 Portland Trail Blazers +3.5 -110 \n", + " away_bet_name home_bet_name \\\n", + "1 Oud-Heverlee Leuven Under 0.5 Oud-Heverlee Leuven Over 0.5 \n", + "9 Under 2.5 Over 2.5 \n", + "15 Under 2.5 Over 2.5 \n", + "19 Tulsa -37.5 Northwestern State +37.5 \n", + "25 Under 53.5 Over 53.5 \n", + "26 Under 53 Over 53 \n", + "27 Under 54.5 Over 54.5 \n", + "28 Under 54 Over 54 \n", + "30 Under 55 Over 55 \n", + "32 Under 56 Over 56 \n", "\n", - " best_price_home_odd_books_new home_team \\\n", - "0 FanDuel FC Bayern Munich \n", - "1 FanDuel FC Bayern Munich \n", - "2 FanDuel FC Bayern Munich \n", - "6 Barstool Bournemouth \n", - "8 FanDuel FC Bayern Munich \n", - "... ... ... \n", - "80358 BetMGM,partypoker,Borgata Memphis Grizzlies \n", - "80360 Pinny,Pinnacle San Antonio Spurs \n", - "80361 Pinny,Pinnacle San Antonio Spurs \n", - "80363 partypoker,BetMGM,Borgata Los Angeles Clippers \n", - "80365 BetAnySports,LowVig,BetOnline,SuperBook Los Angeles Clippers \n", + " away_no_vig_price home_no_vig_price away_price home_price \\\n", + "1 102.85 -102.85 -110.0 -102.0 \n", + "9 -101.35 101.35 -102.0 105.0 \n", + "15 -121.90 121.90 -134.0 124.0 \n", + "19 100.40 -100.40 105.0 -110.0 \n", + "25 132.39 -132.39 122.0 -130.0 \n", + "26 109.70 -109.70 110.0 -110.0 \n", + "27 114.29 -114.29 105.0 -114.0 \n", + "28 122.41 -122.41 112.0 -122.0 \n", + "30 -112.29 112.29 -110.0 110.0 \n", + "32 -104.24 104.24 -112.0 105.0 \n", "\n", - " league market sport \\\n", - "0 Germany - Bundesliga Total Goals soccer \n", - "1 Germany - Bundesliga Team Total soccer \n", - "2 Germany - Bundesliga 1st Half Team Total soccer \n", - "6 England - Premier League Team Total soccer \n", - "8 Germany - Bundesliga Total Goals soccer \n", - "... ... ... ... \n", - "80358 NBA 1st Half Point Spread Basketball \n", - "80360 NBA 1st Half Point Spread Basketball \n", - "80361 NBA 1st Half Point Spread Basketball \n", - "80363 NBA 1st Half Team Total Basketball \n", - "80365 NBA 1st Quarter Point Spread Basketball \n", + " away_sportsbooks ... sportsbook_orderid home_or_away \\\n", + "1 [FanDuel, DraftKings] ... None home \n", + "9 [Bodog, Bovada] ... None home \n", + "15 [FanDuel] ... None home \n", + "19 [betPARX, BetRivers] ... None away \n", + "25 [DraftKings] ... None home \n", + "26 [betPARX, BetRivers] ... None away \n", + "27 [Fanatics] ... None home \n", + "28 [DraftKings] ... None home \n", + "30 [BookMaker] ... None away \n", + "32 [DraftKings] ... None home \n", "\n", - " date weighted_price_away_odd weighted_price_home_odd \\\n", - "0 2023-03-11 -141.153 142.032 \n", - "1 2023-03-11 -126.848 127.536 \n", - "2 2023-03-11 -123.407 123.898 \n", - "6 2023-03-11 141.875 -141.519 \n", - "8 2023-03-11 147.467 -146.976 \n", - "... ... ... ... \n", - "80358 2023-10-26 -133.490 133.546 \n", - "80360 2023-10-26 146.604 -146.127 \n", - "80361 2023-10-26 126.875 -126.419 \n", - "80363 2023-10-26 -106.549 106.565 \n", - "80365 2023-10-26 103.013 -102.757 \n", + " start_timestamp selected_sportsbook bet_status outcome benefit \\\n", + "1 1725129900000 Bovada won 1 0.980392 \n", + "9 1725129900000 BetOnline lost -1 -1.000000 \n", + "15 1725129000000 BetOnline won 1 1.240000 \n", + "19 1724976000000 betPARX lost -1 -1.000000 \n", + "25 1724976000000 betPARX won 1 0.769231 \n", + "26 1724976000000 betPARX lost -1 -1.000000 \n", + "27 1724976000000 betPARX won 1 0.877193 \n", + "28 1724976000000 BetRivers won 1 0.819672 \n", + "30 1724976000000 BookMaker lost -1 -1.000000 \n", + "32 1724976000000 betPARX won 1 1.050000 \n", "\n", - " handicap to go outcome odds US odds EU benefit \n", - "0 Over 4.5 1.0 162 1.620000 1.620000 \n", - "1 FC Bayern Munich Over 3.5 1.0 146 1.460000 1.460000 \n", - "2 FC Bayern Munich Over 1.5 1.0 128 1.280000 1.280000 \n", - "6 Bournemouth Over 0.5 1.0 -137 0.729927 0.729927 \n", - "8 Over 3.5 1.0 -138 0.724638 0.724638 \n", - "... ... ... ... ... ... \n", - "80358 New Orleans Pelicans -1.5 1.0 135 1.350000 1.350000 \n", - "80360 San Antonio Spurs -0.5 1.0 148 1.480000 1.480000 \n", - "80361 San Antonio Spurs +0.5 1.0 128 1.280000 1.280000 \n", - "80363 Los Angeles Clippers Over 60.5 1.0 110 1.100000 1.100000 \n", - "80365 Los Angeles Clippers -3.5 1.0 104 1.040000 1.040000 \n", + " date odds2 investment \n", + "1 2024-09-01 0.980392 1 \n", + "9 2024-09-01 1.050000 1 \n", + "15 2024-09-01 1.240000 1 \n", + "19 2024-08-30 1.050000 1 \n", + "25 2024-08-30 0.769231 1 \n", + "26 2024-08-30 1.100000 1 \n", + "27 2024-08-30 0.877193 1 \n", + "28 2024-08-30 0.819672 1 \n", + "30 2024-08-30 0.909091 1 \n", + "32 2024-08-30 1.050000 1 \n", "\n", - "[37469 rows x 19 columns]" + "[10 rows x 50 columns]" ] }, - "execution_count": 23, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "raw_df[raw_df['outcome'] == 1]" + "data_df.head(10)" ] }, { "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [], - "source": [ - "data_df = raw_df.copy()\n", - "data_df['investment'] = 1" - ] - }, - { - "cell_type": "code", - "execution_count": 179, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "data_df = db_df.copy()\n", - "data_df = data_df[data_df['market_width'] <= 25]\n", - "data_df = data_df[data_df['market_width'] >= 20]\n", - "# data_df = data_df[data_df['selected_sportsbook'] == '1XBet']\n", - "data_df['investment'] = 1" - ] - }, - { - "cell_type": "code", - "execution_count": 180, + "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "年化夏普率: 0.8002309699976565\n", - "ROI: 0.00683522830064485\n" + "status date active inactive\n", + "0 2024-01-01 2 1\n", + "1 2024-01-02 1 1\n", + "2 2024-01-03 0 1\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "# 示例数据\n", + "data = {\n", + " 'date': ['2024-01-01', '2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02', '2024-01-03'],\n", + " 'status': ['active', 'inactive', 'active', 'active', 'inactive', 'inactive']\n", + "}\n", + "\n", + "df = pd.DataFrame(data)\n", + "\n", + "# 将日期列转换为日期类型\n", + "df['date'] = pd.to_datetime(df['date'])\n", + "\n", + "# 使用 pivot_table 进行聚合\n", + "result = pd.pivot_table(df, values='status', index=['date'], columns=['status'], aggfunc='size', fill_value=0).reset_index()\n", + "\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bet_status date lost won\n", + "0 2024-08-26 11 12\n", + "1 2024-08-27 96 113\n", + "2 2024-08-28 138 94\n", + "3 2024-08-29 109 79\n", + "4 2024-08-30 190 178\n", + "5 2024-08-31 99 88\n", + "6 2024-09-01 289 284\n", + "7 2024-09-02 62 59\n", + "8 2024-09-03 89 56\n", + "9 2024-09-04 98 80\n", + "10 2024-09-05 50 37\n", + "Index(['date', 'lost', 'won'], dtype='object', name='bet_status')\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "\n", + "\n", + "# 使用 pivot_table 进行聚合\n", + "result = pd.pivot_table(data_df, index=['date'], columns=['bet_status'], aggfunc='size', fill_value=0).reset_index()\n", + "\n", + "print(result)\n", + "print(result.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "| \n", + " | date | \n", + "status | \n", + "
|---|---|---|
| 0 | \n", + "2024-01-01 | \n", + "active | \n", + "
| 1 | \n", + "2024-01-01 | \n", + "inactive | \n", + "
| 2 | \n", + "2024-01-01 | \n", + "active | \n", + "
| 3 | \n", + "2024-01-02 | \n", + "active | \n", + "
| 4 | \n", + "2024-01-02 | \n", + "inactive | \n", + "
| 5 | \n", + "2024-01-03 | \n", + "inactive | \n", + "