
    ^i                    B   d Z ddlZddlZddlZddlmZ ddlmZmZmZm	Z	 ddl
Z
 e
j                  e      Zej                  j                  ej                  j!                  ej                  j!                  e            d      Z G d d      Z G d d	      Z e       Zy)
a  
Sports Backtesting Engine
Loads data from BallDontLie API cached files and runs betting strategy backtests
Supports: NBA, NFL, MLB, NHL, College Football, College Basketball

Data sources (in priority order):
1. betting/{sport}_historical.json - Deduplicated historical data with real odds
2. {sport}/games.json + {sport}/odds.json - Raw BallDontLie API data
3. Legacy SportsData.io cache (deprecated)
    N)datetime)DictListAnyOptionaldatac                       e Zd ZdZd ZdedefdZdedefdZdefdZ	dedefd	Z
dded
edee   fdZdedee   fdZdded
edee   fdZy)SportsDataLoaderzELoad sports data from BallDontLie JSON files (replaces SportsData.io)c                     i | _         y )N)cacheselfs    >/var/www/html/eventheodds/python_service/sports_backtesting.py__init__zSportsDataLoader.__init__   s	    
    greturnc                    	 |j                  d      xs i }|j                  d      xs i }t        |      }|j                  d      xs |j                  d      }|j                  d      xs |j                  d      }|r$|j                  d|       |j                  d|       |r$|j                  d|       |j                  d|       |j                  d	      }|j                  d
      }|6|j                  d|       |j                  d|       |j                  d|       |6|j                  d|       |j                  d|       |j                  d|       |j                  d      }	|	r$|j                  d|	       |j                  d|	       |j                  d      !|j                  d|j                  d             |j                  d      !|j                  d|j                  d             |S # t        $ r |cY S w xY w)zCAdd legacy keys (HomeTeam/AwayTeam/etc) for strategy compatibility.scoresoddshomeTeamHomeTeamawayTeamAwayTeamHomeTeamNameAwayTeamName	homeScore	awayScoreHomeTeamScore	HomeScoreHomeTeamRunsAwayTeamScore	AwayScoreAwayTeamRunsdateDateTimeDay
spreadHomePointSpread	totalLine	OverUnder)getdict
setdefault	Exception)
r   r   r   r   outhomeawayhsas_ds
             r   _augment_legacy_gamez%SportsDataLoader._augment_legacy_game    s   &	UU8_*F55=&BDq'C77:&=#''**=D77:&=#''**=Dz40~t4z40~t4K(B**[)C~3{B/~r24{C0~s3Az1-ua( xx%1}dhh|.DExx$0{DHH[,ABJ 	H	s   G7G: :HHsportc                 J    t         j                  j                  t        |      S )z.Get the BallDontLie data directory for a sportospathjoinDATA_BASE_PATHr   r7   s     r   _get_balldontlie_pathz&SportsDataLoader._get_balldontlie_pathJ   s    ww||NE22r   c                 J    t         j                  j                  t        d      S )z)Get the betting historical data directorybettingr9   r   s    r   _get_betting_pathz"SportsDataLoader._get_betting_pathN   s    ww||NI66r   c                 $    | j                  |      S )z9Get the cache path for a sport (same as BallDontLie path))r?   r>   s     r   _get_cache_pathz SportsDataLoader._get_cache_pathR   s    ))%00r   seasonc                 D   | d| }|| j                   v r| j                   |   S |j                         rt        |      nd}t        j                  j                  | j                         | d      }t        j                  j                  |      rR	 t        |d      5 }t        j                  |      }|r$|D cg c]  }|j                  d      |k(  s| }}|D cg c]  }| j                  |       }}|D cg c]9  }|j                  d      s$|j                  di       j                  d      d	v s8|; }	}|	rM|	| j                   |<   t        j                  d
t        |	       d|j!                          d       |	cddd       S |rM|| j                   |<   t        j#                  d
t        |       d|j!                          d       |cddd       S 	 ddd       | j)                  |      }t        j                  j                  |d      }t        j                  j                  |      r	 t        |d      5 }t        j                  |      }ddd       t        j                  j                  |d      }i }t        j                  j                  |      r	 t        |d      5 }t        j                  |      }|D ][  }|j                  d      }|s||vri ||<   |j                  dd      j+                         }|dk(  r	|||   d<   N|dk(  sT|||   d<   ] 	 ddd       g }D ]  }|j                  d      dk7  r|j                  d      s*|j                  d      }|j                  |i       }|j                  dd      xs d}|j                  dd      xs d}|dk(  r|dk(  r|j                  di       }|j                  d i       }|j                  d!      xs |j                  d"d#      }|j                  d!      xs |j                  d"d$      }||z
  }dd%i}d&}|r|j                  di       } |j                  di       }!| r*| j                  d'      |d(<   | j                  d)      |d*<   d+}|!r,t-        |!j                  d,d      xs d      }"|" |d-<   |"|d.<   d+}|rd/|d<   |j/                  | d0| |||j                  d1      xs ddd2 |j                  d|      ||||d3|||dkD  rd4n|dk  rd5nd6|||z   d7d8        |r|r$|D cg c]  }|j                  d      |k(  s| }}|D cg c]  }| j                  |       }}|| j                   |<   t1        d9 |D              }#t        j                  d
t        |       d|j!                          d:|# d;       |S 	 t        j#                  d=| d>|        g S c c}w c c}w c c}w # 1 sw Y   
xY w# t$        $ r#}
t        j'                  d|
        Y d}
~
4d}
~
ww xY w# 1 sw Y   xY w# 1 sw Y   
xY w# t$        $ r#}
t        j#                  d|
        Y d}
~
4d}
~
ww xY wc c}w c c}w # t$        $ r"}
t        j'                  d<|
        Y d}
~
d}
~
ww xY w)?zLoad games data for a sport from BallDontLie data.
        
        Priority:
        1. betting/{sport}_historical.json - Best for backtesting (deduplicated, with real odds)
        2. {sport}/games.json - Raw BallDontLie games
        _games_i  z_historical.jsonrrE   hasRealOddsr   source)liveballdontliekagglekaggle_neutralzfootball-data.co.ukzthe-odds-apizLoaded  z; games with REAL odds from BallDontLie (betting historical)Nz: games from BallDontLie (WARNING: may have estimated odds)z'Error loading betting historical data: z
games.jsonz	odds.jsongame_idtype 2way	moneylinespreadzCould not load odds file: statusFinalhome_team_scoreidr   visitor_team_score	home_teamvisitor_team	full_namenameHomeAwaynoneFodds_american_homemoneylineHomeodds_american_visitormoneylineAwayTaway_spreadr(   
spreadAwayrK   -r%   
   )r   r   r1   r2   draw)winnermargintotalPoints)rY   bdl_game_idr7   r%   rE   r   r   r   r   rI   resultc              3   D   K   | ]  }|j                  d       sd  yw)rI      Nr,   ).0r   s     r   	<genexpr>z.SportsDataLoader.load_games.<locals>.<genexpr>   s     $R1QUU==QQ$Rs     z games from BallDontLie (z with real odds)z!Error loading BallDontLie games: zNo BallDontLie data found for  season )r   isdigitintr:   r;   r<   rB   existsopenjsonloadr,   r6   loggerinfolenupperwarningr/   errorr?   lowerfloatappendsum)$r   r7   rE   	cache_key
