Commit graph

32 commits

Author SHA1 Message Date
a417cae77b feat(kevin_bridge): blocklist + daily risk counters
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
2026-05-24 01:01:54 +00:00
3347847e38 feat(kevin_bridge): multi-mention aggregator with capped conviction boost
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
2026-05-24 01:01:02 +00:00
adbd7f3c65 feat(kevin_bridge): main orchestrator with dependency injection
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
Composable: cursor/aggregator/strategy/publisher/audit_writer/broker
all injected. Master kill-switch (kevin_enable_trading=false) routes to
audit-only path. Cursor advances ONLY after XADD succeeds (race fix).
Concrete collaborators wired in subsequent tasks.

Also extends TradeSignal + SignalDirection.EXIT with the optional
fields Kevin paths need (strategy_id, target_dollars, stop_loss_pct,
take_profit_pct).
2026-05-24 00:59:56 +00:00
ed2195d879 feat(meet-kevin): throttle inter-video LLM calls (30s) to stay under Anthropic RPM
First production run hit Anthropic's per-account rate_limit_error (429) trying
to burn through 16 backfill videos in seconds. The SDK's built-in retry can't
recover because the rate limit window resets slower than the 3 retry attempts.

Added meet_kevin_inter_video_sleep_seconds (default 30s) to PipelineDeps and
main's _process_pending_videos loop. 16 backfill videos now take ~8 min (16 * 30s
sleeps + ~30s per LLM call) instead of bursting into the rate limit.
2026-05-22 20:25:19 +00:00
8a1d03a967 refactor(meet-kevin): switch LLM back to native Anthropic SDK with OAuth bearer
Previous refactor (89f01ad) moved to OpenRouter because no sk-ant-api-* key
was found in Vault. Turns out claude-agent-service-spare-{1,2} hold
sk-ant-oat01-* OAuth tokens (108 chars, scope user:inference, 1-year TTL,
minted via 'claude setup-token' — see memory id=832).

These tokens work with the Anthropic SDK via the auth_token= constructor
argument (routes to Authorization: Bearer ... instead of x-api-key: ...).
They consume the Enterprise Claude subscription quota rather than
per-call billing, so the OpenRouter zero-credit problem goes away.

- llm_analyzer.py: revert OpenAI client to AsyncAnthropic; tool-use API
  + cache_control restored
- config.py: openrouter_api_key -> anthropic_oauth_token; model slug
  reverted from anthropic/claude-sonnet-4.5 -> claude-sonnet-4-5
- main.py: AsyncOpenAI -> AsyncAnthropic(auth_token=...), drop OpenRouter
  attribution headers
- pyproject: openai>=1.50 -> anthropic>=0.40 in meet_kevin extras
- tests: mocks ported back to messages.create + tool_use blocks
2026-05-22 19:24:40 +00:00
89f01ad9c0 refactor(meet-kevin): switch LLM analyzer to OpenRouter via OpenAI SDK
User's Vault has openrouter_api_key but no direct sk-ant-* Anthropic key.
OpenRouter passes through Claude Sonnet 4.6 (~3% markup over Anthropic
list pricing) and matches the existing gpt_mini_endpoint pattern used
by recruiter-responder.

