2031 lines
56 KiB
Plaintext
2031 lines
56 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 30,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"from datetime import datetime\n",
|
||
"from dao.Database import Database\n",
|
||
"from data_model import MysqlConfig, OddsJamOrder, OddsjamBet"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"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]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"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"
|
||
}
|
||
],
|
||
"source": [
|
||
"order_data_list[1]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"db_df = pd.DataFrame(order_data_list)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 176,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"def get_benefit(row):\n",
|
||
" home_or_away = row['home_or_away']\n",
|
||
" price = row[f'{home_or_away}_price'] / 100\n",
|
||
" if row['outcome'] == -1:\n",
|
||
" return -1\n",
|
||
" if price >= 0:\n",
|
||
" return price \n",
|
||
" else:\n",
|
||
" return 1 / abs(price) \n",
|
||
" \n",
|
||
"db_df['outcome'] = db_df['bet_status'].apply(lambda x: 1 if x == 'won' else -1)\n",
|
||
"db_df['benefit'] = db_df.apply(get_benefit, axis=1)\n",
|
||
"db_df['date'] = db_df['start_timestamp'].apply(lambda x: datetime.fromtimestamp(x // 1000).strftime(\"%Y-%m-%d\"))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 153,
|
||
"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",
|
||
" return 1 / abs(price) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 154,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"db_df['odds2'] = db_df.apply(get_odds, axis=1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 144,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"3.4551825216755248"
|
||
]
|
||
},
|
||
"execution_count": 144,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df['odds2'].mean()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 133,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"bet_status\n",
|
||
"lost 13439\n",
|
||
"won 5902\n",
|
||
"dtype: int64"
|
||
]
|
||
},
|
||
"execution_count": 133,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df.groupby('bet_status').size()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 130,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"3.4551825216755248"
|
||
]
|
||
},
|
||
"execution_count": 130,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df[db_df['bet_status'].isin(['won', 'lost'])]['benefit'].mean()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 149,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"-1477.1127282023094"
|
||
]
|
||
},
|
||
"execution_count": 149,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df[['home_price', 'away_price', 'home_or_away', 'bet_status', 'benefit']]['benefit']"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": []
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 166,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"count 1780.000000\n",
|
||
"mean 1.165759\n",
|
||
"std 0.338662\n",
|
||
"min 0.359712\n",
|
||
"25% 0.909091\n",
|
||
"50% 1.080000\n",
|
||
"75% 1.360000\n",
|
||
"max 4.000000\n",
|
||
"Name: odds2, dtype: float64"
|
||
]
|
||
},
|
||
"execution_count": 166,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df[(db_df['market_width'] <= 25) & (db_df['market_width'] >= 20)]['odds2'].describe()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 168,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"bet_status\n",
|
||
"lost 932\n",
|
||
"won 848\n",
|
||
"dtype: int64"
|
||
]
|
||
},
|
||
"execution_count": 168,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df[(db_df['market_width'] <= 25) & (db_df['market_width'] >= 20)].groupby(['bet_status']).size()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 171,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"0.4764044943820225"
|
||
]
|
||
},
|
||
"execution_count": 171,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"848 / (848+932)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 170,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"1.0318921348314607"
|
||
]
|
||
},
|
||
"execution_count": 170,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"848 / (848+932) * (1.166 + 1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 156,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"count 5902.000000\n",
|
||
"mean 2.026751\n",
|
||
"std 1.825651\n",
|
||
"min 0.166667\n",
|
||
"25% 1.020000\n",
|
||
"50% 1.430000\n",
|
||
"75% 2.200000\n",
|
||
"max 25.000000\n",
|
||
"Name: odds2, dtype: float64"
|
||
]
|
||
},
|
||
"execution_count": 156,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"db_df[db_df['bet_status'] == 'won']['odds2'].describe()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 157,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"count 13439.000000\n",
|
||
"mean 4.082506\n",
|
||
"std 3.955954\n",
|
||
"min 0.235294\n",
|
||
"25% 1.500000\n",
|
||
"50% 2.700000\n",
|
||
"75% 5.400000\n",
|
||
"max 35.000000\n",
|
||
"Name: odds2, dtype: float64"
|
||
]
|
||
},
|
||
"execution_count": 157,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"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,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"raw_df = pd.read_excel('PEV 3.11-10.26.xlsx', sheet_name='原始数据')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"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>away_team</th>\n",
|
||
" <th>best_price_away_name</th>\n",
|
||
" <th>best_price_away_odd</th>\n",
|
||
" <th>best_price_away_odd_books_new</th>\n",
|
||
" <th>best_price_home_name</th>\n",
|
||
" <th>best_price_home_odd</th>\n",
|
||
" <th>best_price_home_odd_books_new</th>\n",
|
||
" <th>home_team</th>\n",
|
||
" <th>league</th>\n",
|
||
" <th>market</th>\n",
|
||
" <th>sport</th>\n",
|
||
" <th>date</th>\n",
|
||
" <th>weighted_price_away_odd</th>\n",
|
||
" <th>weighted_price_home_odd</th>\n",
|
||
" <th>handicap to go</th>\n",
|
||
" <th>outcome</th>\n",
|
||
" <th>odds US</th>\n",
|
||
" <th>odds EU</th>\n",
|
||
" <th>benefit</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>FC Augsburg</td>\n",
|
||
" <td>Under 4.5</td>\n",
|
||
" <td>-150</td>\n",
|
||
" <td>OddsJam,William Hill,Caesars</td>\n",
|
||
" <td>Over 4.5</td>\n",
|
||
" <td>162</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>FC Bayern Munich</td>\n",
|
||
" <td>Germany - Bundesliga</td>\n",
|
||
" <td>Total Goals</td>\n",
|
||
" <td>soccer</td>\n",
|
||
" <td>2023-03-11</td>\n",
|
||
" <td>-141.153</td>\n",
|
||
" <td>142.032</td>\n",
|
||
" <td>Over 4.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>162</td>\n",
|
||
" <td>1.620000</td>\n",
|
||
" <td>1.620000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>FC Augsburg</td>\n",
|
||
" <td>FC Bayern Munich Under 3.5</td>\n",
|
||
" <td>-137</td>\n",
|
||
" <td>OddsJam</td>\n",
|
||
" <td>FC Bayern Munich Over 3.5</td>\n",
|
||
" <td>146</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>FC Bayern Munich</td>\n",
|
||
" <td>Germany - Bundesliga</td>\n",
|
||
" <td>Team Total</td>\n",
|
||
" <td>soccer</td>\n",
|
||
" <td>2023-03-11</td>\n",
|
||
" <td>-126.848</td>\n",
|
||
" <td>127.536</td>\n",
|
||
" <td>FC Bayern Munich Over 3.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>146</td>\n",
|
||
" <td>1.460000</td>\n",
|
||
" <td>1.460000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>FC Augsburg</td>\n",
|
||
" <td>FC Bayern Munich Under 1.5</td>\n",
|
||
" <td>-135</td>\n",
|
||
" <td>DraftKings,10bet,DraftKings (Tennessee)</td>\n",
|
||
" <td>FC Bayern Munich Over 1.5</td>\n",
|
||
" <td>128</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>FC Bayern Munich</td>\n",
|
||
" <td>Germany - Bundesliga</td>\n",
|
||
" <td>1st Half Team Total</td>\n",
|
||
" <td>soccer</td>\n",
|
||
" <td>2023-03-11</td>\n",
|
||
" <td>-123.407</td>\n",
|
||
" <td>123.898</td>\n",
|
||
" <td>FC Bayern Munich Over 1.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>128</td>\n",
|
||
" <td>1.280000</td>\n",
|
||
" <td>1.280000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>6</th>\n",
|
||
" <td>Liverpool</td>\n",
|
||
" <td>Bournemouth Under 0.5</td>\n",
|
||
" <td>132</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>Bournemouth Over 0.5</td>\n",
|
||
" <td>-137</td>\n",
|
||
" <td>Barstool</td>\n",
|
||
" <td>Bournemouth</td>\n",
|
||
" <td>England - Premier League</td>\n",
|
||
" <td>Team Total</td>\n",
|
||
" <td>soccer</td>\n",
|
||
" <td>2023-03-11</td>\n",
|
||
" <td>141.875</td>\n",
|
||
" <td>-141.519</td>\n",
|
||
" <td>Bournemouth Over 0.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>-137</td>\n",
|
||
" <td>0.729927</td>\n",
|
||
" <td>0.729927</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8</th>\n",
|
||
" <td>FC Augsburg</td>\n",
|
||
" <td>Under 3.5</td>\n",
|
||
" <td>141</td>\n",
|
||
" <td>OddsJam</td>\n",
|
||
" <td>Over 3.5</td>\n",
|
||
" <td>-138</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>FC Bayern Munich</td>\n",
|
||
" <td>Germany - Bundesliga</td>\n",
|
||
" <td>Total Goals</td>\n",
|
||
" <td>soccer</td>\n",
|
||
" <td>2023-03-11</td>\n",
|
||
" <td>147.467</td>\n",
|
||
" <td>-146.976</td>\n",
|
||
" <td>Over 3.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>-138</td>\n",
|
||
" <td>0.724638</td>\n",
|
||
" <td>0.724638</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",
|
||
" <td>...</td>\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",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>80358</th>\n",
|
||
" <td>New Orleans Pelicans</td>\n",
|
||
" <td>Memphis Grizzlies +1.5</td>\n",
|
||
" <td>-143</td>\n",
|
||
" <td>TonyBet</td>\n",
|
||
" <td>New Orleans Pelicans -1.5</td>\n",
|
||
" <td>135</td>\n",
|
||
" <td>BetMGM,partypoker,Borgata</td>\n",
|
||
" <td>Memphis Grizzlies</td>\n",
|
||
" <td>NBA</td>\n",
|
||
" <td>1st Half Point Spread</td>\n",
|
||
" <td>Basketball</td>\n",
|
||
" <td>2023-10-26</td>\n",
|
||
" <td>-133.490</td>\n",
|
||
" <td>133.546</td>\n",
|
||
" <td>New Orleans Pelicans -1.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>135</td>\n",
|
||
" <td>1.350000</td>\n",
|
||
" <td>1.350000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>80360</th>\n",
|
||
" <td>Dallas Mavericks</td>\n",
|
||
" <td>San Antonio Spurs -0.5</td>\n",
|
||
" <td>148</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>Dallas Mavericks +0.5</td>\n",
|
||
" <td>-155</td>\n",
|
||
" <td>Pinny,Pinnacle</td>\n",
|
||
" <td>San Antonio Spurs</td>\n",
|
||
" <td>NBA</td>\n",
|
||
" <td>1st Half Point Spread</td>\n",
|
||
" <td>Basketball</td>\n",
|
||
" <td>2023-10-26</td>\n",
|
||
" <td>146.604</td>\n",
|
||
" <td>-146.127</td>\n",
|
||
" <td>San Antonio Spurs -0.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>148</td>\n",
|
||
" <td>1.480000</td>\n",
|
||
" <td>1.480000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>80361</th>\n",
|
||
" <td>Dallas Mavericks</td>\n",
|
||
" <td>San Antonio Spurs +0.5</td>\n",
|
||
" <td>128</td>\n",
|
||
" <td>FanDuel</td>\n",
|
||
" <td>Dallas Mavericks -0.5</td>\n",
|
||
" <td>-132</td>\n",
|
||
" <td>Pinny,Pinnacle</td>\n",
|
||
" <td>San Antonio Spurs</td>\n",
|
||
" <td>NBA</td>\n",
|
||
" <td>1st Half Point Spread</td>\n",
|
||
" <td>Basketball</td>\n",
|
||
" <td>2023-10-26</td>\n",
|
||
" <td>126.875</td>\n",
|
||
" <td>-126.419</td>\n",
|
||
" <td>San Antonio Spurs +0.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>128</td>\n",
|
||
" <td>1.280000</td>\n",
|
||
" <td>1.280000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>80363</th>\n",
|
||
" <td>Portland Trail Blazers</td>\n",
|
||
" <td>Los Angeles Clippers Under 60.5</td>\n",
|
||
" <td>-116</td>\n",
|
||
" <td>Pinny,Pinnacle</td>\n",
|
||
" <td>Los Angeles Clippers Over 60.5</td>\n",
|
||
" <td>110</td>\n",
|
||
" <td>partypoker,BetMGM,Borgata</td>\n",
|
||
" <td>Los Angeles Clippers</td>\n",
|
||
" <td>NBA</td>\n",
|
||
" <td>1st Half Team Total</td>\n",
|
||
" <td>Basketball</td>\n",
|
||
" <td>2023-10-26</td>\n",
|
||
" <td>-106.549</td>\n",
|
||
" <td>106.565</td>\n",
|
||
" <td>Los Angeles Clippers Over 60.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>110</td>\n",
|
||
" <td>1.100000</td>\n",
|
||
" <td>1.100000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>80365</th>\n",
|
||
" <td>Portland Trail Blazers</td>\n",
|
||
" <td>Los Angeles Clippers -3.5</td>\n",
|
||
" <td>104</td>\n",
|
||
" <td>Unibet,BetRivers,betPARX</td>\n",
|
||
" <td>Portland Trail Blazers +3.5</td>\n",
|
||
" <td>-110</td>\n",
|
||
" <td>BetAnySports,LowVig,BetOnline,SuperBook</td>\n",
|
||
" <td>Los Angeles Clippers</td>\n",
|
||
" <td>NBA</td>\n",
|
||
" <td>1st Quarter Point Spread</td>\n",
|
||
" <td>Basketball</td>\n",
|
||
" <td>2023-10-26</td>\n",
|
||
" <td>103.013</td>\n",
|
||
" <td>-102.757</td>\n",
|
||
" <td>Los Angeles Clippers -3.5</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>104</td>\n",
|
||
" <td>1.040000</td>\n",
|
||
" <td>1.040000</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>37469 rows × 19 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"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",
|
||
"\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",
|
||
"\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",
|
||
"\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",
|
||
"\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",
|
||
"\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",
|
||
"\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",
|
||
"\n",
|
||
"[37469 rows x 19 columns]"
|
||
]
|
||
},
|
||
"execution_count": 23,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"raw_df[raw_df['outcome'] == 1]"
|
||
]
|
||
},
|
||
{
|
||
"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,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"年化夏普率: 0.8002309699976565\n",
|
||
"ROI: 0.00683522830064485\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"def clac_closing_balance(day_benefit_list, pre_balance=1000, pre_benefit=0):\n",
|
||
" closing_balance_list = []\n",
|
||
" for i, benefit in enumerate(day_benefit_list):\n",
|
||
" closing_balance = pre_balance + pre_benefit / 3 + benefit * 2 / 3\n",
|
||
" closing_balance_list.append(closing_balance)\n",
|
||
" pre_balance = closing_balance\n",
|
||
" pre_benefit = benefit\n",
|
||
" return closing_balance_list\n",
|
||
"\n",
|
||
"def calc_in_transit_funds_ratio(daily_investment_list, closing_balance_list, start_closing_balance=1000):\n",
|
||
" assert len(daily_investment_list) == len(closing_balance_list)\n",
|
||
" ratio_list = []\n",
|
||
" for i, daily_investment in enumerate(daily_investment_list):\n",
|
||
" if i == 0:\n",
|
||
" ratio = daily_investment / start_closing_balance\n",
|
||
" else:\n",
|
||
" ratio = daily_investment / closing_balance_list[i-1]\n",
|
||
" ratio_list.append(ratio)\n",
|
||
" return ratio_list\n",
|
||
"\n",
|
||
"\n",
|
||
"init_balance = 1000\n",
|
||
"res_df = data_df.groupby('date').agg({'investment':'sum', 'benefit':'sum'}).rename(columns={'investment':'当日投入', 'benefit':'日收益'}).reset_index()\n",
|
||
"res_df['日收益率'] = res_df['日收益'] / res_df['当日投入']\n",
|
||
"res_df['累计收益'] = res_df['日收益'].cumsum()\n",
|
||
"res_df['累计投入'] = res_df['当日投入'].cumsum()\n",
|
||
"res_df['累计收益率'] = res_df['累计收益'] / res_df['累计投入']\n",
|
||
"\n",
|
||
"day_benefit_list = res_df['日收益'].tolist()\n",
|
||
"closing_balance_list = clac_closing_balance(day_benefit_list=day_benefit_list, pre_balance=init_balance)\n",
|
||
"res_df['日末余额(1.6天结算)'] = closing_balance_list\n",
|
||
"\n",
|
||
"daily_investment_list = res_df['当日投入'].tolist()\n",
|
||
"res_df['在途资金比例'] = calc_in_transit_funds_ratio(daily_investment_list=daily_investment_list, closing_balance_list=closing_balance_list, start_closing_balance=init_balance)\n",
|
||
"annualized_sharpe_ratio = res_df['日收益'].sum() / init_balance / res_df['日收益率'].std() * ((365 / len(res_df))**0.5)\n",
|
||
"print(f'年化夏普率: {annualized_sharpe_ratio}')\n",
|
||
"roi = res_df['日收益'].sum() / res_df['当日投入'].sum()\n",
|
||
"print(f'ROI: {roi}')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 181,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.plotly.v1+json": {
|
||
"config": {
|
||
"plotlyServerURL": "https://plot.ly"
|
||
},
|
||
"data": [
|
||
{
|
||
"mode": "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"
|
||
],
|
||
"y": [
|
||
1002.6656885456886,
|
||
1029.320085562455,
|
||
1031.6353596927408,
|
||
1014.877157613626,
|
||
1004.9262841780602,
|
||
1010.5006139053265,
|
||
1012.8869095027875
|
||
],
|
||
"yaxis": "y"
|
||
},
|
||
{
|
||
"mode": "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"
|
||
],
|
||
"y": [
|
||
0.17384925297968776,
|
||
0.18095199109662177,
|
||
0.05703148399117068,
|
||
0.013933178120379116,
|
||
0.0027913825488691288,
|
||
0.01187018704065157,
|
||
0.00683522830064485
|
||
],
|
||
"yaxis": "y2"
|
||
}
|
||
],
|
||
"layout": {
|
||
"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": "日末余额(1.6天结算) 和 累计收益率 折线图"
|
||
},
|
||
"xaxis": {
|
||
"title": {
|
||
"text": "日期"
|
||
}
|
||
},
|
||
"yaxis": {
|
||
"title": {
|
||
"text": "金额"
|
||
}
|
||
},
|
||
"yaxis2": {
|
||
"overlaying": "y",
|
||
"side": "right",
|
||
"tickformat": ".1%",
|
||
"title": {
|
||
"text": "收益率"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import plotly.graph_objects as go\n",
|
||
"\n",
|
||
"res_df['日期'] = pd.to_datetime(res_df['date'])\n",
|
||
"\n",
|
||
"fig = go.Figure()\n",
|
||
"\n",
|
||
"# 添加日末余额(1.6天结算)的折线图\n",
|
||
"fig.add_trace(go.Scatter(\n",
|
||
" x=res_df['日期'],\n",
|
||
" y=res_df['日末余额(1.6天结算)'],\n",
|
||
" mode='lines',\n",
|
||
" name='日末余额',\n",
|
||
" yaxis='y1'\n",
|
||
"))\n",
|
||
"\n",
|
||
"# 添加日收益率的折线图\n",
|
||
"# fig.add_trace(go.Scatter(\n",
|
||
"# x=res_df['日期'],\n",
|
||
"# y=res_df['日收益率'],\n",
|
||
"# mode='lines',\n",
|
||
"# name='日收益率',\n",
|
||
"# yaxis='y2'\n",
|
||
"# ))\n",
|
||
"\n",
|
||
"# 添加累计收益率的折线图\n",
|
||
"fig.add_trace(go.Scatter(\n",
|
||
" x=res_df['日期'],\n",
|
||
" y=res_df['累计收益率'],\n",
|
||
" mode='lines',\n",
|
||
" name='累计收益率',\n",
|
||
" yaxis='y2'\n",
|
||
"))\n",
|
||
"\n",
|
||
"# 添加在途资金比例的折线图\n",
|
||
"# fig.add_trace(go.Scatter(\n",
|
||
"# x=res_df['日期'],\n",
|
||
"# y=res_df['在途资金比例'],\n",
|
||
"# mode='lines',\n",
|
||
"# name='在途资金比例',\n",
|
||
"# yaxis='y2'\n",
|
||
"# ))\n",
|
||
"\n",
|
||
"# 设置布局,添加第二个y轴\n",
|
||
"fig.update_layout(\n",
|
||
" title='日末余额(1.6天结算) 和 累计收益率 折线图',\n",
|
||
" xaxis=dict(title='日期'),\n",
|
||
" yaxis=dict(title='金额'),\n",
|
||
" yaxis2=dict(title='收益率', overlaying='y', side='right', tickformat='.1%')\n",
|
||
")\n",
|
||
"\n",
|
||
"\n",
|
||
"fig.show()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# 基于market width 进行分层, 然后计算年华夏普率值, 进行资金配比"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 74,
|
||
"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>outcome</th>\n",
|
||
" <th>count</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>-1.0</td>\n",
|
||
" <td>39838</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>37469</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>2804</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>-0.5</td>\n",
|
||
" <td>164</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>0.5</td>\n",
|
||
" <td>91</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" outcome count\n",
|
||
"0 -1.0 39838\n",
|
||
"4 1.0 37469\n",
|
||
"2 0.0 2804\n",
|
||
"1 -0.5 164\n",
|
||
"3 0.5 91"
|
||
]
|
||
},
|
||
"execution_count": 74,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"raw_df.groupby('outcome').agg({'away_team': 'count'}).rename(columns={'away_team': 'count'}).reset_index().sort_values(by='count', ascending=False)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 75,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"1.1811803969722776"
|
||
]
|
||
},
|
||
"execution_count": 75,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"raw_df['odds EU'].mean()"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "base",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.10.9"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|