season_intbetting_filefr   r   real_odds_dataebdl_path
games_file	raw_games	odds_fileodds_by_game	odds_dataorP   	odds_type	convertedgame	game_odds
home_score
away_scorer[   	away_team	home_name	away_namerl   r   has_real_oddsmlrU   rf   
real_counts$                                       r   
load_gameszSportsDataLoader.load_gamesV   s    gWVH-	

"::i(($*NN$4S[$
 ww||D$:$:$<GW>XY77>>,'L,, $99Q<D!+/Qa155?j3PQQBFGQD55a8GDG15  &PA}9MQRQVQVW]_aQbQfQfgoQp  uO  ROa  &PN  &P%0>

9-gc..A-B!EKKM?  SN  %O  P-$ $ 04

9-T1U[[]O  LF  (G  H##$ $ $, --e4WW\\(L9
77>>*%aF*c* -a $		!I- GGLL;?	!77>>),I!)S1 LQ(,		!I%. 	L*+%%	*:#*'.l'B@BW(=01fb0A0G0G0II'0F':MNW(=k(J)2h)>JKW(=h(G	LL  	% ;Dxx)W4TXXFW=X "hhtnG , 0 0" =I "&*;Q!?!D1J!%*>!B!GaJ!Q:?  !%b 9I $ <I )k : [immFTZ>[I )k : [immFTZ>[I'*4F %f-D$)M &]];;!*x!<46FF;O4PD146FF;R4SD1,0M!*/

=!0L0QPQ*RK2=D.1<D.,0M(-3DN$$!&q	2'.!&!%&!1!7R" ="&((8Z"@$-$-)3)3# !%'406
f6TU:[a&,+5
+B#& Q;z !09$[1QUU8_PZ=ZQ$[	$[GP Q!!:!:1!= QI Q,5DJJy)!$$R	$R!RJKK'#i.)95;;=/Ibcmbnn~   A$$  	7whvhOP	s  RG &P$ $$  LFqcJKKL- -L L % I)CA3'GHHIJ %\ Q
  F@DEEFs  W2  W%<WWW% W8W%>9W 8W <AW%	W2 AW%	W2 W2 7Y4 X!A	Y4 #X; /.X.<X.
X.&X; .G3Y4 !Y*;Y*?Y4 Y/AY4 W%%W/*W2 2	X;XX!X+&Y4 .X83X; ;	Y'Y"Y4 "Y''Y4 4	Z=ZZc                    | d}|| j                   v r| j                   |   S | j                  |      }t        j                  j	                  |d      }t        j                  j                  |      r=	 t        |d      5 }t        j                  |      }|| j                   |<   |cddd       S g S # 1 sw Y   g S xY w# t        $ r#}t        j                  d|        Y d}~g S d}~ww xY w)zLoad teams data for a sport_teamsz
teams.jsonrH   NzError loading teams: r   rD   r:   r;   r<   rx   ry   rz   r{   r/   r|   r   )r   r7   r   
cache_pathfilepathr   r   r   s           r   
load_teamszSportsDataLoader.load_teams   s    gV$	

"::i(())%0
77<<
L977>>(#:(C(  A99Q<D,0DJJy)    	  	  :4QC899	:s6   4B?  &B2&	B? 2B<7B? <B? ?	C+C&&C+c                    | d| }|| j                   v r| j                   |   S | j                  |      }t        j                  j	                  |d| d      }t        j                  j                  |      r=	 t        |d      5 }t        j                  |      }|| j                   |<   |cddd       S g S # 1 sw Y   g S xY w# t        $ r#}t        j                  d|        Y d}~g S d}~ww xY w)zLoad standings data for a sport_standings_
standings_z.jsonrH   NzError loading standings: r   )	r   r7   rE   r   r   r   r   r   r   s	            r   load_standingszSportsDataLoader.load_standings   s    g[1	

"::i(())%0
77<<
j,FG77>>(#>(C(  A99Q<D,0DJJy)    	  	  >8<==	>s6   :C &B8,	C 8C=C C 	C1C,,C1N)2024)__name__
__module____qualname____doc__r   r   r6   strr?   rB   rD   r   r   r   r    r   r   r
   r
      s    O(d (t (T33 33 373 71S 1S 1N NS Nd4j N` T
 (C  $t* r   r
   c                   R   e Zd ZdZd Zdedee   fdZ	 d@dededeee	f   d	ed
edeee	f   fdZ
dededee   fdZdededededee   f
dZdededefdZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
dZdededededee   f
d Zdededededee   f
d!Zdededededee   f
d"Zdededededee   f
d#Zdededededee   f
d$Zdededededee   f
d%Z dededededee   f
d&Z!dededededee   f
d'Z"dededededee   f
d(Z#dededededee   f
d)Z$dededededee   f
d*Z%dededededee   f
d+Z&dededededee   f
d,Z'dededededee   f
d-Z(dedededee   fd.Z)dedededee   fd/Z*dededededee   f
d0Z+d1ed2ede,fd3Z-d4ee   dedeee	f   fd5Z.d6eded7edefd8Z/d4ee   deee	f   fd9Z0ded:ed;e,defd<Z1dededededee   f
d=Z2dededededee   f
d>Z3dededededee   f
d?Z4y)ASportsBacktestingEnginezp
    Universal sports backtesting engine.
    Supports predefined betting strategies with pattern matching.
    c                    t               | _        | j                  | j                  | j                  | j
                  | j                  | j                  | j                  d| j                  | j                  | j                  | j                  | j                  | j                  d| j                  | j                  | j                   | j"                  | j                  d| j$                  | j&                  | j(                  | j                  d| j*                  | j,                  | j.                  | j                  d| j0                  | j2                  | j4                  | j                  d| j6                  | j8                  | j                  d| j:                  | j<                  | j>                  | j                  d| j:                  | j<                  | j>                  | j                  d| j:                  | j<                  | j>                  | j                  d| j:                  | j<                  | j>                  | j                  d| j:                  | j<                  | j>                  | j                  dd	| _         y )
N)home_team_losing_streakhome_favoriteroad_underdogback_to_backmomentum_reversalover_under_trenddynamic_custom)r   r   divisional_game	primetimerest_advantager   )r   pitching_matchuprun_line
over_underr   )r   	puck_liner   r   )r   conference_gamespread_bettingr   )r   conference_tournamentmarch_madnessr   )favoriteunderdogr   )r   rj   over_2_5r   )nbanflmlbnhlcfbcbbmmaepl
bundesligalaligaligue1seriea)!r
   data_loader_nba_home_losing_streak_nba_home_favorite_nba_road_underdog_nba_back_to_back_nba_momentum_reversal_nba_over_under_trend_dynamic_strategy_nfl_home_favorite_nfl_road_underdog_nfl_divisional_nfl_primetime_nfl_rest_advantage_mlb_home_favorite_mlb_pitching_mlb_run_line_mlb_over_under_nhl_home_favorite_nhl_puck_line_nhl_back_to_back_cfb_home_favorite_cfb_conference_cfb_spread_cbb_home_favorite_cbb_conference_cbb_march_madness_mma_favorite_mma_underdog_soccer_home_favorite_soccer_draw_soccer_over_2_5
strategiesr   s    r   r   z SportsBacktestingEngine.__init__  sI   +-
 ,0+G+G!%!8!8!%!8!8 $ 6 6%)%@%@$($>$>"&"8"8 "&!8!8!%!8!8#'#7#7!00"&":":"&"8"8 "&!8!8$($6$6 .."22"&"8"8 "&!8!8!00 $ 6 6"&"8"8	 "&!8!8#'#7#7"&"2"2"&"8"8	 "&!8!8)-)=)=!%!8!8"&"8"8	 !.. .."&"8"8 "&!;!;)) 11"&"8"8	 "&!;!;)) 11"&"8"8	 "&!;!;)) 11"&"8"8	 "&!;!;)) 11"&"8"8	 "&!;!;)) 11"&"8"8	WQ
r   r7   r   c                 h    t        | j                  j                  |i       j                               S )z$Get available strategies for a sport)listr   r,   keysr>   s     r   get_available_strategiesz0SportsBacktestingEngine.get_available_strategiesl  s'    DOO''r2779::r   Nstrategy_nameparamsstrategy_descriptionrE   c                 ,   |j                         }|| j                  vr*dd| t        | j                  j                               dS | j                  |   }|dk(  r|r| j	                  ||      }|sd}||vr dd| t        |j                               dS | j
                  j                  ||      }| j
                  j                  |      }| j
                  j                  ||      }	|sdd| d	| d
S ||   }
	  |
|||	|      }|sddd
S | j                  ||      }i ddd|d|d|dt        |      d|d   d|d   d|d   d|j                  dd      d|d   d|d|d|dd d| j!                  |||      d |d!| j#                  |      d"d#|j%                          d$d%d&t'        j(                         j+                         d'S # t        $ r3}t        j                  d|        ddt        |       d
cY d}~S d}~ww xY w)(a  
        Run a backtest for the given sport and strategy.
        
        Args:
            sport: The sport (nba, nfl, mlb, nhl, cfb, cbb)
            strategy_name: The strategy to use
            params: Strategy parameters (stake, etc.)
            strategy_description: For dynamic strategies, the natural language description
            season: The season to load (default: 2025)
        
        Returns:
            Dict with backtest results
        FzUnknown sport: )successr   available_sportsr   r   zUnknown strategy: )r   r   available_strategieszNo games data available for ru   )r   r   zStrategy execution error: zStrategy execution failed: NzNo trades generated by strategyr   Tr7   r   rE   total_tradeswin_ratetotal_profitprofit_factorsharpe_ratior   max_drawdownresults
all_tradestradesiperformance_summarydetailed_statisticschart_visualizationverification_datazBallDontLie z dataz"Historical backtest on cached dataVerified)data_sourcecalculation_methodverification_status	timestamp)r   r   r   r    _match_strategy_from_descriptionr   r   r   r   r/   r|   r   r   _calculate_resultsr~   r,   _generate_summary_generate_chart_datar   r   now	isoformat)r   r7   r   r   r   rE   sport_strategiesgamesteams	standingsstrategy_funcr  r   r  s                 r   run_backtestz$SportsBacktestingEngine.run_backtestp  s    ' *5'2$()=)=)?$@   ??51 ,,1E AA%I]^M  / 00 -m_=(,-=-B-B-D(E    ++E6:  ++E2$$33E6B	 7whvhO  )7	"5%FCF  :  ))&&9
t
U
 ]
 f	

 CK
 
+
 GN3
 W_5
 GKK:
 GN3
 w
 &
 fSTl
 "4#9#9'5-#X
 "7
  "4#<#<V#D!
"  !-ekkm_EB&J'1%\\^557	"#
 	
!  	LL5aS9: 6s1vh? 	s   ?G 	H (HHHdescriptionc                 "   |j                         }d|v sd|v rd|v r	|dk(  rdS dS d|v r	d|v sd	|v ryd
|v sd|v r.| dt        | j                  j                  |i             v rdS dS d|v sd|v ryd|v sd|v ryd|v sd|v sd|v r	|dk(  rdS dS y)z7Match a strategy name from natural language descriptionzlosing streaklostr  r   r   r   r1   r   teamr   road_road_underdogr   zback to backb2br   momentumreversalr   overundertotalr   r   N)r   r   r   r,   )r   r7   r  
desc_lowers       r   r  z8SportsBacktestingEngine._match_strategy_from_description  s     &&(
 j(Fj,@WPZEZ05,SOSZZ:%=:AU"#v';).~&>#dooFYFYZ_acFdBe&e?zkzzZ'5J+>!#zZ'?&Z7j#8Gz<Q).%%I\Ir   r  r  r  c                    g }|j                  dd      }|j                  dd      }i }t        |d       }	|	D ]  }
|
j                  d|
j                  dd	            }|
j                  d
|
j                  dd	            }|
j                  d|
j                  dd            }|
j                  d|
j                  dd            }|
j                  d      s|
j                  d      r%|
j                  d|
j                  dd	            dd nd}|r||||v rr||   | d }t        |      |k\  r[t        d |D              rI|r|s||kD  }|r|dz  n| }|j	                  || d| d||d|rdndt        |d      | d| dd 	       ||vrg ||<   ||   j	                  ||kD  rd!nd"       ||vrg ||<   ||   j	                  ||kD  rd!nd"        |S )#z4Bet on home team after they've lost N games in a rowstaked   losing_streak   c                 F    | j                  d| j                  dd            S Nr&   r'   rR   rr   r   s    r   <lambda>zASportsBacktestingEngine._nba_home_losing_streak.<locals>.<lambda>      155QUU5RTEU3V r   keyr   r   rR   r   r   r   r    r   r"   r#   r&   r'   Nri   Unknownc              3   &   K   | ]	  }|d k(    yw)LNr   rs   rH   s     r   rt   zBSportsBacktestingEngine._nba_home_losing_streak.<locals>.<genexpr>        :T18:T   ? @ 	Moneylineffffff?winloss    on z-game losing streak	r%   r   bet_type	selectionr,  r   outcomeprofitreasonWr9  r,   sortedr~   allr   roundr   r  r  r  r   r  r,  streak_thresholdteam_recordssorted_gamesr   r[   r   r   r   	game_daterecentwonrI  s                      r   r   z/SportsBacktestingEngine._nba_home_losing_streak  s#   

7C(!::oq9  e)VW  (	TDTXXnb-IJITXXnb-IJI/488K3KLJ/488K3KLJJN((S]J^bfbjbjkpbqTXXeR-@A#2F  xAI
 2j6H L(%i02B1B1CDv;"22s:TV:T7T&: $z1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2%.Kt4D3EEX"Y
# 
 ,*,Y'#***z2I3sS,*,Y'#***z2I3sSQ(	TT r   odds_valr,  c                 d    	 t        |      }|dkD  r||dz  z  S |dt        |      z  z  S #  Y yxY w)z'Calculate profit based on American oddsr   r-  g        r   abs)r   rW  r,  r   s       r   _calculate_payoutz)SportsBacktestingEngine._calculate_payout  sC    	?Daxs
++c$i00	s   + + /c                 (    | j                  ||d      S )zBet on home favoritesNBA_generic_home_favoriter   r  r  r  r   s        r   r   z*SportsBacktestingEngine._nba_home_favorite*      **5&%@@r   c                 (    | j                  ||d      S )zBet on road underdogsr]  _generic_road_underdogr`  s        r   r   z*SportsBacktestingEngine._nba_road_underdog.  ra  r   c                    g }|j                  dd      }t        |d       }i }|D ]-  }	|	j                  d|	j                  dd            }
|	j                  d|	j                  d	d            }|	j                  d
d      }|	j                  dd      }|	j                  d      s|	j                  d      r%|	j                  d|	j                  dd            dd nd}|
r|s||v rf||   }| j                  ||      rO|r|s|||
<   |||<   ||kD  }|r|dz  n| }|j                  || d|
 d|
|d|rdndt	        |d      | dd	       |||
<   |||<   0 |S ) Fade teams on back-to-back gamesr,  r-  c                 F    | j                  d| j                  dd            S r1  rr   r2  s    r   r3  z;SportsBacktestingEngine._nba_back_to_back.<locals>.<lambda>8  r4  r   r5  r   r   rR   r   r   r   r   r"   r&   r'   Nri   r=  r>  r?  r@  rA  rB  rC  z on back-to-backrE  )r,   rM  _is_next_dayr   rO  )r   r  r  r  r   r  r,  rS  team_last_gamer   r[   r   r   r   rT  	last_daterV  rI  s                     r   r   z)SportsBacktestingEngine._nba_back_to_back2  s   

7C( e)VW  $	2DTXXnb-IJITXXnb-IJI/15J/15JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyII N**95	$$Y	:&:4=y14=y1 $z1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2%.K/?"@
# 
 )2N9%(1N9%I$	2L r   c                 x   g }|j                  dd      }|j                  dd      }i }t        |d       }	|	D ]}  }
|
j                  d|
j                  dd	            }|
j                  d
|
j                  dd	            }|
j                  dd      }|
j                  dd      }|
j                  d      s|
j                  d      r%|
j                  d|
j                  dd	            dd nd	}|s||v rr||   | d }t        |      |k\  r[t        d |D              rI|r|s||kD  }|r|dz  n| }|j	                  || d| d||d|rdndt        |d      d| d| dd	       ||vrg ||<   ||vrg ||<   |sD|sH||   j	                  ||kD  rdnd        ||   j	                  ||kD  rdnd         |S )!z)Bet against teams on long winning streaksr,  r-  
win_streak   c                 F    | j                  d| j                  dd            S r1  rr   r2  s    r   r3  z@SportsBacktestingEngine._nba_momentum_reversal.<locals>.<lambda>j  r4  r   r5  r   r   rR   r   r   r   r   r"   r&   r'   Nri   c              3   &   K   | ]	  }|d k(    yw)rK  Nr   r:  s     r   rt   zASportsBacktestingEngine._nba_momentum_reversal.<locals>.<genexpr>y  r;  r<  r=  r>  r?  r@  rA  rB  rC  zFade rD  z-game win streakrE  rK  r9  rL  rP  s                      r   r   z.SportsBacktestingEngine._nba_momentum_reversalc  s   

7C(!::lA6e)VW  (	XDTXXnb-IJITXXnb-IJI/15J/15JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyI L(%i02B1B1CDv;"22s:TV:T7T&: $z1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2$))D9I8JJZ"[
# 
 ,*,Y',*,Y'jY'..j:6MsSVWY'..j:6MsSVWQ(	XT r   c                    g }|j                  dd      }i }t        |d       }|D ]  }	|	j                  d|	j                  dd            }
|	j                  d|	j                  d	d            }|	j                  d
d      xs d}|	j                  dd      xs d}|	j                  dd      }|	j                  d      s|	j                  d      r%|	j                  d|	j                  dd            dd nd}|
r|r|s||z   }|
|v r||v rt        ||
   dd       t        t	        ||
         d      z  }t        ||   dd       t        t	        ||         d      z  }|dkD  rI|dkD  rD||xs dkD  }|r|dz  n| }|j                  || d|
 dd| |d|rdndt        |d      dd	       |
|vrg ||
<   ||vrg ||<   ||
   j                  |       ||   j                  |        |S ) z0Bet on over/under based on recent scoring trendsr,  r-  c                 F    | j                  d| j                  dd            S r1  rr   r2  s    r   r3  z?SportsBacktestingEngine._nba_over_under_trend.<locals>.<lambda>  r4  r   r5  r   r   rR   r   r   r   r   r"   r+      r&   r'   Nri   rm  n   r=  r>  
Over/UnderOver r@  rA  rB  rC  z$Both teams averaging over 110 pointsrE  )r,   rM  r   minr~   r   rO  )r   r  r  r  r   r  r,  team_scoringrS  r   r[   r   r   r   r   rT  r)  home_avgaway_avgrV  rI  s                        r   r   z-SportsBacktestingEngine._nba_over_under_trend  s2   

7C(e)VW  *	7DTXXnb-IJITXXnb-IJI/15:J/15:J+s3JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyIZJ+E L(Y,-F|I6rs;<s3|T]G^C_ab?cc|I6rs;<s3|T]G^C_ab?ccc>hn:#45C,/US[eVFMM )#,+S <$0',ZL%9!& #,/5V"'"2"H
# 
 ,*,Y',*,Y'#**:6#**:6U*	7X r   c                 (    | j                  ||d      S )zBet on NFL home favoritesNFLr^  r`  s        r   r   z*SportsBacktestingEngine._nfl_home_favorite  ra  r   c                 (    | j                  ||d      S )zBet on NFL road underdogsr|  rc  r`  s        r   r   z*SportsBacktestingEngine._nfl_road_underdog  ra  r   c                    g }|j                  dd      }i }|D ]A  }|j                  dd      }	|j                  d|j                  dd            }
|	s:|
s=|	||
<   C |D ]  }|j                  dd      }|j                  dd      }|j                  d	d
      }|j                  dd
      }|j                  d      s|j                  d      r%|j                  d|j                  dd            dd nd}|r|s|j                  |      |j                  |      k(  s|r|s||kD  }|r|dz  n| }|j                  || d| d||d|rdndt        |d      dd	        |S )z%Bet on home teams in divisional gamesr,  r-  DivisionrR   KeyTeamIDr   r   r    r   r#   Dater'   Nri   r=  r>  r?  r@  rA  rB  rC  z%Divisional game - home team advantagerE  r,   r   rO  )r   r  r  r  r   r  r,  division_mapr!  divr6  r   r[   r   r   r   rT  rV  rI  s                      r   r   z'SportsBacktestingEngine._nfl_divisional  s   

7C(  	(D((:r*C((5$((8R"89Cs$'S!		(  	DR0IR0I+q1J+q1JFJhhvFVZ^ZbZbchZi%)<=crBoqII 	*l.>.>y.II"z :-(+%%(kYK8 +!*"(+u#FA.E
 
%	< r   c                    g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  dd      }
|j                  dd      }|j                  d	|j                  d
d            }|
r|sr|su|j                  dd      }|s|
|kD  }|r|dz  n| }|j                  t        |      dd |	 d| d||d|rdndt        |d      d| dd	        |dd S )z?Bet on home team in primetime games (identified by week number)r,  r-  r   rR   r   r    r   r#   r  r'   Weekr=  Nri   r>  r?  r@  rA  rB  rC  z	NFL Week z gamerE  )r,   r   r   rO  )r   r  r  r  r   r  r,  r   r[   r   r   r   rT  weekrV  rI  s                   r   r   z&SportsBacktestingEngine._nfl_primetime  s'   

7C( !	DR0IR0I+q1J+q1J%)<=I : 88FA&Dz)C$'US[eVFMMIs+$+S4'&$'5V*%dV51
 
/!	F ds|r   c                 (    | j                  ||d      S )z1Bet on teams with extra rest (bye week advantage)r|  r^  r`  s        r   r   z+SportsBacktestingEngine._nfl_rest_advantage/  ra  r   c                 (    | j                  ||d      S )zBet on MLB home favoritesMLBr^  r`  s        r   r   z*SportsBacktestingEngine._mlb_home_favorite5  ra  r   c                 .   g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  d|j                  dd            }
|j                  d	|j                  d
d            }|j                  d      s|j                  d      r%|j                  d|j                  dd            dd nd}|s|
r|s|
|kD  }|r|dz  n| }|j                  ||	 d| d||d|rdndt        |d      dd	        |dd S )z6Bet on home team (proxy for pitching matchup analysis)r,  r-  r   rR   r   r!   r    r   r$   r#   r&   r'   Nri   r=  r>  r?  r@  rA  rB  rC  zMLB home team betrE  r  r   r  r  r  r   r  r,  r   r[   r   r   r   rT  rV  rI  s                  r   r   z%SportsBacktestingEngine._mlb_pitching9  s7   

7C( 	DR0IR0I.$((;2JKJ.$((;2JKJJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyI : z)C$'US[eVFMM!$+S4'&$'5V*-
 
%	< ds|r   c                 L   g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  d|j                  dd            xs d}
|j                  d	|j                  d
d            xs d}|j                  d      s|j                  d      r%|j                  d|j                  dd            dd nd}|r|
r|s|
|z
  dk\  }|r|dz  n| }|j                  ||	 d| d| d|d|rdndt        |d      dd	       	 |dd S )zBet on MLB run line (-1.5)r,  r-  r   rR   r   r!   r    r   r$   r#   r&   r'   Nri   rC        ?r>  zRun Line -1.5      @rA  rB  zHome team run linerE  r  r  s                  r   r   z%SportsBacktestingEngine._mlb_run_line^  sG   

7C( 	DR0IR0I.$((;2JKPqJ.$((;2JKPqJJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyIZJ 
*q0C$'US[eVFMM!$+S4& ){%0$'5V*.
 
	4 ds|r   c                 |   g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  d|j                  dd            xs d}
|j                  d	|j                  d
d            xs d}|j                  dd      }|j                  d      s|j                  d      r%|j                  d|j                  dd            dd nd}|r|
r|s|
|z   }||xs dkD  }|r|dz  n| }|j                  ||	 d| dd| |d|rdndt        |d      dd	       ! |dd S )z)Bet on MLB over (total runs exceeds line)r,  r-  r   rR   r   r!   r    r   r$   r#   r+   g      !@r&   r'   Nri   r=  r>  ru  rv  r@  rA  rB  rC  zMLB over betrE  r  )r   r  r  r  r   r  r,  r   r[   r   r   r   r   rT  r)  rV  rI  s                    r   r   z'SportsBacktestingEngine._mlb_over_under  sa   

7C( 	DR0IR0I.$((;2JKPqJ.$((;2JKPqJ+s3JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyIZJ+E :,-C$'US[eVFMM!$+S4($ZL1$'5V*(
 
#	: ds|r   c                 (    | j                  ||d      S )zBet on NHL home favoritesNHLr^  r`  s        r   r   z*SportsBacktestingEngine._nhl_home_favorite  ra  r   c                    g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  dd      xs d}
|j                  dd      xs d}|j                  d	      s|j                  d
      r%|j                  d	|j                  d
d            dd nd}|r|
r|s|
|z
  dk\  }|r|dz  n| }|j                  ||	 d| d| d|d|rdndt        |d      dd	        |dd S )zBet on NHL puck line (-1.5)r,  r-  r   rR   r   r   r   r"   r&   r'   Nri   rC  r  r>  z	Puck Liner  r  rA  rB  zHome team puck linerE  r  r  s                  r   r   z&SportsBacktestingEngine._nhl_puck_line  s1   

7C( 	DR0IR0I/15:J/15:JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyIZJ 
*q0C$'US[eVFMM!$+S4' ){%0$'5V*/
 
	4 ds|r   c                 *    | j                  ||||      S )rf  )r   r`  s        r   r   z)SportsBacktestingEngine._nhl_back_to_back  s    %%eUIvFFr   c                 (    | j                  ||d      S )zBet on CFB home favoritesCFBr^  r`  s        r   r   z*SportsBacktestingEngine._cfb_home_favorite  ra  r   c                 *    | j                  ||||      S )z%Bet on home teams in conference games)r   r`  s        r   r   z'SportsBacktestingEngine._cfb_conference  s    ##E5)VDDr   c                 R   g }|j                  dd      }|D ]	  }|j                  dd      }|j                  dd      }	|j                  dd      xs d}
|j                  dd      xs d}|j                  d	d
      }|j                  d      s|j                  d      r%|j                  d|j                  dd            dd nd}|r|
r|s|
|z
  }|t        |xs d      kD  }|r|dz  n| }|j                  ||	 d| d| d| |d|rdndt        |d      dd	        |dd S )zBet against the spread in CFBr,  r-  r   rR   r   r   r   r"   r)   ir&   r'   Nri      r=  r>  SpreadrO   r@  rA  rB  rC  zHome team spread betrE  )r,   rZ  r   rO  )r   r  r  r  r   r  r,  r   r[   r   r   r   rU   rT  rl   coveredrI  s                    r   r   z#SportsBacktestingEngine._cfb_spread  sS   

7C( 	DR0IR0I/15:J/15:JXXmR0FJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyIZJ  *,Fs6;Q//G$+US[%FMM!$+S4$ ){!F84$+5*0
 
!	8 ds|r   c                 (    | j                  ||d      S )zBet on CBB home favoritesCBBr^  r`  s        r   r   z*SportsBacktestingEngine._cbb_home_favorite  ra  r   c                 (    | j                  ||d      S )z"Bet in conference tournament gamesr  r^  r`  s        r   r   z'SportsBacktestingEngine._cbb_conference  ra  r   c                    g }|j                  dd      }|D ]  }|j                  dd      }|j                  dd      }	|j                  dd      xs d}
|j                  dd      xs d}|j                  d	      s|j                  d
      r%|j                  d	|j                  d
