feat: productionize local service — fix signal pipeline, lower thresholds, add company-name ticker extraction

- Point Ollama to local instance via host.docker.internal, use gemma3 model
- Remove Docker Ollama service (using host's Ollama instead)
- Add company-name-to-ticker mapping (Apple→AAPL, Tesla→TSLA, etc.) for RSS articles
- Lower signal thresholds for faster feedback with paper trading:
  - FinBERT confidence: 0.6→0.4, signal strength: 0.3→0.15
  - News strategy: article_count 2→1, confidence 0.5→0.3, score ±0.3→±0.15
- Fix market data BarSet access bug (BarSet.__contains__ returns False incorrectly)
- Fix market data SIP feed error by switching to IEX feed for free Alpaca accounts
- Fix nginx proxy routing for /api/auth/* to api-gateway /auth/*
- Add seed_sample_data script
- Update tests for new thresholds and alpaca mock modules
This commit is contained in:
Viktor Barzin 2026-02-22 22:17:26 +00:00
parent 67e64fab18
commit d36ae40df1
No known key found for this signature in database
GPG key ID: 0EB088298288D958
18 changed files with 749 additions and 185 deletions

View file

@ -10,12 +10,12 @@ class NewsDrivenStrategy(BaseStrategy):
"""Generate signals from aggregated news sentiment for a ticker.
**Buy signal** (LONG):
``avg_score > 0.3`` AND ``avg_confidence > 0.5`` AND
``article_count >= 2``.
``avg_score > 0.15`` AND ``avg_confidence > 0.3`` AND
``article_count >= 1``.
**Sell signal** (SHORT):
``avg_score < -0.3`` AND ``avg_confidence > 0.5`` AND
``article_count >= 2``.
``avg_score < -0.15`` AND ``avg_confidence > 0.3`` AND
``article_count >= 1``.
Signal strength = ``abs(avg_score) * avg_confidence``, clamped to
[0, 1].
@ -32,17 +32,17 @@ class NewsDrivenStrategy(BaseStrategy):
if sentiment is None:
return None
# Require at least 2 articles for statistical confidence.
if sentiment.article_count < 2:
# Require at least 1 article.
if sentiment.article_count < 1:
return None
# Require minimum confidence.
if sentiment.avg_confidence <= 0.5:
if sentiment.avg_confidence <= 0.3:
return None
if sentiment.avg_score > 0.3:
if sentiment.avg_score > 0.15:
direction = SignalDirection.LONG
elif sentiment.avg_score < -0.3:
elif sentiment.avg_score < -0.15:
direction = SignalDirection.SHORT
else:
# Sentiment is neutral — no opinion.