
    ^i                    B   S r SSKrSSKrSSKrSSKJr  SSKJrJrJrJ	r	  SSK
r
\
R                  " \5      r\R                  R                  \R                  R!                  \R                  R!                  \5      5      S5      r " S S5      r " S S	5      r\" 5       rg)
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                       \ rS rSrSrS rS\S\4S jrS\S\4S jr	S\4S	 jr
S\S\4S
 jrSS\S\S\\   4S jjrS\S\\   4S jrSS\S\S\\   4S jjrSrg)SportsDataLoader   zELoad sports data from BallDontLie JSON files (replaces SportsData.io)c                     0 U l         g )Ncacheselfs    W/home/hazypiff/Work/eventheodds/eventheodds_backup/python_service/sports_backtesting.py__init__SportsDataLoader.__init__   s	    
    greturnc                 f    UR                  S5      =(       d    0 nUR                  S5      =(       d    0 n[        U5      nUR                  S5      =(       d    UR                  S5      nUR                  S5      =(       d    UR                  S5      nU(       a$  UR                  SU5        UR                  SU5        U(       a$  UR                  SU5        UR                  SU5        UR                  S	5      nUR                  S
5      nUb6  UR                  SU5        UR                  SU5        UR                  SU5        Ub6  UR                  SU5        UR                  SU5        UR                  SU5        UR                  S5      n	U	(       a$  UR                  SU	5        UR                  SU	5        UR                  S5      b!  UR                  SUR                  S5      5        UR                  S5      b!  UR                  SUR                  S5      5        U$ ! [         a    Us $ f = f)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_game%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   HH! !H0/H0sportc                 J    [         R                  R                  [        U5      $ )z.Get the BallDontLie data directory for a sportospathjoinDATA_BASE_PATHr   r;   s     r   _get_balldontlie_path&SportsDataLoader._get_balldontlie_pathJ   s    ww||NE22r   c                 J    [         R                  R                  [        S5      $ )z)Get the betting historical data directorybettingr=   r   s    r   _get_betting_path"SportsDataLoader._get_betting_pathN   s    ww||NI66r   c                 $    U R                  U5      $ )z9Get the cache path for a sport (same as BallDontLie path))rC   rB   s     r   _get_cache_path SportsDataLoader._get_cache_pathR   s    ))%00r   seasonc                    U SU 3nX0R                   ;   a  U R                   U   $ UR                  5       (       a  [        U5      OSn[        R                  R                  U R                  5       U S35      n[        R                  R                  U5      (       Gap   [        US5       n[        R                  " U5      nU(       a(  U Vs/ s H  oR                  S5      U:X  d  M  UPM     nnU Vs/ s H  oR                  U5      PM     nnU Vs/ s HA  oR                  S5      (       d'  UR                  S0 5      R                  S5      S	;   d  M?  UPMC     n	nU	(       aL  XR                   U'   [        R                  S
[        U	5       SUR!                  5        S35        U	sSSS5        $ U(       aL  XpR                   U'   [        R#                  S
[        U5       SUR!                  5        S35        UsSSS5        $  SSS5        U R)                  U5      n[        R                  R                  US5      n[        R                  R                  U5      (       Ga   [        US5       n[        R                  " U5      nSSS5        [        R                  R                  US5      n0 n[        R                  R                  U5      (       a   [        US5       n[        R                  " U5      nU Hh  nUR                  S5      nU(       d  M  UU;  a  0 UU'   UR                  SS5      R+                  5       nUS:X  a
  UUU   S'   MX  US:X  d  M`  UUU   S'   Mj     SSS5        / nW GH"  nUR                  S5      S:w  a  UR                  S5      (       d  M1  UR                  S5      nUR                  U0 5      nUR                  SS5      =(       d    SnUR                  SS5      =(       d    SnUS:X  a  US:X  a  M  UR                  S0 5      nUR                  S 0 5      nUR                  S!5      =(       d    UR                  S"S#5      nUR                  S!5      =(       d    UR                  S"S$5      nUU-
  nSS%0nS&nU(       a  UR                  S0 5      n UR                  S0 5      n!U (       a*  U R                  S'5      US('   U R                  S)5      US*'   S+nU!(       a1  [-        U!R                  S,S5      =(       d    S5      n"U"* US-'   U"US.'   S+nU(       a  S/US'   UR/                  U S0U 3UUUR                  S15      =(       d    SSS2 UR                  SU5      UUUUS3.UUUS:  a  S4O	US:  a  S5OS6UUU-   S7.S8.5        GM%     U(       a  U(       a(  U Vs/ s H  oR                  S5      U:X  d  M  UPM     nnU Vs/ s H  oR                  U5      PM     nnUU R                   U'   [1        S9 U 5       5      n#[        R                  S
[        U5       SUR!                  5        S:U# S;35        U$  [        R#                  S=U S>U 35        / $ s  snf s  snf s  snf ! , (       d  f       GNx= f! [$         a#  n
[        R'                  SU
 35         Sn
A
GNSn
A
ff = f! , (       d  f       GN8= f! , (       d  f       GNj= f! [$         a#  n
[        R#                  SU
 35         Sn
A
GNSn
A
ff = fs  snf s  snf ! [$         a"  n
[        R'                  S<U
 35         Sn
A
NSn
A
ff = f)?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rrL   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+   
spreadAwayrR   -r(   
   )r    r!   r4   r5   draw)winnermargintotalPoints)r`   bdl_game_idr;   r(   rL   r   r   r   r   rP   resultc              3   T   #    U  H  oR                  S 5      (       d  M  Sv   M      g7f)rP      Nr/   ).0r   s     r   	<genexpr>.SportsDataLoader.load_games.<locals>.<genexpr>   s     $R	1UU==QQQ	s   (	(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@   rG   existsopenjsonloadr/   r9   loggerinfolenupperwarningr2   errorrC   lowerfloatappendsum)$r   r;   rL   	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orW   	odds_type	convertedgame	game_odds
home_score
away_scorerb   	away_team	home_name	away_namers   r   has_real_oddsmlr\   rm   
real_counts$                                       r   
load_gamesSportsDataLoader.load_gamesV   s    gWVH-	

"::i(($*NN$4$4S[$
 ww||D$:$:$<GW>XY77>>,''L,,99Q<D!+/Q4a55?j3P4QBFG$Q55a8$DG15  &PA}9M9MQRQVQVW]_aQbQfQfgoQp  uO  ROa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1Q(,		!I%.*+%%	*:#*7'.l'B@BW(=01fb0A0G0G0II'0F':MNW(=k(J)2h)>JKW(=h(G &/ 2  	%Dxx)W4TXXFW=X=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$[	1UU8_PZ=ZQ		$[GP Qy!!:!:1!=yI 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 +* 21 % I)CA3'GHHIJ %\ Q
  F@DEEFs+  Z	 +"Y7Y()Y(/Y75Y-Y7>Y2Y2AY7(	Z	 2A	Y7;	Z	 Z	 %\ 1Z9A\ [ #2[?[[([ 0H=\ -\	\\ \/A\ (Y77
ZZ	 Z	 	
Z6Z11Z69
[\ 
[[ \ [ 
\
'\?\ \

\ 
]!\>>]c                    U S3nX R                   ;   a  U R                   U   $ U R                  U5      n[        R                  R	                  US5      n[        R                  R                  U5      (       a=   [        US5       n[        R                  " U5      nX`R                   U'   UsSSS5        $ / $ ! , (       d  f       / $ = f! [         a#  n[        R                  SU 35         SnA/ $ SnAff = f)zLoad teams data for a sport_teamsz
teams.jsonrO   NzError loading teams: r   rJ   r>   r?   r@   r   r   r   r   r2   r   r   )r   r;   r   
cache_pathfilepathr   r   r   s           r   
load_teamsSportsDataLoader.load_teams   s    gV$	

"::i(())%0
77<<
L977>>(##:(C(A99Q<D,0JJy) )( 	 )( 	  :4QC899	:s6   :C
 &B8,	C
 8
CC
 C
 

C7C22C7c                     U SU 3nX0R                   ;   a  U R                   U   $ U R                  U5      n[        R                  R	                  USU S35      n[        R                  R                  U5      (       a=   [        US5       n[        R                  " U5      nXpR                   U'   UsSSS5        $ / $ ! , (       d  f       / $ = f! [         a#  n[        R                  SU 35         SnA/ $ SnAff = f)zLoad standings data for a sport_standings_
standings_z.jsonrO   NzError loading standings: r   )	r   r;   rL   r   r   r   r   r   r   s	            r   load_standingsSportsDataLoader.load_standings   s    g[1	

"::i(())%0
77<<
j,FG77>>(##>(C(A99Q<D,0JJy) )( 	 )( 	  >8<==	>s6    C &B>2	C >
CC C 
C=C88C=r   N)2024)__name__
__module____qualname____firstlineno____doc__r   r   r9   strrC   rG   rJ   r   r   r   r   __static_attributes__ 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S rSrSrS rS\S\\   4S jr SBS\S\S	\	\\
4   S
\S\S\	\\
4   4S jjrS\S\S\\   4S jrS\S\S\S	\	S\\	   4
S jrS\S\S\4S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S jrS\S\S\S	\	S\\	   4
S  jrS\S\S\S	\	S\\	   4
S! jrS\S\S\S	\	S\\	   4
S" jrS\S\S\S	\	S\\	   4
S# jrS\S\S\S	\	S\\	   4
S$ jrS\S\S\S	\	S\\	   4
S% jr S\S\S\S	\	S\\	   4
S& jr!S\S\S\S	\	S\\	   4
S' jr"S\S\S\S	\	S\\	   4
S( jr#S\S\S\S	\	S\\	   4
S) jr$S\S\S\S	\	S\\	   4
S* jr%S\S\S\S	\	S\\	   4
S+ jr&S\S\S\S	\	S\\	   4
S, jr'S\S\S\S	\	S\\	   4
S- jr(S\S\S\S	\	S\\	   4
S. jr)S\S	\	S\S\\	   4S/ jr*S\S	\	S\S\\	   4S0 jr+S\S\S\S	\	S\\	   4
S1 jr,S2\S3\S\-4S4 jr.S5\\	   S	\	S\	\\
4   4S6 jr/S7\	S\S8\S\4S9 jr0S5\\	   S\	\\
4   4S: jr1S\S;\S<\-S\4S= jr2S\S\S\S	\	S\\	   4
S> jr3S\S\S\S	\	S\\	   4
S? jr4S\S\S\S	\	S\\	   4
S@ jr5SAr6g)CSportsBacktestingEnginei  zd
Universal sports backtesting engine.
Supports predefined betting strategies with pattern matching.
c                    [        5       U l        U R                  U R                  U R                  U R
                  U R                  U R                  U R                  S.U R                  U R                  U R                  U R                  U R                  U R                  S.U R                  U R                  U R                   U R"                  U R                  S.U R$                  U R&                  U R(                  U R                  S.U R*                  U R,                  U R.                  U R                  S.U R0                  U R2                  U R4                  U R                  S.U R6                  U R8                  U R                  S.U R:                  U R<                  U R>                  U R                  S.U R:                  U R<                  U R>                  U R                  S.U R:                  U R<                  U R>                  U R                  S.U R:                  U R<                  U R>                  U R                  S.U R:                  U R<                  U R>                  U R                  S.S	.U l         g )
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   rq   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    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   r;   r   c                 h    [        U R                  R                  U0 5      R                  5       5      $ )z$Get available strategies for a sport)listr  r/   keysrB   s     r   get_available_strategies0SportsBacktestingEngine.get_available_strategiesl  s'    DOO''r2779::r   Nstrategy_nameparamsstrategy_descriptionrL   c                 N   UR                  5       nXR                  ;  a*  SSU 3[        U R                  R                  5       5      S.$ U R                  U   nUS:X  a!  U(       a  U R	                  X5      nU(       d  SnX&;  a   SSU 3[        UR                  5       5      S.$ U R
                  R                  X5      nU R
                  R                  U5      nU R
                  R                  X5      n	U(       d  SSU S	U 3S
.$ Xb   n
 U
" XxX5      nU(       d  SSS
.$ U R                  X5      n0 SS_SU_SU_SU_S[        U5      _SUS   _SUS   _SUS   _SUR                  SS5      _SUS   _SU_SU_SUSS _SU R!                  XU5      _S U_S!U R#                  U5      _S"S#UR%                  5        S$3S%S&[&        R(                  " 5       R+                  5       S'._$ ! [         a3  n[        R                  SU 35        SS[        U5       3S
.s SnA$ SnAff = f)(am  
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 r}   )r  r   zStrategy execution error: zStrategy execution failed: NzNo trades generated by strategyr  Tr;   r  rL   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   r2   r   r   r   _calculate_resultsr   r/   _generate_summary_generate_chart_datar   r   now	isoformat)r   r;   r  r	  r
  rL   sport_strategiesgamesteams	standingsstrategy_funcr  r   r  s                 r   run_backtest$SportsBacktestingEngine.run_backtestp  s    ' *5'2$()=)=)?$@   ??51 ,,1E AA%^M  /0 -m_=(,-=-B-B-D(E    ++E:  ++E2$$33EB	 7whvhO  )7	"5CF  :  ))&9
t
U
 ]
 f	

 CK
 
+
 GN3
 W_5
 GKK:
 GN3
 w
 &
 fSTl
 "4#9#9'-#X
 "7
  "4#<#<V#D!
"  !-ekkm_EB&J'1%\\^557	"#
 	
!  	LL5aS9: 6s1vh? 	s   	G' '
H$1(HH$H$descriptionc                 f   UR                  5       nSU;   d  SU;   a  SU;   a
  US:X  a  S$ S$ SU;   a  SU;   d  S	U;   a  gS
U;   d  SU;   a0  U S3[        U R                  R                  U0 5      5      ;   a  S$ S$ SU;   d  SU;   a  gSU;   d  SU;   a  gSU;   d  SU;   d  SU;   a
  US:X  a  S$ S$ g)z7Match a strategy name from natural language descriptionzlosing streaklostr(  r   r   r   r4   r   teamr   road_road_underdogr   zback to backb2br   momentumreversalr   overundertotalr   r   N)r   r   r  r/   )r   r;   r.  
desc_lowers       r   r!  8SportsBacktestingEngine._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                    / nUR                  SS5      nUR                  SS5      n0 n[        US S9n	U	 GH  n
U
R                  SU
R                  SS	5      5      nU
R                  S
U
R                  SS	5      5      nU
R                  SU
R                  SS5      5      nU
R                  SU
R                  SS5      5      nU
R                  S5      (       d  U
R                  S5      (       a%  U
R                  SU
R                  SS	5      5      SS OSnU(       a  Ub  Uc  M  X;   a  X   U* S n[        U5      U:  at  [        S U 5       5      (       a]  U(       a  U(       d  GM2  X:  nU(       a  US-  OU* nUR	                  UU SU 3SUUSU(       a  SOS[        US5      U SU S3S .	5        X;  a  / X'   X   R	                  X:  a  S!OS"5        X;  a  / X'   X   R	                  X:  a  S!OS"5        GM     U$ )#z4Bet on home team after they've lost N games in a rowstaked   losing_streak   c                 F    U R                  SU R                  SS5      5      $ Nr)   r*   rY   ry   r   s    r   <lambda>ASportsBacktestingEngine._nba_home_losing_streak.<locals>.<lambda>      155QUU5RTEU3Vr   keyr   r   rY   r   r   r"   r#   r   r%   r&   r)   r*   Nrp   Unknownc              3   *   #    U  H	  oS :H  v   M     g7f)LNr   rz   rO   s     r   r{   BSportsBacktestingEngine._nba_home_losing_streak.<locals>.<genexpr>        :TV8V   ? @ 	Moneylineffffff?winloss    on z-game losing streak	r(   r   bet_type	selectionr=  r   outcomeprofitreasonWrK  r/   sortedr   allr   roundr   r(  r)  r*  r	  r  r=  streak_thresholdteam_recordssorted_gamesr   rb   r   r   r   	game_daterecentwonr\  s                      r   r   /SportsBacktestingEngine._nba_home_losing_streak  s   

7C(!::oq9  e)VW DTXXnb-IJITXXnb-IJI/488K3KLJ/488K3KLJJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2F  xAI
 2j6H (%02B1B1CDv;"22s:TV:T7T7T&: $1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2%.Kt4D3EEX"Y
# 
 ,*,'#***2I3sS,*,'#***2I3sSQ !T r   odds_valr=  c                 d     [        U5      nUS:  a  X#S-  -  $ US[        U5      -  -  $ !    g= f)z'Calculate profit based on American oddsr   r>  g        r   abs)r   rk  r=  r   s       r   _calculate_payout)SportsBacktestingEngine._calculate_payout  sA    	?Daxs
++c$i00	s   + + /c                 &    U R                  XS5      $ )zBet on home favoritesNBA_generic_home_favoriter   r(  r)  r*  r	  s        r   r   *SportsBacktestingEngine._nba_home_favorite*      **5%@@r   c                 &    U R                  XS5      $ )zBet on road underdogsrr  _generic_road_underdogru  s        r   r   *SportsBacktestingEngine._nba_road_underdog.  rw  r   c                    / nUR                  SS5      n[        US S9n0 nU GHX  n	U	R                  SU	R                  SS5      5      n
U	R                  SU	R                  S	S5      5      nU	R                  S
S5      nU	R                  SS5      nU	R                  S5      (       d  U	R                  S5      (       a%  U	R                  SU	R                  SS5      5      SS OSnU
(       a  U(       d  M  X;   a|  X   nU R                  X5      (       ab  U(       a  U(       d  XU
'   XU'   GM  X:  nU(       a  US-  OU* nUR                  UU SU
 3SU
USU(       a  SOS[	        US5      U S3S.	5        XU
'   XU'   GM[     U$ ) Fade teams on back-to-back gamesr=  r>  c                 F    U R                  SU R                  SS5      5      $ rB  ry   rC  s    r   rD  ;SportsBacktestingEngine._nba_back_to_back.<locals>.<lambda>8  rF  r   rG  r   r   rY   r   r   r"   r   r%   r)   r*   Nrp   rP  rQ  rR  rS  rT  rU  rV  z on back-to-backrX  )r/   r`  _is_next_dayr   rb  )r   r(  r)  r*  r	  r  r=  rf  team_last_gamer   rb   r   r   r   rg  	last_dateri  r\  s                     r   r   )SportsBacktestingEngine._nba_back_to_back2  s   

7C( e)VW DTXXnb-IJITXXnb-IJI/15J/15JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyII **5	$$Y::&:4=y14=y1 $1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2%.K/?"@
# 
 )29%(19%I !L r   c                    / nUR                  SS5      nUR                  SS5      n0 n[        US S9n	U	 GH  n
U
R                  SU
R                  SS	5      5      nU
R                  S
U
R                  SS	5      5      nU
R                  SS5      nU
R                  SS5      nU
R                  S5      (       d  U
R                  S5      (       a%  U
R                  SU
R                  SS	5      5      SS OS	nU(       d  M  X;   a  X   U* S n[        U5      U:  au  [        S U 5       5      (       a^  U(       a  U(       d  GM  X:  nU(       a  US-  OU* nUR	                  UU SU 3SUUSU(       a  SOS[        US5      SU SU S3S.	5        X;  a  / X'   X;  a  / X'   U(       d  GMu  U(       d  GM  X   R	                  X:  a  SOS 5        X   R	                  X:  a  SOS 5        GM     U$ )!z)Bet against teams on long winning streaksr=  r>  
win_streak   c                 F    U R                  SU R                  SS5      5      $ rB  ry   rC  s    r   rD  @SportsBacktestingEngine._nba_momentum_reversal.<locals>.<lambda>j  rF  r   rG  r   r   rY   r   r   r"   r   r%   r)   r*   Nrp   c              3   *   #    U  H	  oS :H  v   M     g7f)r^  Nr   rL  s     r   r{   ASportsBacktestingEngine._nba_momentum_reversal.<locals>.<genexpr>y  rN  rO  rP  rQ  rR  rS  rT  rU  rV  zFade rW  z-game win streakrX  r^  rK  r_  rc  s                      r   r   .SportsBacktestingEngine._nba_momentum_reversalc  s   

7C(!::lA6e)VW DTXXnb-IJITXXnb-IJI/15J/15JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyI (%02B1B1CDv;"22s:TV:T7T7T&: $1C,/US[eVFMM )#,+S <$/%.!& #,/5V"'"2$))D9I8JJZ"[
# 
 ,*,',*,'zjj'..j6MsSVW'..j6MsSVWQ !T r   c                 4   / nUR                  SS5      n0 n[        US S9nU GH  n	U	R                  SU	R                  SS5      5      n
U	R                  SU	R                  S	S5      5      nU	R                  S
S5      =(       d    SnU	R                  SS5      =(       d    SnU	R                  SS5      nU	R                  S5      (       d  U	R                  S5      (       a%  U	R                  SU	R                  SS5      5      SS OSnU
(       a  U(       a  U(       d  M  X-   nX;   a  X;   a  [        Xz   SS 5      [        [	        Xz   5      S5      -  n[        X{   SS 5      [        [	        X{   5      S5      -  nUS:  aY  US:  aS  UU=(       d    S:  nU(       a  US-  OU* nUR                  UU SU
 3SSU 3USU(       a  SOS[        US5      SS.	5        X;  a  / Xz'   X;  a  / X{'   Xz   R                  U5        X{   R                  U5        GM     U$ ) z0Bet on over/under based on recent scoring trendsr=  r>  c                 F    U R                  SU R                  SS5      5      $ rB  ry   rC  s    r   rD  ?SportsBacktestingEngine._nba_over_under_trend.<locals>.<lambda>  rF  r   rG  r   r   rY   r   r   r"   r   r%   r.      r)   r*   Nrp   r  n   rP  rQ  
Over/UnderOver rS  rT  rU  rV  z$Both teams averaging over 110 pointsrX  )r/   r`  r   minr   r   rb  )r   r(  r)  r*  r	  r  r=  team_scoringrf  r   rb   r   r   r   r   rg  r9  home_avgaway_avgri  r\  s                        r   r   -SportsBacktestingEngine._nba_over_under_trend  s   

7C(e)VW DTXXnb-IJITXXnb-IJI/15:J/15:J+s3JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyIZJ+E (Y-F|6rs;<s3|G^C_ab?cc|6rs;<s3|G^C_ab?ccc>hn:#45C,/US[eVFMM )#,+S <$0',ZL%9!& #,/5V"'"2"H
# 
 ,*,',*,'#**:6#**:6U !X r   c                 &    U R                  XS5      $ )zBet on NFL home favoritesNFLrs  ru  s        r   r   *SportsBacktestingEngine._nfl_home_favorite  rw  r   c                 &    U R                  XS5      $ )zBet on NFL road underdogsr  ry  ru  s        r   r   *SportsBacktestingEngine._nfl_road_underdog  rw  r   c                 <   / nUR                  SS5      n0 nU HM  nUR                  SS5      n	UR                  SUR                  SS5      5      n
U	(       d  M@  U
(       d  MI  XU
'   MO     U GH+  nUR                  SS5      nUR                  SS5      nUR                  S	S
5      nUR                  SS
5      nUR                  S5      (       d  UR                  S5      (       a%  UR                  SUR                  SS5      5      SS OSnU(       a  U(       d  M  UR                  U5      UR                  U5      :X  d  M  U(       a  U(       d  M  X:  nU(       a  US-  OU* nUR                  UU SU 3SUUSU(       a  SOS[        US5      SS.	5        GM.     U$ )z%Bet on home teams in divisional gamesr=  r>  DivisionrY   KeyTeamIDr   r   r#   r   r&   Dater*   Nrp   rP  rQ  rR  rS  rT  rU  rV  z%Divisional game - home team advantagerX  r/   r   rb  )r   r(  r)  r*  r	  r  r=  division_mapr1  divrH  r   rb   r   r   r   rg  ri  r\  s                      r   r   'SportsBacktestingEngine._nfl_divisional  s   

7C( D((:r*C((5$((8R"89Csss$'S!	  DR0IR0I+q1J+q1JFJhhvFVFVZ^ZbZbchZiZi%)<=crBoqII 	*l.>.>y.II"z -(+%%(kYK8 +!*"(+u#FA.E
 
% < r   c                 .   / nUR                  SS5      nU H  nUR                  SS5      nUR                  SS5      n	UR                  SS5      n
UR                  SS5      nUR                  S	UR                  S
S5      5      nU
(       a  U(       d  M}  U(       d  M  UR                  SS5      nU(       d  M  X:  nU(       a  US-  OU* nUR                  [        U5      SS U	 SU 3SUUSU(       a  SOS[        US5      SU S3S.	5        M     USS $ )z?Bet on home team in primetime games (identified by week number)r=  r>  r   rY   r   r#   r   r&   r  r*   WeekrP  Nrp   rQ  rR  rS  rT  rU  rV  z	NFL Week z gamerX  )r/   r   r   rb  )r   r(  r)  r*  r	  r  r=  r   rb   r   r   r   rg  weekri  r\  s                   r   r   &SportsBacktestingEngine._nfl_primetime  s    

7C(DR0IR0I+q1J+q1J%)<=I : 88FA&D)C$'US[eVFMMIs+$+S4'&$'5V*%dV51
 
/ F ds|r   c                 &    U R                  XS5      $ )z1Bet on teams with extra rest (bye week advantage)r  rs  ru  s        r   r   +SportsBacktestingEngine._nfl_rest_advantage/  rw  r   c                 &    U R                  XS5      $ )zBet on MLB home favoritesMLBrs  ru  s        r   r   *SportsBacktestingEngine._mlb_home_favorite5  rw  r   c                 ~   / nUR                  SS5      nU GH  nUR                  SS5      nUR                  SS5      n	UR                  SUR                  SS5      5      n
UR                  S	UR                  S
S5      5      nUR                  S5      (       d  UR                  S5      (       a%  UR                  SUR                  SS5      5      SS OSnU(       d  M  U
(       a  U(       d  M  X:  nU(       a  US-  OU* nUR                  UU	 SU 3SUUSU(       a  SOS[        US5      SS.	5        GM!     USS $ )z6Bet on home team (proxy for pitching matchup analysis)r=  r>  r   rY   r   r$   r#   r   r'   r&   r)   r*   Nrp   rP  rQ  rR  rS  rT  rU  rV  zMLB home team betrX  r  r   r(  r)  r*  r	  r  r=  r   rb   r   r   r   rg  ri  r\  s                  r   r   %SportsBacktestingEngine._mlb_pitching9  s6   

7C(DR0IR0I.$((;2JKJ.$((;2JKJJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyI : )C$'US[eVFMM!$+S4'&$'5V*-
 
% < ds|r   c                    / nUR                  SS5      nU GH4  nUR                  SS5      nUR                  SS5      n	UR                  SUR                  SS5      5      =(       d    Sn
UR                  S	UR                  S
S5      5      =(       d    SnUR                  S5      (       d  UR                  S5      (       a%  UR                  SUR                  SS5      5      SS OSnU(       a  U
(       a  U(       d  M  X-
  S:  nU(       a  US-  OU* nUR                  UU	 SU 3SU S3USU(       a  SOS[        US5      SS.	5        GM7     USS $ )zBet on MLB run line (-1.5)r=  r>  r   rY   r   r$   r#   r   r'   r&   r)   r*   Nrp   rV        ?rQ  zRun Line -1.5      @rT  rU  zHome team run linerX  r  r  s                  r   r   %SportsBacktestingEngine._mlb_run_line^  sF   

7C(DR0IR0I.$((;2JKPqJ.$((;2JKPqJJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyIZJ *q0C$'US[eVFMM!$+S4& ){%0$'5V*.
 
 4 ds|r   c                    / nUR                  SS5      nU GHP  nUR                  SS5      nUR                  SS5      n	UR                  SUR                  SS5      5      =(       d    Sn
UR                  S	UR                  S
S5      5      =(       d    SnUR                  SS5      nUR                  S5      (       d  UR                  S5      (       a%  UR                  SUR                  SS5      5      SS OSnU(       a  U
(       a  U(       d  M  X-   nX=(       d    S:  nU(       a  US-  OU* nUR                  UU	 SU 3SSU 3USU(       a  SOS[        US5      SS.	5        GMS     USS $ )z)Bet on MLB over (total runs exceeds line)r=  r>  r   rY   r   r$   r#   r   r'   r&   r.   g      !@r)   r*   Nrp   rP  rQ  r  r  rS  rT  rU  rV  zMLB over betrX  r  )r   r(  r)  r*  r	  r  r=  r   rb   r   r   r   r   rg  r9  ri  r\  s                    r   r   'SportsBacktestingEngine._mlb_over_under  s^   

7C(DR0IR0I.$((;2JKPqJ.$((;2JKPqJ+s3JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyIZJ+E ,-C$'US[eVFMM!$+S4($ZL1$'5V*(
 
# : ds|r   c                 &    U R                  XS5      $ )zBet on NHL home favoritesNHLrs  ru  s        r   r   *SportsBacktestingEngine._nhl_home_favorite  rw  r   c                 j   / nUR                  SS5      nU GH  nUR                  SS5      nUR                  SS5      n	UR                  SS5      =(       d    Sn
UR                  SS5      =(       d    SnUR                  S	5      (       d  UR                  S
5      (       a%  UR                  S	UR                  S
S5      5      SS OSnU(       a  U
(       a  U(       d  M  X-
  S:  nU(       a  US-  OU* nUR                  UU	 SU 3SU S3USU(       a  SOS[        US5      SS.	5        GM     USS $ )zBet on NHL puck line (-1.5)r=  r>  r   rY   r   r"   r   r%   r)   r*   Nrp   rV  r  rQ  z	Puck Liner  r  rT  rU  zHome team puck linerX  r  r  s                  r   r   &SportsBacktestingEngine._nhl_puck_line  s0   

7C(DR0IR0I/15:J/15:JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyIZJ *q0C$'US[eVFMM!$+S4' ){%0$'5V*/
 
 4 ds|r   c                 &    U R                  XX45      $ )r}  )r   ru  s        r   r   )SportsBacktestingEngine._nhl_back_to_back  s    %%eIFFr   c                 &    U R                  XS5      $ )zBet on CFB home favoritesCFBrs  ru  s        r   r   *SportsBacktestingEngine._cfb_home_favorite  rw  r   c                 &    U R                  XX45      $ )z%Bet on home teams in conference games)r   ru  s        r   r   'SportsBacktestingEngine._cfb_conference  s    ##E)DDr   c                    / nUR                  SS5      nU GH<  nUR                  SS5      nUR                  SS5      n	UR                  SS5      =(       d    Sn
UR                  SS5      =(       d    SnUR                  S	S
5      nUR                  S5      (       d  UR                  S5      (       a%  UR                  SUR                  SS5      5      SS OSnU(       a  U
(       a  U(       d  M  X-
  nU[        U=(       d    S5      :  nU(       a  US-  OU* nUR                  UU	 SU 3SU SU 3USU(       a  SOS[        US5      SS.	5        GM?     USS $ )zBet against the spread in CFBr=  r>  r   rY   r   r"   r   r%   r,   ir)   r*   Nrp      rP  rQ  SpreadrV   rS  rT  rU  rV  zHome team spread betrX  )r/   rn  r   rb  )r   r(  r)  r*  r	  r  r=  r   rb   r   r   r   r\   rg  rs   coveredr\  s                    r   r   #SportsBacktestingEngine._cfb_spread  sR   

7C(DR0IR0I/15:J/15:JXXmR0FJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyIZJ  ,Fs6;Q//G$+US[%FMM!$+S4$ ){!F84$+5*0
 
! 8 ds|r   c                 &    U R                  XS5      $ )zBet on CBB home favoritesCBBrs  ru  s        r   r   *SportsBacktestingEngine._cbb_home_favorite  rw  r   c                 &    U R                  XS5      $ )z"Bet in conference tournament gamesr  rs  ru  s        r   r   'SportsBacktestingEngine._cbb_conference  rw  r   c                 p   / nUR                  SS5      nU GH  nUR                  SS5      nUR                  SS5      n	UR                  SS5      =(       d    Sn
UR                  SS5      =(       d    SnUR                  S	5      (       d  UR                  S
5      (       a%  UR                  S	UR                  S
S5      5      SS OSnU(       a  U	(       d  M  U
(       a  U(       d  M  X:  nU(       a  US-  OU* nUR                  UU	 SU 3SU	USU(       a  SOS[        US5      SS.	5        GM     USS $ )z:March Madness upset strategy - bet on away team (underdog)r=  r>  r   rY   r   r"   r   r%   r)   r*   Nrp   r  rQ  rR  g      @rT  rU  rV  zTournament underdog betrX  2   r  r  s                  r   r   *SportsBacktestingEngine._cbb_march_madness  s,   

7C(DR0IR0I/15:J/15:JJN((S]J^J^bfbjbjkpbqbqTXXeR-@A#2FwyII : )C$'US[eVFMM!$+S4'&$'5V*3
 
% < cr{r   c                    / nUR                  SS5      nU GHa  nUR                  S5      =(       d    0 nUR                  S5      n	UR                  S5      n
UR                  S5      =(       d    0 nUR                  S5      nU	b	  U
b  US	;  a  My  S
[        S[        4S jnU" U	5      nU" U
5      nX:  a  SOSnUU:H  nUS:X  a  U	OU
nU(       a   US:  a  UUS-  -  OUS[        U5      -  -  nOU* nUR                  SS5      nUR                  SS5      nUR                  S5      =(       d    SSS =(       d    SnUR                  UU SU 3SUS:X  a  UOUUUU(       a  SOS[	        US5      SS.	5        GMd     U$ ) zLBet the favorite (lower implied probability / typically negative moneyline).r=  r>  r   rj   rl   rv   rr   Nr4   r5   ar   c                 V    [        U 5      n U S:  a  U S-  S-   $ S[        U 5      -  S-   $ Nr         Y@g      ?rm  r  s    r   american_to_decimalBSportsBacktestingEngine._mma_favorite.<locals>.american_to_decimal:  1    !H,-EE	CMA8LMr   r4   r5   r   r  r   	Fighter 1r   	Fighter 2r(   rY   rp   rI   vs rR  rT  rU  rV  z%MMA favorite (by implied probability)rX  r/   r   rn  r   rb  r   r(  r)  r*  r	  r  r=  r   r   ml_homeml_awayresrr   r  home_decaway_decpickri  odds_americanr\  r4   r5   r(   s                          r   r   %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                    / nUR                  SS5      nU GHa  nUR                  S5      =(       d    0 nUR                  S5      n	UR                  S5      n
UR                  S5      =(       d    0 nUR                  S5      nU	b	  U
b  US	;  a  My  S
[        S[        4S jnU" U	5      nU" U
5      nX:  a  SOSnUU:H  nUS:X  a  U	OU
nU(       a   US:  a  UUS-  -  OUS[        U5      -  -  nOU* nUR                  SS5      nUR                  SS5      nUR                  S5      =(       d    SSS =(       d    SnUR                  UU SU 3SUS:X  a  UOUUUU(       a  SOS[	        US5      SS.	5        GMd     U$ ) zMBet the underdog (higher implied probability / typically positive moneyline).r=  r>  r   rj   rl   rv   rr   Nr  r  r   c                 V    [        U 5      n U S:  a  U S-  S-   $ S[        U 5      -  S-   $ r  rm  r  s    r   r  BSportsBacktestingEngine._mma_underdog.<locals>.american_to_decimalk  r  r   r4   r5   r   r  r   r  r   r  r(   rY   rp   rI  r  rR  rT  rU  rV  z%MMA underdog (by implied probability)rX  r  r  s                          r   r   %SportsBacktestingEngine._mma_underdog\  r  r   c                    / nUR                  SS5      nU GH  nUR                  S0 5      nUR                  S0 5      n[        U[        5      (       a  UR                  S5      OS=(       d2    UR                  SUR                  SUR                  S	S
5      5      5      n	[        U[        5      (       a  UR                  S5      OS=(       d2    UR                  SUR                  SUR                  SS
5      5      5      n
UR                  S0 5      nUR                  S5      =(       db    UR                  S5      =(       dJ    UR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SnUR                  S5      =(       db    UR                  S5      =(       dJ    UR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SnUR                  SUR                  SUR                  SUR                  SS
5      5      5      5      n[        U[        5      (       a  [	        U5      S:  a  USS nU	(       d  GMe  U(       a  U(       d  GMv  X:  nUR                  S0 5      nUR                  S 5      nU(       a  U(       a  U R                  UU5      OU* nUnOU(       a  US!-  OU* nS"nUR                  U(       a  [        U5      SS OS#U
 S$U	 3S%U	UUU(       a  S&OS'[        US(5      U S)3S*.	5        GM"     USS+ $ ),zGeneric home favorite strategyr=  r>  rb   rc   abbreviationNr   r   r   rY   r   r   r   r   r_   r"   r#   r    r$   r   ra   r%   r&   r!   r'   r)   r*   r(   r  rp   r   rj   rP  rI  rQ  rR  rT  rU  rV  z home favoriterX     )r/   
isinstancer0   r   r   ro  r   rb  )r   r(  r	  r;   r  r=  r   home_team_objvisitor_team_objrb   r   r   r   r   rg  ri  odds_objr  r\  rk  s                       r   rt  .SportsBacktestingEngine._generic_home_favorite  s|   

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\^bAcAc)--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	 : )C xx+Hll?3GCF//?UF" ),%MM/8Is+i$+S4'& $'5V*"G>2
 
c z ds|r   c                    / nUR                  SS5      nU GH  nUR                  S0 5      nUR                  S0 5      n[        U[        5      (       a  UR                  S5      OS=(       d2    UR                  SUR                  SUR                  S	S
5      5      5      n	[        U[        5      (       a  UR                  S5      OS=(       d2    UR                  SUR                  SUR                  SS
5      5      5      n
UR                  S0 5      nUR                  S5      =(       db    UR                  S5      =(       dJ    UR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SnUR                  S5      =(       db    UR                  S5      =(       dJ    UR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SnUR                  SUR                  SUR                  SUR                  SS
5      5      5      5      nU
(       d  GM<  U(       a  U(       d  GMM  X:  nUR                  S0 5      nUR                  S5      nU(       a  U(       a  U R                  UU5      OU* nUnOU(       a  US -  OU* nS!nUR	                  UU
 S"U	 3S#U
UUU(       a  S$OS%[        US&5      U S'3S(.	5        GM     USS $ ))zGeneric road underdog strategyr=  r>  rb   rc   r  Nr   r   r   rY   r   r   r   r   r_   r"   r#   r    r$   r   ra   r%   r&   r!   r'   r)   r*   r(   r  r   rl   r  r  rQ  rR  rT  rU  rV  z road underdogrX  )r/   r  r0   ro  r   rb  )r   r(  r	  r;   r  r=  r   r  r  rb   r   r   r   r   rg  ri  r  r  r\  rk  s                       r   rz  .SportsBacktestingEngine._generic_road_underdog  sH   

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\^bAcAc)--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 : )C xx+Hll?3GCF//?UF"(+%MM!$+S4'& $'5V*"G>2
 
Y p ds|r   c                 &    U R                  XS5      $ )z4Fallback for dynamic strategies - uses home favoriteDYNAMICrs  ru  s        r   r   )SportsBacktestingEngine._dynamic_strategy  s    **5)DDr   date1date2c                      SSK J nJn  UR                  " USS S5      nUR                  " USS S5      nXe-
  R                  S:H  $ !    g= f)z%Check if date2 is the day after date1r   )r   	timedeltaNrp   z%Y-%m-%drx   F)r   r   strptimedays)r   r  r  r   r   d1d2s          r   r  $SportsBacktestingEngine._is_next_day  sU    	4""5":z:B""5":z:BG>>Q&&	s   AA Ar  c                    U(       d  SSSSSSSSS.$ [        S U 5       5      n[        U5      U-
  n[        SU-  [        U5      -  S5      nU Vs/ s H  ofS   PM	     nn[        [        U5      S5      n[        S U 5       5      n	[        [        S U 5       5      5      n
U
S:  a  [        X-  S5      OS	n/ nSnU H  nX-  nUR	                  U5        M     SnSnU H  nUU:  a  UnUU-
  nUU:  d  M  UnM     SS
Kn[        U5      S:  a=  UR                  U5      nUR                  U5      nUS:  a  [        UU-  S-  S5      OSnOSn[        U5      UUUUU[        US5      U[        U[        U5      -  S5      [        U5      [        U5      [        U	S5      [        U
S5      [        U5      UUUS.S.$ s  snf )z&Calculate backtest results from tradesr   )r  winslossesr  r  r  r  r  c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)r[  rT  rx   Nr   )rz   ts     r   r{   =SportsBacktestingEngine._calculate_results.<locals>.<genexpr>0  s     >f)(=11fs   	r>  rV  r\  c              3   4   #    U  H  oS :  d  M
  Uv   M     g7fr   Nr   rz   ps     r   r{   r  7  s     7gQ11g   		c              3   4   #    U  H  oS :  d  M
  Uv   M     g7fr  r   r  s     r   r{   r  8  s     91q5QQr  gR?@Nrx   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   rb  rn  r   
statisticsmeanstdevmaxr  )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"  *SportsBacktestingEngine._calculate_results"  s    ! !!" ! !	 	 >f>>Vt#tc&k115(./1X;/S\1-7g77999:
?IA~l7;SY 
ALG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   G r  strategyc                     SUR                  5        SU SUS    SUS    SUS    S	US
    SUS    SUR                  SS5       SUR                  5        S3$ )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  r;   r)  s       r   r#  )SportsBacktestingEngine._generate_summaryj  s    ;;=/%hZ 0 () *Z ! ".)* +/*+ ,.)* +^U34 5'',{{}o 6 	r   c           	         U(       d  SS0$ / nSn/ n[        U5       HN  u  pVX6S   -  nUR                  [        US5      5        UR                  UR                  SSUS-    35      5        MP     S	US
UUS   S:  a  SOSSS./[	        U5      U(       a  US   OSU(       a  [        U5      OSU(       a  [        U5      OSS.S.$ )z!Generate chart visualization datar   zNo trades to visualizer   r\  rV  r(   zTrade rx   linezCumulative P/Lz#10B981z#EF4444F)labelr   borderColorfill)r  	final_pnlpeak_pnl
trough_pnl)rX   labelsdatasetssummary)	enumerater   rb  r/   r   r  r  )r   r  r  r   r5  itrades          r   r$  ,SportsBacktestingEngine._generate_chart_dataz  s    566
!&)HAX&GeGQ/0MM%))FfQqSEN;< * )",6rNQ,>yI	  !$F/9Z^q/9C
Oq1;c*o	
 	
r   r   ri  c                     U(       d  U* $ Uc  U$  [        U5      nUS:  a  XS-  -  $ US:  a  US[        U5      -  -  $ U$ ! [         a    Us $ f = f)z6Return profit (not return) for a bet at American odds.r   r  )r   r2   rn  )r   r=  r   ri  r   s        r   _american_profit(SportsBacktestingEngine._american_profit  so    6M<L	dA q5I&&q5ECFN++  	L	s   A AAc                    / nUR                  SS5      nU GH  nUR                  SUR                  SS5      5      nUR                  SUR                  SS5      5      n	UR                  SUR                  S	S
5      5      =(       d    S
n
UR                  SUR                  SS
5      5      =(       d    S
nUR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SSS nU(       a  U(       d  M  UR                  S5      =(       d    0 nUR                  S5      nUR                  S5      nUR                  S5      nUb  Uc  GMQ  S nU" U5      nU" U5      nU" U5      nUb  Uc  GMu  UU::  a  GM~  Ub	  UU::  a  GM  X:  nU R                  XnU5      nUR                  UU	 SU 3SU S3UUU(       a  SOS[        US5      SS.	5        GM     USS $ ) zDBet home team when it is the clear favorite vs away/draw (3-way ML).r=  r>  r   r   rY   r   r   r"   r#   r   r%   r&   r)   r*   r(   Nrp   r   rj   moneylineDrawrl   c                     U c  g  [        U 5      n U S:  a  SU S-   -  $ U S:  a
  U * U * S-   -  $ g ! [         a     g f = f)Nr   r  )r   r2   )r   s    r   imp:SportsBacktestingEngine._soccer_home_favorite.<locals>.imp  sa    : rB 6 BJ//6CbSEM22 !   s   0 
==rQ  rR  z MLrT  rU  rV  zHome is favorite (3-way ML)rX     r/   r=  r   rb  )r   r(  r)  r*  r	  r  r=  r   rb   r   r6   r7   r(   r   ml_hml_dml_arB  p_hp_ap_dri  r\  s                          r   r   -SportsBacktestingEngine._soccer_home_favorite  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88O,D88O,D88O,D|t| d)Cd)Cd)C{ckcz3#:(C**5<FMM$+S4' ){#.$'5V*7
 
Y p ds|r   c                 ,   / nUR                  SS5      nU GHu  nUR                  SUR                  SS5      5      nUR                  SUR                  SS5      5      n	UR                  SUR                  S	S
5      5      =(       d    S
n
UR                  SUR                  SS
5      5      =(       d    S
nUR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SSS nU(       a  U(       d  M  UR                  S5      =(       d    0 nUR                  S5      nUc  GM,  X:H  nU R                  XnU5      nUR                  UU	 SU 3SSUUU(       a  SOS[        US5      SS.	5        GMx     USS $ )z.Bet draw when draw odds are available (3-way).r=  r>  r   r   rY   r   r   r"   r#   r   r%   r&   r)   r*   r(   Nrp   r   r@  rQ  rR  DrawrT  rU  rV  z3-way draw betrX  rD  rE  )r   r(  r)  r*  r	  r  r=  r   rb   r   r6   r7   r(   r   rG  ri  r\  s                    r   r   $SportsBacktestingEngine._soccer_draw  si   

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                    / nUR                  SS5      nU GH  nUR                  SUR                  SS5      5      nUR                  SUR                  SS5      5      n	UR                  SUR                  S	S
5      5      =(       d    S
n
UR                  SUR                  SS
5      5      =(       d    S
nUR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    SSS nU(       a  U(       d  M  UR                  S5      =(       d    0 nUR                  S5      nUc  GM,   [        U5      nUS:w  a  GMA  X-   nUS:  nU R                  USU5      nUR	                  UU	 SU 3SSUSU(       a  SOS[        US5      SS.	5        GM     USS $ ! [         a     GM  f = f)z/Bet over 2.5 total goals when totalLine is 2.5.r=  r>  r   r   rY   r   r   r"   r#   r   r%   r&   r)   r*   r(   Nrp   r   r-   r  r  rQ  TotalzOver 2.5rT  rU  rV  zOver 2.5 goalsrX  rD  )r/   r   r2   r=  r   rb  )r   r(  r)  r*  r	  r  r=  r   rb   r   r6   r7   r(   r   r-  r9  ri  r\  s                     r   r   (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   F11
G ?G )r   r  )N2025)7r   r   r   r   r   r   r   r   r  r   r   r,  r   r!  r   r   ro  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   rt  rz  r   boolr  r"  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>   r   randomr   typingr   r   r   r   logging	getLoggerr   r   r?   r@   dirname__file__rA   r
   r   sports_enginer   r   r   <module>r\     s   	 
    , , 			8	$ bggoobggooh.GH&Qr rjf fT) ()r   