feat: cap-tier filtering, Alpaca cost model, README cleanup

- simulate.py: --cap-tier large|mid|small|micro; yfinance market cap fetch
  with DB cache (ticker_meta table); argv fix for main.py dispatch
- plot.py: equity curves now show cap tiers with Alpaca costs (zero commission);
  HP sweep uses Alpaca cost decomposition; SPY line clamped to last strategy date
- db/models.py: TickerMeta table
- db/db.py: get_cached_market_caps, upsert_market_caps
- README: add --cap-tier to simulate docs; backfill note (~3 days for 2 years
  at SEC 10 req/s limit); remove duplicate setup block; remove em-dashes in prose;
  results table tilde estimates to be updated once cap-tier sims complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 18:10:09 +02:00
co-authored by Claude Sonnet 4.6
parent 56ec0b4a81
commit d0e98b9cb7
6 changed files with 127 additions and 381 deletions
+23 -1
View File
@@ -6,7 +6,7 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
import config
from db.models import Base, Filing, PriceCache, Signal
from db.models import Base, Filing, PriceCache, Signal, TickerMeta
def _engine():
@@ -219,6 +219,28 @@ def get_signals_for_backtest(min_score: float, min_cluster_size: int) -> list[di
return [_signal_to_dict(r) for r in rows]
def get_cached_market_caps(tickers: list[str]) -> dict[str, float]:
if not tickers:
return {}
with _session() as session:
rows = session.scalars(
select(TickerMeta).where(TickerMeta.ticker.in_(tickers))
).all()
return {r.ticker: r.market_cap for r in rows if r.market_cap is not None}
def upsert_market_caps(caps: dict[str, float]) -> None:
with _session() as session:
for ticker, cap in caps.items():
existing = session.get(TickerMeta, ticker)
if existing:
existing.market_cap = cap
existing.fetched_at = datetime.utcnow()
else:
session.add(TickerMeta(ticker=ticker, market_cap=cap))
session.commit()
def get_cached_prices(ticker: str, start_date: str, end_date: str) -> dict[str, float]:
with _session() as session:
rows = session.scalars(
+8
View File
@@ -66,6 +66,14 @@ class Signal(Base):
)
class TickerMeta(Base):
__tablename__ = "ticker_meta"
ticker = Column(String, primary_key=True)
market_cap = Column(Float, nullable=True)
fetched_at = Column(DateTime, default=datetime.utcnow)
class PriceCache(Base):
__tablename__ = "price_cache"