d            dd nd}|r|	s|
r|s||
kD  }|r|dz  n| }|j                  ||	 d| d|	|d|rdndt        |d      dd	        |dd S )z:March Madness upset strategy - bet on away team (underdog)r,  r-  r   rR   r   r   r   r"   r&   r'   Nri   r  r>  r?  g      @rA  rB  rC  zTournament underdog betrE  2   r  r  s                  r   r   z*SportsBacktestingEngine._cbb_march_madness  s-   

7C( 	DR0IR0I/15:J/15:JJN((S]J^bfbjbjkpbqTXXeR-@A#2FwyII : z)C$'US[eVFMM!$+S4'&$'5V*3
 
%	< cr{r   c                    g }|j                  dd      }|D ]9  }|j                  d      xs i }|j                  d      }	|j                  d      }
|j                  d      xs i }|j                  d      }|	|
|d	vrjd
t        dt        fd} ||	      } ||
      }||k  rdnd}||k(  }|dk(  r|	n|
}|r|dkD  r||dz  z  n|dt        |      z  z  }n| }|j                  dd      }|j                  dd      }|j                  d      xs ddd xs d}|j                  || d| d|dk(  r|n||||rdndt	        |d      dd	       < |S ) zLBet the favorite (lower implied probability / typically negative moneyline).r,  r-  r   rc   re   ro   rk   Nr1   r2   ar   c                 T    t        |       } | dkD  r| dz  dz   S dt        |       z  dz   S Nr         Y@g      ?rY  r  s    r   american_to_decimalzBSportsBacktestingEngine._mma_favorite.<locals>.american_to_decimal:  1    !H,-EE	CMA8LMr   r1   r2   r   r  r   	Fighter 1r   	Fighter 2r%   rR   ri   r7   vs r?  rA  rB  rC  z%MMA favorite (by implied probability)rE  r,   r   rZ  r   rO  r   r  r  r  r   r  r,  r   r   ml_homeml_awayresrk   r  home_decaway_decpickrV  odds_americanrI  r1   r2   r%   s                          r   r   z%SportsBacktestingEngine._mma_favorite+     