- Replace anthropic.AsyncAnthropic with openai.AsyncOpenAI + base_url
- Convert Anthropic tool-use API to OpenAI function-calling
- System prompt unchanged (analyst instructions are model-agnostic)
- Drop cache_control (not in OpenAI API); revisit later if cost matters
- Model slug: anthropic/claude-sonnet-4.5 (OpenRouter's current Claude tier)
- Pricing: $3.10/M input, $15.50/M output (OpenRouter pass-through)
- Config field anthropic_api_key -> openrouter_api_key
- pyproject extras: anthropic>=0.40 -> openai>=1.50

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 09:52:55 +00:00
7b81980c66 fix(meet-kevin): API smoke-test bugs from Task 17 QA
Three issues caught during end-to-end manual QA against docker-compose:

1. SAEnum field columns serialized to Python enum NAMES ('DISCOVERED')
   but the DB enum had VALUES ('discovered'). Added `values_callable`
   to all 5 SAEnum() declarations in shared/models/meet_kevin.py so they
   emit values, matching the migration's enum literals.

2. /dashboard's "last 7 days" / "last 14 days" filters used
   `func.cast("7 days", type_=None)` which produced NullType DDL.
   Replaced with `text("now() - interval '7 days'")`.

3. /dashboard's outlook trend query repeated `func.date_trunc("day", col)`
   in SELECT, GROUP BY and ORDER BY — Postgres treats each as a separate
   parameterized expression. Hoisted into a single `day_trunc` variable
   so all three clauses reference the same SQL fragment.

All 11 /api/meet-kevin/* endpoints now return valid JSON against a
docker-compose Postgres seeded with one analyzed video + NVDA mention.
2026-05-21 20:15:08 +00:00
bfa7a503da feat(api): /api/meet-kevin/* routes (11 endpoints) 2026-05-21 19:53:16 +00:00
8f5ee8f1c3 feat(meet-kevin): pipeline orchestrator + service main loop
Implements Task 8 of the Meet Kevin revival plan.

- pipeline.py: PipelineDeps dataclass (frozen, DI-friendly), process_one_video
  state machine (discovered→captioned→analyzed with retry/cost-cap logic),
  and daily_cost_used() SQL helper.
- main.py: async run() entry point with RSS poll loop, per-video pipeline
  processing, OTEL counters, SIGTERM/SIGINT shutdown, httpx client lifecycle,
  and clean Anthropic/DB teardown.
- tests: 5 pipeline unit tests (happy path, no captions, cost cap, retry
  increment, failed-after-3-retries) all passing; full watcher suite 56/56.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 19:48:43 +00:00
8309556c00 feat(meet-kevin): Claude Sonnet 4.6 LLM analyzer (tool-use forcing + prompt cache)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 19:44:57 +00:00
145f7dbec5 feat(meet-kevin): caption extractor via yt-dlp
- Implement CaptionResult frozen dataclass for structured caption data
- Add parse_srt() to parse SubRip format with flexible timestamp handling
- Add extract_captions() async function using yt-dlp subprocess wrapper
- Prefer manual captions over auto-generated; clean up SRT files after parsing
- Add 16 comprehensive tests covering edge cases (empty input, malformed SRT,
  timestamp variations, language extraction, manual vs auto selection)
- Type-safe implementation with full mypy --strict compliance
- Add sample.srt fixture with 3 segments mentioning NVDA for test reference
2026-05-21 19:40:52 +00:00
8ce3ede09c feat(meet-kevin): RSS poller for YouTube uploads 2026-05-21 19:36:22 +00:00
8edcb070ed feat: scaffold meet_kevin_watcher service + config 2026-05-21 19:33:04 +00:00
Viktor Barzin
121ece5702
fix: add __main__ entrypoint to api-gateway so it starts under python -m
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Without this block, `python -m services.api_gateway.main` just imports
the module and exits with code 0, causing CrashLoopBackOff.
2026-02-28 11:22:52 +00:00
Viktor Barzin
a3cdd0f1a5
fix: resolve all remaining TODOs, add dev mode auth bypass
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- Learning engine: expand default weights from 3 to all 9 strategies
- Learning engine: resolve placeholder strategy_id with DB lookup
- Learning engine: pass strategy_sources from trade execution
- Trade executor: respect trading:paused Redis flag in RiskManager
- Portfolio sync: compute actual daily P&L from day-start snapshot
- Portfolio API: cumulative P&L from first snapshot, read pause flag
- Portfolio metrics: compute max drawdown and avg hold duration
- Add strategy_sources field to TradeExecution schema
- Add dev_mode config (TRADING_DEV_MODE) to bypass auth for local dev
- Dashboard: VITE_DEV_MODE bypasses ProtectedRoute and 401 redirects
- Vite proxy target configurable via VITE_API_TARGET
- Add top-level README.md and remaining-work-plan.md
- Update CLAUDE.md with correct counts and remove stale TODOs
- 404 tests passing

Made-with: Cursor
2026-02-25 22:02:25 +00:00
Viktor Barzin
4df7c67c13
fix: news articles showing 1970 dates when published_at is null
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Backend falls back to fetched_at when published_at is NULL in the database,
so the API always returns a meaningful date. Frontend also handles null
defensively to avoid new Date(null) producing Unix epoch 0.
2026-02-23 22:48:16 +00:00
Viktor Barzin
a2c08743ac
feat: make backtest work end-to-end with Alpaca bars, ticker selection, all 9 strategies
- Change BacktestRequest from strategy_weights dict to strategies list to match frontend
- Add tickers field so users can select which stocks to backtest
- Fetch historical bars from Alpaca StockHistoricalDataClient instead of empty data loader
- Register all 9 strategies (momentum, mean_reversion, news_driven, value, macd_crossover,
  bollinger_breakout, vwap, liquidity, ma_stack) filtered by user selection
- Fix response format: use frontend field names (max_drawdown, total_trades, win_rate as
  0-1 decimal), include equity_curve and run_id in response
- Add ticker selector with checkboxes and custom ticker input to dashboard
- Add alpaca-py to api dependency group in pyproject.toml
2026-02-23 22:25:41 +00:00
Viktor Barzin
b8eaa20d63
feat: wire 6 new strategies and fundamentals into signal generator 2026-02-23 21:55:59 +00:00
Viktor Barzin
6c909d12c3
feat: add MACD, Bollinger, VWAP, ATR, EMA, SMA-200 indicator computations 2026-02-23 21:49:26 +00:00
Viktor Barzin
99b041a0dd
fix: flush article before creating sentiment FK references
ArticleSentiment referenced db_article.id before the Article was flushed,
causing a NotNullViolationError on the article_id column. Adding an explicit
flush after session.add(db_article) ensures the UUID is populated before
creating the foreign key reference.
2026-02-23 20:57:11 +00:00
Viktor Barzin
d36ae40df1
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
2026-02-22 22:17:26 +00:00
Viktor Barzin
e2a3bd456d
feat: real data pipeline — market data, DB persistence, portfolio sync, signal-trade linkage
Wire the trading bot to real Alpaca market data and persist pipeline
state to the database so the dashboard displays live information.

- Add market-data service fetching OHLCV bars from Alpaca, publishing
  to market:bars Redis Stream; signal generator consumes bars and
  injects current_price into signals for position sizing
- Sentiment analyzer now persists Article + ArticleSentiment rows to
  DB after scoring, with duplicate and error handling
- API gateway runs a background portfolio sync task that snapshots
  Alpaca account state into PortfolioSnapshot/Position DB tables
  during market hours
- TradeSignal carries a signal_id UUID; signal generator and trade
  executor both persist their records to DB with cross-references
- 303 unit tests pass (57 new tests added)
2026-02-22 19:52:45 +00:00
Viktor Barzin
5a6b20c8f1
fix: resolve 13 important issues from code review
I1: Add graceful shutdown (SIGTERM/SIGINT) to all 5 background services
I2: Fix Dockerfile healthcheck to use curl on /metrics endpoint
I3: Fix StreamConsumer.ensure_group() to only catch BUSYGROUP errors
I4: Fix SimulatedBroker to reject orders with insufficient cash/shares
I5: Move ORM attribute access inside DB session context in trades routes
I6: Add Redis-based rate limiting (10 req/min/IP) on all auth endpoints
I8: Prevent backtest background task garbage collection
I9: Use Numeric(16,6) instead of Float for financial columns in migration
I10: Add index on trades.created_at for time-range queries
I11: Bind infrastructure ports to 127.0.0.1 in docker-compose
I12: Add migrations init service; all app services depend on it
I13: Fix user enumeration in login_begin (return options for non-existent users)
2026-02-22 17:58:01 +00:00
Viktor Barzin
2a56727267
fix: resolve 8 critical issues from code review
C1: Fix BacktestDataLoader constructor args (was passing wrong kwargs)
C2: Fix BacktestResult attribute names (max_drawdown_pct, avg_hold_duration)
C3: Remove insecure JWT secret default (now required via env var)
C4: Fix .env.example to use TRADING_ prefix for all config vars
C5: Add missing fields to portfolio endpoint (daily_pnl_pct, total_pnl, trading_active)
C6: Add missing /portfolio/metrics endpoint
C7: Add 'value' field to equity curve response for frontend compatibility
C8: Add 6M/ALL periods and case-insensitive period enum parsing
Also: make app creation lazy to avoid config validation at import time
2026-02-22 17:48:40 +00:00
Viktor Barzin
6fe586f722
feat: API gateway trading endpoints, controls, backtest, WebSocket 2026-02-22 15:54:20 +00:00
Viktor Barzin
e0d138c457
feat: API gateway with passkey (WebAuthn) authentication 2026-02-22 15:53:48 +00:00
Viktor Barzin
c089bcb92c
feat: learning engine — multi-armed bandit strategy weight adjustment 2026-02-22 15:43:11 +00:00
Viktor Barzin
3fef8a631c
feat: trade executor — risk management and order execution 2026-02-22 15:36:08 +00:00
Viktor Barzin
f3e5fc944d
feat: signal generator — weighted ensemble with market data 2026-02-22 15:36:04 +00:00
Viktor Barzin
e483e9987f
Merge branch 'worktree-agent-a6b241b2' 2026-02-22 15:27:54 +00:00
Viktor Barzin
6952a829ae
feat: sentiment analyzer — FinBERT + Ollama tiered analysis 2026-02-22 15:27:06 +00:00
Viktor Barzin
90b52a5144
feat: news fetcher service — RSS and Reddit sources 2026-02-22 15:25:27 +00:00