
    oi9                     T   d Z ddlZddlZddlZddlmZmZmZ ddlmZ i ddddddd	d
dd
dd
ddddddddddddddddddddddi ddddddd dd!dd"dd#d$d%d$d&d$d'd(d)d(d*d(d+d,d-d,d.d,d/d0d1d0i d2d0d3d4d5d4d6d4d7d8d9d8d:d8d;d<d=d<d>d<d?d@dAd@dBd@dCdDdEdDdFdDdGdHi dIdHdJdHdKdLdMdLdNdLdOdLdPdQdRdQdSdQdTdUdVdUdWdUdXdYdZdYd[dYd\dYd]d^i d_d^d`d^dadbdcdbdddbdedbdfdgdhdgdidgdjdkdldkdmdkdndkdodpdqdpdrdpdsdtdtdtdudududvdvdvdwdwdwdxi dydzd{dzd|dzd}dd~dddddddddddddddddddddddddi dddddddddddddd$dd$dd(dd(dddddddd0dd0dd4dd4i dd4dddddddddddddddddddd8dd8ddddddDddDddLi ddLddddddddddddddddddddbddbddǓddǓddǓdd˓dd˓dddddddddddddwdwdМi ddғddғddғddzddzdd
dd
ddddddܓddܓddܓddddddddddi dddddddddddddddddddd(dd(ddddddddddddi dddqdddLddLddddddd dddddddddddddd	dd
dddi ddddddddddddddbddbddǓddǓddǓdddddddd͓dd͓d d!i d"d!d#d!d$d!d%d&d'd&d(d&d)dud*dud+dud,dvd-dvd.d/d0d/d1d/d2d3d4d3d5d3d3d6d6d6d7d7d7d8i i i d9Z	d:e
d;e
d<e
fd=Zd> Zd? Zed@k(  r e        yy(A  z
ETL: Populate Opening/Closing Lines from OddsSnapshot to SportsGame
Uses team name matching since externalGameIds don't match between sources.

Run: python3 scripts/etl_opening_closing_lines.py
    N)datetimetimezone	timedelta)defaultdictzatlanta hawksATLhawksatlantazboston celticsBOScelticsbostonzbrooklyn netsBKNnetsbrooklynzcharlotte hornetsCHAhornets	charlottezchicago bullsCHIbullschicagozcleveland cavaliersCLE	cavalierscavs	clevelandzdallas mavericksDAL	mavericksmavsdallaszdenver nuggetsDENnuggetsdenverzdetroit pistonsDETpistonsdetroitzgolden state warriorsGSWwarriorszgolden statezhouston rocketsHOUrocketshoustonzindiana pacersINDpacersindianazlos angeles clippersLACclipperszla clipperszlos angeles lakersLALlakersz	la lakerszmemphis grizzliesMEM	grizzliesmemphisz
miami heatMIAheatmiamizmilwaukee bucksMILbucks	milwaukeezminnesota timberwolvesMINtimberwolveswolves	minnesotaznew orleans pelicansNOPpelicansznew orleansznew york knicksNYKknicksznew yorkzoklahoma city thunderOKCthunderzoklahoma cityokczorlando magicORLmagicorlandozphiladelphia 76ersPHI76erssixersphiladelphiazphoenix sunsPHXsunsphoenixzportland trail blazersPORztrail blazersblazersportlandzsacramento kingsSACkings
sacramentozsan antonio spursSASTORUTAWAS)spurszsan antonioztoronto raptorsraptorstorontoz	utah jazzjazzutahzwashington wizardswizards
washingtonzarizona cardinalsARI	cardinalsarizonazatlanta falconsfalconszbaltimore ravensBALravens	baltimorezbuffalo billsBUFbillsbuffalozcarolina panthersCARpantherscarolinazchicago bearsbearszcincinnati bengalsCINbengals
cincinnatizcleveland brownsbrownszdallas cowboyscowboyszdenver broncosbroncoszdetroit lionslionszgreen bay packersGBpackersz	green bayzhouston texanstexanszindianapolis coltscoltsindianapoliszjacksonville jaguarsJAXjaguarsjacksonvillezkansas city chiefsKCchiefszkansas cityzlas vegas raidersLVraidersz	las vegaszlos angeles chargerschargerszlos angeles ramsLARramszmiami dolphinsdolphinszminnesota vikingsvikingsznew england patriotsNEpatriotsznew englandznew orleans saintsNOsaintsznew york giantsNYGgiantsznew york jetsNYJjetszphiladelphia eagleseagleszpittsburgh steelersPITsteelers
pittsburghzsan francisco 49ersSF49ersSEATBTEN)zsan francisconinerszseattle seahawksseahawksseattleztampa bay buccaneers
buccaneersbucsz	tampa bayztennessee titanstitans	tennesseezwashington commanders
commanderszanaheim ducksANAducksanaheimzarizona coyotescoyoteszboston bruinsbruinszbuffalo sabressabreszcalgary flamesCGYflamescalgaryzcarolina hurricanes
hurricanescaneszchicago blackhawks
blackhawkszcolorado avalancheCOL	avalancheavscoloradozcolumbus blue jacketsCBJzblue jacketscolumbuszdallas starsstarszdetroit red wingsz	red wingszedmonton oilersEDMoilersedmontonzflorida panthersFLAfloridazlos angeles kingsLAKzminnesota wildwildzmontreal canadiensMTL	canadienshabsmontrealznashville predatorsNSH	predatorspreds	nashvilleznew jersey devilsNJDdevilsz
new jerseyznew york islandersNYI	islandersznew york rangersNYRrangerszottawa senatorsOTTsenatorssensottawazphiladelphia flyersflyerszpittsburgh penguinspenguinspenszsan jose sharksSJSsharkszsan josezseattle krakenkrakenzst. louis bluesSTLblueszst louis blueszsaint louis bluesztampa bay lightningTBL	lightningboltsztoronto maple leafszmaple leafsleafszutah hockey clubr\   zvancouver canucksVANcanucks	vancouverzvegas golden knightsVGKzgolden knightsknightsWSHWPG)vegaszwashington capitalscapitalscapszwinnipeg jetsr   winnipeg)nbanflnhlmlbncaabncaaf	team_nameleaguereturnc                 0   | syt        |       dk  r| j                         r| S | j                         j                         }t        j                  |i       }||v r||   S |j                         D ]  \  }}||v s||v s|c S  | dd j                         S )z,Normalize team name to standard abbreviationN      )lenisupperlowerstripTEAM_ALIASESgetitemsupper)r   r   
team_lowerleague_aliasesaliasabbrevs         >/var/www/html/eventheodds/scripts/etl_opening_closing_lines.pynormalize_teamr      s     9~y002 "((*J "%%fb1N^#j)) (--/ vJ*"5M
 Ra=      c                     d} 	 t        | d      5 }|D ]b  }|j                  d      s|j                  dd      d   j                         j                  d      j                  d      d   c cd d d        S  	 d d d        t
        j                  j                  d	d
      j                  d      d   S # 1 sw Y   ;xY w# t        $ r Y Iw xY w)Nz/var/www/html/eventheodds/.envrzSPORTS_DATABASE_URL==   "?r   SPORTS_DATABASE_URL )open