7C( (	A55=&BDhh/Ghh/G%%/'RCWWX&F'/VCS5SNu N N +73H*73H%06fDT>C'+v~G7M<IA<M-%"78SX\adghudv\vSw55[1D55[1DEE&M'R"-:DMM&TF+'%)V^T%$'5V*A
 
=(	T r   c                    g }|j                  dd      }|D ]9  }|j                  d      xs i }|j                  d      }	|j                  d      }
|j                  d      xs i }|j                  d      }|	|
|d	vrjd
t        dt        fd} ||	      } ||
      }||kD  rdnd}||k(  }|dk(  r|	n|
}|r|dkD  r||dz  z  n|dt        |      z  z  }n| }|j                  dd      }|j                  dd      }|j                  d      xs ddd xs d}|j                  || d| d|dk(  r|n||||rdndt	        |d      dd	       < |S ) zMBet the underdog (higher implied probability / typically positive moneyline).r,  r-  r   rc   re   ro   rk   Nr  r  r   c                 T    t        |       } | dkD  r| dz  dz   S dt        |       z  dz   S r  rY  r  s    r   r  zBSportsBacktestingEngine._mma_underdog.<locals>.american_to_decimalk  r  r   r1   r2   r   r  r   r  r   r  r%   rR   ri   r7  r  r?  rA  rB  rC  z%MMA underdog (by implied probability)rE  r  r  s                          r   r   z%SportsBacktestingEngine._mma_underdog\  r  r   c                    g }|j                  dd      }|D ]  }|j                  di       }|j                  di       }t        |t              r|j                  d      ndxs2 |j                  d|j                  d|j                  d	d
                  }	t        |t              r|j                  d      ndxs2 |j                  d|j                  d|j                  dd
                  }
