| import os |
| import requests |
| import gradio as gr |
| import pandas as pd |
|
|
| BASE_URL = "https://sportsbook-nash.draftkings.com/sites/US-VA-SB/api/sportscontent/controldata/league/leagueSubcategory/v1/markets" |
|
|
| LEAGUE_ID = "42133" |
| SUBCATEGORY_ID = "18010" |
|
|
| |
| ADJUSTMENT_FACTOR = 0.67 |
|
|
| DEBUG = True |
|
|
|
|
| def log(msg): |
| if DEBUG: |
| print(msg) |
|
|
|
|
| |
| |
| |
| def american_to_prob(odds): |
| odds = float(odds) |
| if odds > 0: |
| return 100 / (odds + 100) |
| else: |
| return abs(odds) / (abs(odds) + 100) |
|
|
|
|
| def prob_to_decimal(p): |
| if p <= 0: |
| return None |
| return round(1 / p, 3) |
|
|
|
|
| def extract_decimal_adjusted(odds): |
| try: |
| if odds is None: |
| return None |
|
|
| if isinstance(odds, dict): |
| odds = odds.get("american") or odds.get("value") or odds.get("price") |
|
|
| odds = str(odds).strip().replace("−", "-") |
|
|
| |
| if "." in odds and not odds.startswith("+") and not odds.startswith("-"): |
| base_dec = float(odds) |
| p = 1 / base_dec |
| else: |
| p = american_to_prob(float(odds)) |
|
|
| |
| p_adj = p * ADJUSTMENT_FACTOR |
|
|
| return prob_to_decimal(p_adj) |
|
|
| except: |
| return None |
|
|
|
|
| |
| |
| |
| def df_to_tsv(df): |
| if df is None or df.empty: |
| return "" |
| return "\n".join( |
| f"{row['Player']}\t{row['Decimal Odds']}" |
| for _, row in df.iterrows() |
| ) |
|
|
|
|
| |
| |
| |
| def fetch_data(): |
| headers = { |
| "accept": "*/*", |
| "content-type": "application/json; charset=utf-8", |
| "origin": "https://sportsbook.draftkings.com", |
| "referer": "https://sportsbook.draftkings.com/", |
| "user-agent": "Mozilla/5.0", |
| } |
|
|
| params = { |
| "isBatchable": "false", |
| "templateVars": f"{LEAGUE_ID},{SUBCATEGORY_ID}", |
| "eventsQuery": f"$filter=leagueId eq '{LEAGUE_ID}' AND clientMetadata/Subcategories/any(s: s/Id eq '{SUBCATEGORY_ID}')", |
| "marketsQuery": f"$filter=clientMetadata/subCategoryId eq '{SUBCATEGORY_ID}'", |
| "include": "Events", |
| "entity": "events", |
| } |
|
|
| r = requests.get(BASE_URL, headers=headers, params=params, timeout=20) |
| r.raise_for_status() |
| data = r.json() |
|
|
| log(f"Events: {len(data.get('events', []))}") |
| log(f"Selections: {len(data.get('selections', []))}") |
|
|
| return data |
|
|
|
|
| |
| |
| |
| def extract_games(data): |
| games = [] |
|
|
| for e in data.get("events", []): |
| event_id = e.get("id") |
| name = e.get("name") |
|
|
| if event_id and name: |
| games.append((name, str(event_id))) |
|
|
| return games |
|
|
|
|
| |
| |
| |
| def get_market_ids(data, event_id): |
| market_ids = [] |
|
|
| for m in data.get("markets", []): |
| mid = m.get("id") |
|
|
| if str(m.get("eventId")) == str(event_id): |
| market_ids.append(str(mid)) |
|
|
| if "eventIds" in m and str(event_id) in [str(x) for x in m["eventIds"]]: |
| market_ids.append(str(mid)) |
|
|
| return set(market_ids) |
|
|
|
|
| |
| |
| |
| def extract_players(data, event_id): |
| selections = data.get("selections", []) |
| market_ids = get_market_ids(data, event_id) |
|
|
| rows = [] |
|
|
| for s in selections: |
| market_id = s.get("marketId") |
|
|
| if str(market_id) not in market_ids: |
| continue |
|
|
| player = None |
|
|
| if s.get("participants"): |
| player = s["participants"][0].get("name") |
|
|
| if not player: |
| player = s.get("label") or s.get("outcomeName") |
|
|
| odds = s.get("displayOdds") or s.get("oddsAmerican") or s.get("price") |
|
|
| dec = extract_decimal_adjusted(odds) |
|
|
| if player and dec is not None: |
| rows.append((player, dec)) |
|
|
| df = pd.DataFrame(rows, columns=["Player", "Decimal Odds"]) |
|
|
| return df.drop_duplicates().sort_values("Player").reset_index(drop=True) |
|
|
|
|
| |
| |
| |
| def initialize_app(): |
| data = fetch_data() |
| games = extract_games(data) |
|
|
| if not games: |
| return {}, gr.Dropdown(choices=[], value=None) |
|
|
| game_map = {name: eid for name, eid in games} |
|
|
| return game_map, gr.Dropdown( |
| choices=list(game_map.keys()), |
| value=list(game_map.keys())[0] |
| ) |
|
|
|
|
| |
| |
| |
| def run_selected_game(game_map, selected_game): |
| if not selected_game: |
| return pd.DataFrame(), "" |
|
|
| data = fetch_data() |
| event_id = game_map[selected_game] |
|
|
| df = extract_players(data, event_id) |
|
|
| return df, df_to_tsv(df) |
|
|
|
|
| |
| |
| |
| with gr.Blocks(title="DK NHL OT Adjusted Points") as demo: |
| gr.Markdown("# DK NHL OT Adjusted Points") |
|
|
| game_map_state = gr.State({}) |
|
|
| with gr.Row(): |
| game_dropdown = gr.Dropdown(label="Select Game", scale=5) |
| run_btn = gr.Button("Run", variant="primary") |
| refresh_btn = gr.Button("Refresh") |
|
|
| output_df = gr.Dataframe( |
| headers=["Player", "Decimal Odds"], |
| datatype=["str", "number"], |
| interactive=False, |
| label="Adjusted Player Table" |
| ) |
|
|
| copy_box = gr.Textbox( |
| label="Copy (paste into Excel/Sheets)", |
| lines=12, |
| interactive=False |
| ) |
|
|
| demo.load( |
| initialize_app, |
| inputs=[], |
| outputs=[game_map_state, game_dropdown] |
| ) |
|
|
| run_btn.click( |
| run_selected_game, |
| inputs=[game_map_state, game_dropdown], |
| outputs=[output_df, copy_box] |
| ) |
|
|
| refresh_btn.click( |
| initialize_app, |
| inputs=[], |
| outputs=[game_map_state, game_dropdown] |
| ) |
|
|
|
|
| |
| |
| |
| if __name__ == "__main__": |
| demo.queue().launch( |
| server_name="0.0.0.0", |
| server_port=int(os.getenv("PORT", 7860)) |
| ) |