startswithsplitr   FileNotFoundErrorosenvironr   )env_pathflines      r   load_db_urlr     s    /H(C  	RA R??#9:::c1-a0668>>sCII#NqQQ	R 	RR	R ::>>/4::3?BB	R 	R  s:   B? B3AB3-	B? 7B39B? 3B<8B? ?	C
Cc                     t        d       t        d       t        dt        j                  t        j                        j                                 t        d       t               } | st        d      t        j                  |       }|j                         }ddddd}t        d       |j                  d       |j                         }t        d	t        |       d
       |j                  d       i }|j                         D ]H  \  }}}}	}
t        |	|      }t        |
|      }|t        |      ||f}|t        |      ||f}|||<   |||<   J d}|D ]p  \  }}}}}	}
|st        |j!                               }t        |	|      }t        |
|      }||||f}|j#                  |      }|sX|j                  d||f       |dz  }r |j%                          ||d<   t        d| d       t        d       |j                  d       |j&                  |d<   t        d|j&                   d       |j%                          t        d       |j                  d       |j&                  |d<   t        d|j&                   d       |j%                          t        d       |j                  d       t        ddddd d!dd"d#dd$d#       t        dd% dd% dd& dd&        |j                         D ]T  }|\  }}}}}|dkD  rd'|z  |z  d(d)nd*}|dkD  rd'|z  |z  d(d)nd*}t        d|dd|d!d|d+d,|d-d.|d+d,|d-d/       V |j)                          |j)                          t        d0       t        d1       t        d2|d           t        d3|d           t        d4|d           t        d       |S )5Nz<============================================================z/ETL: OPENING/CLOSING LINES (Team Name Matching)zTime: zSPORTS_DATABASE_URL not setr   )games_linkedopening_setclosing_setalready_linkedz8
[1] Linking OddsSnapshot to SportsGame by team names...z
        SELECT id, league, "externalGameId", "gameDate", "homeTeam", "awayTeam"
        FROM "OddsSnapshot"
        WHERE "gameId" IS NULL
        ORDER BY league, "gameDate"
    z  Found z unlinked snapshotsz
        SELECT id, league, DATE("gameDate") as gd, "homeTeam", "awayTeam"
        FROM "SportsGame"
        WHERE "gameDate" >= '2024-10-01'
    zS
                UPDATE "OddsSnapshot" SET "gameId" = %s WHERE id = %s
            r   r  z	  Linked z  snapshots to SportsGame recordsz 