|j                  di       }|j                  d      xsN |j                  d      xs; |j                  d      xs( |j                  d      xs |j                  d      xs d}|j                  d      xsN |j                  d      xs; |j                  d      xs( |j                  d      xs |j                  d      xs d}|j                  d|j                  d|j                  d|j                  dd
                        }t        |t              rt	        |      dkD  r|dd }|	s|r|s||kD  }|j                  di       }|j                  d       }|r|r| j                  ||      n| }|}n|r|d!z  n| }d"}|j                  |rt        |      dd nd#|
 d$|	 d%|	|||rd&nd't        |d(      | d)d*	        |dd+ S ),zGeneric home favorite strategyr,  r-  r[   r\   abbreviationNr   r   r   rR   r   r   r   r   rX   r   r    r   r!   r   rZ   r"   r#   r   r$   r&   r'   r%   r  ri   r   rc   r=  r7  r>  r?  rA  rB  rC  z home favoriterE     )r,   
isinstancer-   r   r~   r[  r   rO  )r   r  r   r7   r  r,  r   home_team_objvisitor_team_objr[   r   r   r   r   rT  rV  odds_objr  rI  rW  s                       r   r_  z.SportsBacktestingEngine._generic_home_favorite  sz   

7C( ;	D HH["5M#xx;>HX\>]**>:cg  M  EI  EM  EM  NX  Z^  Zb  Zb  cm  os  ow  ow  xF  HJ  oK  ZL  EMIAKL\^bAc)--n=im  S  KO  KS  KS  T^  `d  `h  `h  is  uy  u}  u}  ~L  NP  uQ  `R  KSI XXh+F((#45 7/27+.7  K07 .1	7 67	 
 ((#78 7/27+.7  K07 .1	7 67	  TXXeTXXfdhhW]_aNb=c-deI)S)c)nr.A%crN	 : z)C xx+Hll?3GCF//?UF" ),%MM/8Is+i$+S4'& $'5V*"G>2
 
c;	z ds|r   c                 ,   g }|j                  dd      }|D ]v  }|j                  di       }|j                  di       }t        |t              r|j                  d      ndxs2 |j                  d|j                  d|j                  d	d
                  }	t        |t              r|j                  d      ndxs2 |j                  d|j                  d|j                  dd
                  }
