Optimize signal read paths and enforce score invariants
This commit is contained in:
@@ -10,9 +10,10 @@ import json
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy import select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database import insert_for_session
|
||||
from app.exceptions import NotFoundError
|
||||
from app.models.fundamental import FundamentalData
|
||||
from app.models.score import DimensionScore
|
||||
@@ -48,51 +49,45 @@ async def store_fundamental(
|
||||
"""
|
||||
ticker = await _get_ticker(db, symbol)
|
||||
|
||||
# Check for existing record
|
||||
result = await db.execute(
|
||||
select(FundamentalData).where(FundamentalData.ticker_id == ticker.id)
|
||||
)
|
||||
existing = result.scalar_one_or_none()
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
unavailable_fields_json = json.dumps(unavailable_fields or {})
|
||||
|
||||
if existing is not None:
|
||||
existing.pe_ratio = pe_ratio
|
||||
existing.revenue_growth = revenue_growth
|
||||
existing.earnings_surprise = earnings_surprise
|
||||
existing.market_cap = market_cap
|
||||
existing.next_earnings_date = next_earnings_date
|
||||
existing.fetched_at = now
|
||||
existing.unavailable_fields_json = unavailable_fields_json
|
||||
record = existing
|
||||
else:
|
||||
record = FundamentalData(
|
||||
ticker_id=ticker.id,
|
||||
pe_ratio=pe_ratio,
|
||||
revenue_growth=revenue_growth,
|
||||
earnings_surprise=earnings_surprise,
|
||||
market_cap=market_cap,
|
||||
next_earnings_date=next_earnings_date,
|
||||
fetched_at=now,
|
||||
unavailable_fields_json=unavailable_fields_json,
|
||||
)
|
||||
db.add(record)
|
||||
stmt = insert_for_session(db, FundamentalData).values(
|
||||
ticker_id=ticker.id,
|
||||
pe_ratio=pe_ratio,
|
||||
revenue_growth=revenue_growth,
|
||||
earnings_surprise=earnings_surprise,
|
||||
market_cap=market_cap,
|
||||
next_earnings_date=next_earnings_date,
|
||||
fetched_at=now,
|
||||
unavailable_fields_json=unavailable_fields_json,
|
||||
)
|
||||
stmt = stmt.on_conflict_do_update(
|
||||
index_elements=["ticker_id"],
|
||||
set_={
|
||||
"pe_ratio": stmt.excluded.pe_ratio,
|
||||
"revenue_growth": stmt.excluded.revenue_growth,
|
||||
"earnings_surprise": stmt.excluded.earnings_surprise,
|
||||
"market_cap": stmt.excluded.market_cap,
|
||||
"next_earnings_date": stmt.excluded.next_earnings_date,
|
||||
"fetched_at": stmt.excluded.fetched_at,
|
||||
"unavailable_fields_json": stmt.excluded.unavailable_fields_json,
|
||||
},
|
||||
).returning(FundamentalData)
|
||||
record = (await db.execute(stmt)).scalar_one()
|
||||
|
||||
# Mark fundamental dimension score as stale if it exists
|
||||
# TODO: Use DimensionScore service when built
|
||||
dim_result = await db.execute(
|
||||
select(DimensionScore).where(
|
||||
await db.execute(
|
||||
update(DimensionScore)
|
||||
.where(
|
||||
DimensionScore.ticker_id == ticker.id,
|
||||
DimensionScore.dimension == "fundamental",
|
||||
)
|
||||
.values(is_stale=True)
|
||||
)
|
||||
dim_score = dim_result.scalar_one_or_none()
|
||||
if dim_score is not None:
|
||||
dim_score.is_stale = True
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(record)
|
||||
return record
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user