[2] Populating opening lines...a  
        WITH earliest_snapshots AS (
            SELECT DISTINCT ON ("gameId")
                "gameId",
                "spreadHome",
                "spreadAway",
                "moneylineHome",
                "moneylineAway",
                "total",
                "snapshotAt"
            FROM "OddsSnapshot"
            WHERE "gameId" IS NOT NULL
              AND "spreadHome" IS NOT NULL
            ORDER BY "gameId", "snapshotAt" ASC
        )
        UPDATE "SportsGame" g SET
            "openingSpreadHome" = e."spreadHome",
            "openingSpreadAway" = e."spreadAway",
            "openingMoneylineHome" = e."moneylineHome",
            "openingMoneylineAway" = e."moneylineAway",
            "openingTotal" = e."total",
            "openingCapturedAt" = e."snapshotAt",
            "updatedAt" = NOW()
        FROM earliest_snapshots e
        WHERE g.id = e."gameId"
          AND (g."openingSpreadHome" IS NULL OR g."openingCapturedAt" > e."snapshotAt")
    r  z  Set opening lines for z gamesz 
[3] Populating closing lines...a  
        WITH latest_pregame AS (
            SELECT DISTINCT ON (s."gameId")
                s."gameId",
                s."spreadHome",
                s."spreadAway",
                s."moneylineHome",
                s."moneylineAway",
                s."total",
                s."snapshotAt"
            FROM "OddsSnapshot" s
            JOIN "SportsGame" g ON s."gameId" = g.id
            WHERE s."gameId" IS NOT NULL
              AND s."spreadHome" IS NOT NULL
              AND s."snapshotAt" < g."gameDate"
            ORDER BY s."gameId", s."snapshotAt" DESC
        )
        UPDATE "SportsGame" g SET
            "closingSpreadHome" = l."spreadHome",
            "closingSpreadAway" = l."spreadAway",
            "closingMoneylineHome" = l."moneylineHome",
            "closingMoneylineAway" = l."moneylineAway",
            "closingTotal" = l."total",
            "closingCapturedAt" = l."snapshotAt",
            "updatedAt" = NOW()
        FROM latest_pregame l
        WHERE g.id = l."gameId"
          AND g."homeScore" IS NOT NULL  -- Game completed
          AND (g."closingSpreadHome" IS NULL OR g."closingCapturedAt" < l."snapshotAt")
    r  z  Set closing lines for z
[4] Coverage Report:a  
        SELECT
            league,
            COUNT(*) as total,
            COUNT(*) FILTER (WHERE "homeScore" IS NOT NULL) as completed,
            COUNT(*) FILTER (WHERE "openingSpreadHome" IS NOT NULL) as has_opening,
            COUNT(*) FILTER (WHERE "closingSpreadHome" IS NOT NULL) as has_closing
        FROM "SportsGame"
        WHERE "gameDate" >= '2024-10-01'
          AND league IN ('nba', 'nfl', 'nhl', 'ncaab', 'epl', 'mma')
        GROUP BY league
        ORDER BY total DESC
    z  Leaguez<10 	Completedz>10Openingz>12Closingz