|j                  di       }|j                  d      xsN |j                  d      xs; |j                  d      xs( |j                  d      xs |j                  d      xs d}|j                  d      xsN |j                  d      xs; |j                  d      xs( |j                  d      xs |j                  d      xs d}|j                  d|j                  d|j                  d|j                  dd
                        }|
s|r|s||kD  }|j                  di       }|j                  d      }|r|r| j                  ||      n| }|}n|r|d z  n| }d!}|j	                  ||
 d"|	 d#|
|||rd$nd%t        |d&      | d'd(	       y |dd S ))zGeneric road underdog strategyr,  r-  r[   r\   r  Nr   r   r   rR   r   r   r   r   rX   r   r    r   r!   r   rZ   r"   r#   r   r$   r&   r'   r%   r  r   re   r  r  r>  r?  rA  rB  rC  z road underdogrE  )r,   r  r-   r[  r   rO  )r   r  r   r7   r  r,  r   r  r  r[   r   r   r   r   rT  rV  r  r  rI  rW  s                       r   rd  z.SportsBacktestingEngine._generic_road_underdog  sI   

7C( 6	D HH["5M#xx;>HX\>]**>:cg  M  EI  EM  EM  NX  Z^  Zb  Zb  cm  os  ow  ow  xF  HJ  oK  ZL  EMIAKL\^bAc)--n=im  S  KO  KS  KS  T^  `d  `h  `h  is  uy  u}  u}  ~L  NP  uQ  `R  KSI XXh+F((#45 7/27+.7  K07 .1	7 67	 
 ((#78 7/27+.7  K07 .1	7 67	  TXXeTXXfdhhW]_aNb=c-deI : z)C xx+Hll?3GCF//?UF"(+%MM!$+S4'& $'5V*"G>2
 
Y6	p ds|r   c                 (    | j                  ||d      S )z4Fallback for dynamic strategies - uses home favoriteDYNAMICr^  r`  s        r   r   z)SportsBacktestingEngine._dynamic_strategy  s    **5&)DDr   date1date2c                     	 ddl m }m}  |j                  |dd d      } |j                  |dd d      }||z
  j                  dk(  S #  Y yxY w)z%Check if date2 is the day after date1r   )r   	timedeltaNri   z%Y-%m-%drq   F)r   r  strptimedays)r   r  r  r   r  d1d2s          r   rh  z$SportsBacktestingEngine._is_next_day  s[    	4"""5":z:B"""5":z:BG>>Q&&	s   AA Ar  c                 l   |sdddddddddS t        d |D              }t        |      |z
  }t        d|z  t        |      z  d      }|D cg c]  }|d   	 }}t        t        |      d      }t        d |D              }	t        t        d |D                    }
|
dkD  rt        |	|
z  d      nd	}g }d}|D ]  }||z  }|j	                  |        d}d}|D ]  }||kD  r|}||z
  }||kD  s|} dd
l}t        |      dkD  r<|j                  |      }|j                  |      }|dkD  rt        ||z  dz  d      nd}nd}t        |      |||||t        |d      |t        |t        |      z  d      t        |      t        |      t        |	d      t        |
d      t        |      |||ddS c c}w )z&Calculate backtest results from tradesr   )r   winslossesr  r  r  r  r  c              3   2   K   | ]  }|d    dk(  sd  yw)rH  rA  rq   Nr   )rs   ts     r   rt   z=SportsBacktestingEngine._calculate_results.<locals>.<genexpr>0  s     >)(=1>s   r-  rC  rI  c              3   ,   K   | ]  }|d kD  s	|  ywr   Nr   rs   ps     r   rt   z=SportsBacktestingEngine._calculate_results.<locals>.<genexpr>7  s     7Q17   
c              3   ,   K   | ]  }|d k  s	|  ywr  r   r  s     r   rt   z=SportsBacktestingEngine._calculate_results.<locals>.<genexpr>8  s     911q5Q9r  gR?@Nrq   g_u~/@)r   winning_tradeslosing_tradesr  )r   r  r  r  r  r  r  r  avg_profit_per_trade
best_tradeworst_tradegross_profit
gross_losstrade_analysis)
r   r~   rO  rZ  r   
statisticsmeanstdevmaxrw  )r   r  r   r  r  r  r  profitsr  r  r  r  
cumulativerunningr  peakmax_ddcddr  
avg_return
std_returnsharpes                          r   r  z*SportsBacktestingEngine._calculate_results"  s    ! !!" ! !	 	 >f>>Vt#tc&k115(./11X;//S\1-7g77999:
?IA~lZ7;SY 
 	'AqLGg&	'  	A4xBF{	 	w<!#1J#))'2JISVWU:
2jA1E]^FF  K (*!&!,"$),V*Da$Hg,w<!,2
A. #F"&!'$	
 	
A 0s   F1r  strategyc                     d|j                          d| d|d    d|d    d|d    d	|d
    d|d    d|j                  dd       d|j                          dS )z"Generate a text summary of resultsz
**z Backtest Results - u2   **

📊 **Performance Metrics:**
- Total Trades: r   z
- Win Rate: r  z%
- Total Profit: $r  z
- Profit Factor: r  z
- Max Drawdown: $r  z
- Sharpe Ratio: r  zN/Au(   

✅ Strategy backtested on historical z data from BallDontLie API.
)r   r,   )r   r  r7   r  s       r   r  z)SportsBacktestingEngine._generate_summaryj  s    ;;=/%hZ 0 () *Z ! ".)* +/*+ ,.)* +^U34 5'',{{}o 6 	r   c           	      `   |sddiS g }d}g }t        |      D ]O  \  }}||d   z  }|j                  t        |d             |j                  |j                  dd|dz                 Q d	|d
||d   dkD  rdndddgt	        |      |r|d   nd|rt        |      nd|rt        |      ndddS )z!Generate chart visualization datar   zNo trades to visualizer   rI  rC  r%   zTrade rq   linezCumulative P/Lz#10B981z#EF4444F)labelr   borderColorfill)r   	final_pnlpeak_pnl
trough_pnl)rQ   labelsdatasetssummary)	enumerater   rO  r,   r~   r  rw  )r   r  r  r  r  itrades          r   r  z,SportsBacktestingEngine._generate_chart_dataz  s    566
!&) 	=HAuuX&GeGQ/0MM%))FfQqSEN;<	= )",6rNQ,>yI	  !$F/9Z^q/9C
Oq1;c*o	
 	
