@ -480,13 +480,16 @@ class PriceDataService:
return None
now = datetime . now ( timezone . utc )
rows = [ ]
today = now . date ( )
historical_rows = [ ]
live_rows = [ ]
for date_idx , row in hist_data . iterrows ( ) :
price_date = date_idx . to_pydatetime ( )
if price_date . tzinfo is None :
price_date = price_date . replace ( tzinfo = timezone . utc )
rows . append ( {
target_rows = live_rows if price_date . date ( ) > = today else historical_rows
target_rows . append ( {
' id ' : _uuid . uuid4 ( ) ,
' ticker ' : ticker ,
' date ' : price_date ,
@ -501,12 +504,20 @@ class PriceDataService:
' updated_at ' : now ,
} )
if not rows:
if not historical_rows and not live_ rows:
return
# Upsert: on conflict update OHLCV + updated_at so that stale intraday-cached rows
# get overwritten when force_refresh=True re-fetches final EOD data.
stmt = pg_insert ( PriceData ) . values ( rows )
# Yahoo-adjusted historical prices are not point-in-time stable: future
# dividends/splits can rewrite old OHLC values. Preserve existing
# historical rows and only update today's row, where intraday partials
# legitimately need EOD replacement.
if historical_rows :
stmt = pg_insert ( PriceData ) . values ( historical_rows )
stmt = stmt . on_conflict_do_nothing ( constraint = ' uq_price_data ' )
await db . execute ( stmt )
if live_rows :
stmt = pg_insert ( PriceData ) . values ( live_rows )
stmt = stmt . on_conflict_do_update (
constraint = ' uq_price_data ' ,
set_ = {
@ -942,13 +953,16 @@ class PriceDataService:
return None
now = datetime . now ( timezone . utc )
rows = [ ]
today = now . date ( )
historical_rows = [ ]
live_rows = [ ]
for date_idx , row in ticker_data . iterrows ( ) :
price_date = date_idx . to_pydatetime ( )
if price_date . tzinfo is None :
price_date = price_date . replace ( tzinfo = timezone . utc )
rows . append ( {
target_rows = live_rows if price_date . date ( ) > = today else historical_rows
target_rows . append ( {
' id ' : _uuid . uuid4 ( ) ,
' ticker ' : ticker ,
' date ' : price_date ,
@ -963,10 +977,16 @@ class PriceDataService:
' updated_at ' : now ,
} )
if not rows:
if not historical_rows and not live_ rows:
return
stmt = pg_insert ( PriceData ) . values ( rows )
if historical_rows :
stmt = pg_insert ( PriceData ) . values ( historical_rows )
stmt = stmt . on_conflict_do_nothing ( constraint = ' uq_price_data ' )
await db . execute ( stmt )
if live_rows :
stmt = pg_insert ( PriceData ) . values ( live_rows )
stmt = stmt . on_conflict_do_update (
constraint = ' uq_price_data ' ,
set_ = {
@ -981,7 +1001,12 @@ class PriceDataService:
}
)
await db . execute ( stmt )
logger . info ( f " Batch upserted { len ( rows ) } price records for { ticker } " )
logger . info (
" Stored price records for %s : historical_insert_only= %d live_upsert= %d " ,
ticker ,
len ( historical_rows ) ,
len ( live_rows ) ,
)
async def _get_existing_dates_for_ticker (
self ,