----------z------------d   z.1f%z0%z>8z (z>5z) )z=
============================================================zETL Complete:z  Snapshots linked: z  Opening lines set: z  Closing lines set: )printr   nowr   utc	isoformatr  RuntimeErrorpsycopg2connectcursorexecutefetchallr   r   strdater   commitrowcountclose)db_urlconncurstatsunlinked	sg_lookupsg_idr   gdhomeaway	home_norm	away_normkey1key2linked_countos_idext_id	game_datedate_strkeyrowtotal	completedopeningclosingopen_pct	close_pcts                               r   run_etlrE     s#   	(O	
;<	F8<<-779:
;<	(O]F899F#D
++-C 	E 

EF KK  	 ||~H	HS]O#6
78 KK  	
 I),  %vr4"40	"40	BI6BI6	$	$  L8@ 4vvy$y~~'("40	"40	xI6c"KK ! AL  	KKM(E.	Il^#C
DE 

-.KK  	6 <<E-	$S\\N&
9:KKM 

-.KK  	< <<E-	$S\\N&
9:KKM 

"#KK  	 
BxnAk#.a	#a	#
OP	Bvhaxq&
23||~ l582y'76?!mc'k)+C027@1}s7{9,S13$	6#,a	#a|2hr]"WUWLXZ[degZhhijk	l IIKJJL	/	M	 ~!6 7
89	!%"6!7
89	!%"6!7
89	(OLr   __main__)__doc__r   r  rer   r   r   collectionsr   r   r%  r   r  rE  __name__ r   r   <module>rL     s6    	 	 2 2 # '095%!*E3;U 	 !' 0:5 	U	 %.u	 7B5	
 	
 !(
 1:5 	u '25 ;A% JUV[ 	E $/ 8>u GOPU 	% "+E 4<U 	5 #,U 5>u 	  )3E <J5 	5 #,U 5>u 	% "*5 3<U 	 (25 ;H 	e &.u 7B5 	U %0 9B5  	e!  $U!  -4U!" 	5#" #*5#" 3>u#$ 	!%%$ *8%$ AI%%$ R]^c%& 	'& (25'& ;H'( 	5)( #+E)( 4>u)* 	 +* )25+* ;J5+* SXY^+, 	-, !(-, 1:5-. 	e/. &-e/. 6>u/. GUV[/0 	10  &u10 /812 	!%32 *9%32 BKE32 T^_d34 	E54 $+E54 4@56 	U76 .35 UuE5#U=B!U!$/!8A5!5!"+U! 	E! $,U! 5@! 		! !(	! 1:5	!
 	U!
 %/!
 8B5! 	! !(! 	e! &/! 8DU! 	E! $,U! 	%! "+E! 	%! "+E! 	! !(! 	T! $-d! 5@! 	%! "*5! 	e! &-e! 6DU! 	! (1%! :H!  	d!!  %-d!!  5B4!!" 	T#!" $-d#!" 5@#!$ 	%!$ (25%!& 	E'!& $*5'!( 	%)!( ",U)!* 	U+!* %.u+!, 	-!, '1$-!, 9Ft-!. 	d/!. %-d/!0 	51!0 #+E1!2 	3!2 !'3!4 	u5!4 '/5!6 	u7!6 '1%7!6 :Fu7!8 	t9!8 &-d9!8 FJUY!u $D$UY!U!&eA!F"" '"095"5""+U" 	" !)%" 	%	" "*5	"
 	%"
 "*5"
 3<U" 	u" '3E" <CE" 	e" &25" 	e" &1%" :?" HRSX" 	 " )7" @J5" 	"  '" 	U" %0" 	5" #+E" 4>u" 	E" $.u" 7@" 	U" %,U" 	%" "("  	e!"  &1%!"  :@!"  ISTY!"" 	u#"" '25#"" ;B5#"" KVW\#"$ 	U%"$ %-e%"$ 6B5%"& 	e'"& &1%'"( 	E)"( $-e)"* 	5+"* #-e+"* 6<U+"* EMe+", 	u-", '/-". 	u/". '1%/". :@/"0 	51"0 #+E1"0 4>u1"2 	%3"2 "*53"4 	55"4 #*55"4 3CE5"4 L_`e5"6 	u7"6 '257"6 ;B57"8 	u9"8 '4U9"8 =DU9": 	E;": $*5;"< 	U="< %.u="< 7B5="> 	?"> (8?"> AJ5?"> \a$%5C"H [nb!c !3 !3 !4	Cod zI r   