r   r   rV  c                     |s| S ||S 	 t        |      }|dkD  r||dz  z  S |dk  r|dt        |      z  z  S |S # t        $ r |cY S w xY w)z6Return profit (not return) for a bet at American odds.r   r  )r   r/   rZ  )r   r,  r   rV  r   s        r   _american_profitz(SportsBacktestingEngine._american_profit  sq    6M<L	dA q5AI&&q5ECFN++  	L	s   ; A	A	c                 |   g }|j                  dd      }|D ]  }|j                  d|j                  dd            }|j                  d|j                  dd            }	|j                  d|j                  d	d
            xs d
}
|j                  d|j                  dd
            xs d
}|j                  d      xs( |j                  d      xs |j                  d      xs ddd }|r|s|j                  d      xs i }|j                  d      }|j                  d      }|j                  d      }||%d } ||      } ||      } ||      }||F||k  rM|||k  rV|
|kD  }| j                  |||      }|j                  ||	 d| d| d|||rdndt        |d      dd	        |dd S ) zDBet home team when it is the clear favorite vs away/draw (3-way ML).r,  r-  r   r   rR   r   r   r   r    r   r"   r#   r&   r'   r%   Nri   r   rc   moneylineDrawre   c                 x    | y 	 t        |       } | dkD  rd| dz   z  S | dk  r
|  |  dz   z  S y # t        $ r Y y w xY w)Nr   r  )r   r/   )r   s    r   impz:SportsBacktestingEngine._soccer_home_favorite.<locals>.imp  sa    : rB 6 BJ//6CbSEM22 !   s   - 	99r>  r?  z MLrA  rB  rC  zHome is favorite (3-way ML)rE     r,   r  r   rO  )r   r  r  r  r   r  r,  r   r[   r   r3   r4   r%   r   ml_hml_dml_ar  p_hp_ap_drV  rI  s                          r   r   z-SportsBacktestingEngine._soccer_home_favorite  s   

