Repository navigation
feat: ground trader in market data and harden unattended runs - #12
Merged
Merged
Conversation
- daily-pipeline: fetch check_stock quote/history before each trader run and pass a condensed context file to the panel, so verdicts are based on real prices instead of training data - daily-pipeline: render the crypto portfolio in the report, send a best-effort failure alert email on stage errors, and make the run lock atomic - trader: enforce the judge's verdict JSON with structured outputs - financial-news: dedup syndicated articles by URL/title; keyword score is now a capped match count instead of a fraction of all configured keywords - common: retries with backoff and a User-Agent on the shared HTTP client - mcp: per-script timeout and shared logger in the MCP server - ci: GitHub Actions workflows for tests/lint and GHCR image publishing - docs: README sections for trader and daily-pipeline; deployment guide updated for alerting and CI Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #11 (merged). A full review of the repo surfaced one correctness gap and a set of robustness holes in the unattended path; this lands all of them, plus the three follow-ups #11 explicitly deferred.
Trader verdicts are now grounded in real market data
The headline fix.
run_panel.pyhas always accepted--context-file, but the daily pipeline never passed one — so the analyst panel worked entirely from training data. The technical analyst was emitting concrete ENTRY/STOP/TARGET price levels and the fundamental analyst was quoting P/E ratios for prices it had never seen.The pipeline now fetches each symbol's quote and history via
check_stock(free Yahoo data, zero marginal cost) before the trader runs, and passes a condensed context file to the panel. Newdaily_pipeline/context.pyrenders quote, period range, SMA20/50/200 and the last 10 bars — deliberately kept under ~2.5KB, since the context goes to all five panel roles and the raw history JSON is tens of KB. A failed fetch logs and falls back to an ungrounded run rather than failing the day. Lookback istrader.history_period(default6mo).Judge output is schema-enforced
run_judgenow passes a JSON schema via structured outputs (output_config.format), so a malformed scorecard is no longer possible.call_rolegrew an optionaloutput_schemaparameter to support it. The fence-stripping parser and the report's "malformed output" branch stay as a safety net.Unattended-run robustness
StageErrornow sends a best-effort "pipeline FAILED" email through the existing SMTP config before exiting non-zero. Previously a failed stage exited quietly into a cron log that's indistinguishable from a slow news day. Alert delivery failure is logged and swallowed so it can never mask the original error.common.http_clientmounts urllib3 retries (3 attempts, backoff, honoursRetry-Afteron 429/5xx) and sets aUser-Agent. The 07:30 run hits CoinGecko (aggressive 429s on the free tier), Trading212 and Crypto.com; one transient failure used to mark a stagefailedfor the day. One change incommonhardens every skill.acquire_lockused exists-then-write, so two simultaneous cron fires could both pass. Nowopen("x")._runhad no subprocess timeout, so a hung yfinance call would wedge the tool and its SSE connection indefinitely; now capped at 900s to match the pipeline. Also wired intocommon.logger, which it was bypassing.Analysis quality
--min-keyword 0.5would have required 6 of 12 matches. Now a capped match count (1 = 0.33, 2 = 0.67, 3+ = 1.0), independent of list size. Worth landing before more scoring data is gathered.Deferred items from #11, now done
build_report.pygained--crypto.ci.ymlruns pytest +ruff check+ruff format --checkon every PR.docker.ymlbuilds and pushes to GHCR on merge to main, so the CasaOS host candocker compose pullinstead of building ~1GB of dependencies locally. Uses Buildx with GHA cache; the Dockerfile's legacy-builder compatibility is unaffected since that constraint only applies to the CasaOS host.Docs
README gained
/traderand/daily-pipelinesections (both were missing entirely) and lost a duplicated financial-news scoring-filter block; the verify snippet now imports every workspace package.docs/deployment.mdswapped its "Not yet done" section for the shipped alerting and CI behaviour. SKILL.md versions bumped per repo convention (financial-news0.2.0→0.2.1,daily-pipeline0.1.2→0.1.3), and daily-pipeline's "Known limitations" now reflects that only crypto trader-gating remains.Test plan
uv run pytest— 439 passed, 97.32% coverage (was 399 / 97.24%; threshold 85%)uv run ruff check .— cleanuv run ruff format --check .— 81 files formattedtest_context.py(context builder, SMA edges, compactness assertion), context-file plumbing and ungrounded-fallback intest_run_daily.py, failure-alert paths incl. alert-failure-doesn't-mask-exit-code, lock race, crypto section formatting, dedup cases, keyword-score independence from list size, judge schema enforcement, HTTP retry adapter configpipeline.yamlagainst current Anthropic rates while reviewing the cost table —claude-sonnet-4-6$3/$15 andclaude-opus-4-8/claude-opus-5$5/$25 per MTok are all correct and current; no change neededci.ymlruns here for the first time — the workflows have never executed, since they only exist on this branch)run_<date>/context_<SYMBOL>.mdis written and the crypto section renders in the emailed reportdocker.ymlpublishes to GHCR on merge; then optionally repoint compose atghcr.io/agb1986/finance-agent:latestNotes
Based on
24cac86; merge-base with main is clean, so this is exactly the 27-file diff with no rebase needed. The work was originally committed tofeature/daily-pipelineafter #11 had already merged, leaving it stranded on a branch with no open PR — this branch carries the identical commit onto a PR that actually targets main. No changes to #11's merged content.Not included
select_candidates(stock positions only)docs/deployment.md🤖 Generated with Claude Code