7C( 6	DTXXj"-EFITXXj"-EFI/488K+CDIB((?DHH[!,DEJCHHZ(UDHHUOUtxx?OUSUWZXZ[DD88F#)rD88O,D88O,D88O,D|t| d)Cd)Cd)C{ckcz3#:s(C**5$<FMM$+S4' ){#.$'5V*7
 
Y6	p ds|r   c                    g }|j                  dd      }|D ]F  }|j                  d|j                  dd            }|j                  d|j                  dd            }	|j                  d|j                  d	d
            xs d
}
|j                  d|j                  dd
            xs d
}|j                  d      xs( |j                  d      xs |j                  d      xs ddd }|r|s|j                  d      xs i }|j                  d      }||
|k(  }| j                  |||      }|j                  ||	 d| dd|||rdndt        |d      dd	       I |dd S )z.Bet draw when draw odds are available (3-way).r,  r-  r   r   rR   r   r   r   r    r   r"   r#   r&   r'   r%   Nri   r   r  r>  r?  DrawrA  rB  rC  z3-way draw betrE  r  r  )r   r  r  r  r   r  r,  r   r[   r   r3   r4   r%   r   r	  rV  rI  s                    r   r   z$SportsBacktestingEngine._soccer_draw  sr   

7C( 	DTXXj"-EFITXXj"-EFI/488K+CDIB((?DHH[!,DEJCHHZ(UDHHUOUtxx?OUSUWZXZ[DD88F#)rD88O,D|)C**5$<FMM$+S4'#$'5V**
 
#	: ds|r   c                    g }|j                  dd      }|D ]^  }|j                  d|j                  dd            }|j                  d|j                  dd            }	|j                  d|j                  d	d
            xs d
}
|j                  d|j                  dd
            xs d
}|j                  d      xs( |j                  d      xs |j                  d      xs ddd }|r|s|j                  d      xs i }|j                  d      }|	 t        |      }|dk7  r|
|z   }|dkD  }| j                  |d|      }|j	                  ||	 d| dd|d|rdndt        |d      dd	       a |dd S # t        $ r Y sw xY w)z/Bet over 2.5 total goals when totalLine is 2.5.r,  r-  r   r   rR   r   r   r   r    r   r"   r#   r&   r'   r%   Nri   r   r*   r  r  r>  TotalzOver 2.5rA  rB  rC  zOver 2.5 goalsrE  r  )r,   r   r/   r  r   rO  )r   r  r  r  r   r  r,  r   r[   r   r3   r4   r%   r   r  r)  rV  rI  s                     r   r   z(SportsBacktestingEngine._soccer_over_2_5  s   

7C( "	DTXXj"-EFITXXj"-EFI/488K+CDIB((?DHH[!,DEJCHHZ(UDHHUOUtxx?OUSUWZXZ[DD88F#)rD88K(D|T{ s{HE#+C**5$<FMM$+S4#'$'5V**
 
1"	H ds|+  s   E>>	F
F)N2025)5r   r   r   r   r   r   r   r   r   r   r  r   r  r   r   r[  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r_  rd  r   boolrh  r  r  r  r  r   r   r   r   r   r   r   r     s   
U
n;c ;d3i ;
 FL_
# _
c _
4S> _
+._
?B_
PTUXZ]U]P^_
Bc  PXY\P] ,6T 6$ 64 6Y] 6bfgkbl 6p	% 	 	% 	A AT Ad ATX A]abf]g AA AT Ad ATX A]abf]g A/t /D /T /SW /\`ae\f /b3D 3 3$ 3X\ 3aefjak 3j44 4 4 4W[ 4`dei`j 4pA AT Ad ATX A]abf]g AA AT Ad ATX A]abf]g A+T +$ +4 +QU +Z^_cZd +Z(D ( ($ (PT (Y]^bYc (TA Ad At AUY A^bcg^h AA AT Ad ATX A]abf]g A#4 # # #t #X\]aXb #J4   t X\]aXb B"T "$ "4 "QU "Z^_cZd "LA AT Ad ATX A]abf]g AD  $ PT Y]^bYc BGt GD GT GSW G\`ae\f GA AT Ad ATX A]abf]g AET E$ E4 EQU EZ^_cZd E! !d !t !T !VZ[_V` !FA AT Ad ATX A]abf]g AAT A$ A4 AQU AZ^_cZd A# #T #d #TX #]abf]g #P/4 / / /t /X\]aXb /b/4 / / /t /X\]aXb /fBD B$ Bs BtTXz BH=D =$ =s =tTXz =~Et ED ET ESW E\`ae\f E# c d F
d F
T F
d3PS8n F
P c S S  
4: 
$sCx. 
>e 5 t   =4 = = =W[ =`dei`j =~"$ "t " "d "W[\`Wa "H)d )4 )D )RV )[_`d[e )r   r   )r   r:   rz   randomr   typingr   r   r   r   logging	getLoggerr   r|   r;   r<   dirname__file__r=   r
   r   sports_enginer   r   r   <module>r     s   	 
    , , 			8	$ bggoobggooh.GH&Qr rjf fT) ()r   