Commit Graph

345 Commits

Author SHA1 Message Date
Yijia-Xiao
241638da68 fix(dataflows): search all subreddits in one Reddit request
- anonymous RSS allows about one request per minute per IP, so fetching each
  subreddit separately hit a 429 and a 60s back-off on nearly every run
- search the subreddits as one combined feed at Reddit's full page size and
  group posts by the subreddit each entry names; each subreddit keeps its own
  limit, and a full page is not taken as evidence of absence
- drop the unused JSON search path, still blocked with a 403, and the
  per-subreddit pacing; arguments after subreddits are keyword-only
- the sentiment prompt no longer asks for vote and comment counts, which the
  RSS feed does not carry
2026-09-14 22:07:42 +00:00
Yijia-Xiao
2e38b47dca fix(dataflows): report windows a feed cannot observe as unavailable
- Yahoo news and the Reddit and StockTwits feeds serve only recent items, so a
  historical window trimmed to nothing was reported as "no news" or "no
  posts", and the sentiment analyst scored that silence as a neutral signal
- judge each empty window in one shared rule: it is a real absence only when
  the feed's coverage reaches the window's first day and the window ends by
  today; otherwise report it unavailable with where coverage starts
- coverage comes from the returned timestamps, which are newest-first on these
  feeds, plus Reddit's one-week search lookback; merged global-news searches
  prove no continuity and are bounded by the present alone
- state in the sentiment analyst that historical sentiment inputs are not
  guaranteed to be point-in-time
2026-09-14 22:07:41 +00:00
Yijia-Xiao
673abb3c68 feat(llm): add GPT-6 Astra, Gemini 3.8 Flash and the current Claude models
- OpenAI: gpt-6-astra
- Google: gemini-3.8-flash and gemini-3.5-flash-lite
- Anthropic: claude-opus-5 and claude-fable-5-1
- models taken out of the picker stay valid through LEGACY_MODELS, so configs
  that name them run without an unknown-model warning
2026-09-14 18:09:33 +00:00
Yijia-Xiao
9b4c741d33 fix(llm): forward reasoning effort to GPT-6 and gate minimal thinking
- reasoning_effort was forwarded only to IDs matching gpt-5 or the o-series, so
  GPT-6 models silently dropped the configured effort; match GPT-5 and later,
  with a version boundary so unrelated IDs do not match
- Gemini Pro, 3.8+ and the -latest aliases reject thinking_level "minimal"
  with a 400; send it only to numbered Flash models before 3.8 and map it to
  "low" elsewhere, since aliases move between generations
2026-09-14 18:09:33 +00:00
Yijia-Xiao
62d3479217 fix(agents): stop conflict alone from defaulting the verdict to Hold
- both manager prompts and both rating fields listed "materially conflicting"
  as a Hold condition, and every bull/bear and risk debate is conflicting, so
  a modest directional edge collapsed to Hold
- state one rule at all four sites: conflict alone is not a reason to Hold,
  commit to the stronger side sized by how decisively it wins, and Hold only
  when the evidence is still balanced after weighing or too thin for a call
- a modest bull edge now resolves to Overweight; a genuinely balanced debate
  still resolves to Hold #1321
2026-09-14 18:09:33 +00:00
Tauric-Research
be952b8ecc Merge pull request #1310 from TauricResearch/v0.4.2
Point-in-time fixes, honest failure reporting, and housekeeping
2026-09-07 17:30:55 -05:00
Yijia-Xiao
821848bb82 docs: tighten the comments on the point-in-time guards
- keep what the code cannot state itself: which session a closeless bar is,
  where the drop actually happens, and why the trim must stay unguarded
- drop the field-by-field enumeration, the account of what the previous
  behaviour got wrong, and the restatements of adjacent calls
2026-09-07 22:21:20 +00:00
Yijia-Xiao
d6ca23aee5 feat(llm): add the current Kimi models to the picker
- list kimi-k3 (flagship, 1M context) and kimi-k2.6 (256K, thinking modes) on
  both tiers, replacing the custom-only entry
- keep Custom model ID for models newer than the list
- omit the k2.7-code variants: coding specialists, not analysis models
2026-09-07 21:52:29 +00:00
Yijia-Xiao
ef383df8f4 fix(dataflows): don't report a symbol as unavailable over an unsettled bar
- a newest bar with no close made load_ohlcv reject the whole frame, so the
  routing layer answered with its no-data sentinel: the caller lost the entire
  price history and was told the symbol may be invalid, delisted or not
  covered, when only the latest session had not settled
- treat a closeless newest bar as an unsettled session instead. The gap fill
  already drops it, here and mid-series alike, so the frame ends at the last
  settled bar; only a range with no close anywhere is still no data
- the staleness check keeps deciding whether what remains is recent enough, so
  falling back cannot resurrect a long-dead series
- log which bars had no close and which date is being used as the latest close
2026-09-07 21:42:25 +00:00
Yijia-Xiao
d58b838081 test: keep the Ollama endpoint assertions off the terminal colour
- the console highlights numbers and URLs, so with colour enabled the rendered
  output splits asserted substrings with escape codes and two tests fail
- strip the codes before asserting so the result no longer depends on where the
  suite runs
2026-09-07 21:28:52 +00:00
Yijia-Xiao
ffd5d9a180 chore(dataflows): use the module logger and drop dead helpers
- four modules wrote to stdout with print() while ten others use a module
  logger; a warning printed into the rendered CLI output is effectively
  invisible, which is how the trim failure above went unnoticed
- convert the remaining calls to logger.warning with lazy formatting
- remove save_output, SavePathType, decorate_all_methods and get_next_weekday
  from utils, none of which had a caller, along with the pandas and typing
  imports that only they needed
2026-09-07 21:28:52 +00:00
Yijia-Xiao
16f7fd613c fix(dataflows): fail closed when the Alpha Vantage date trim fails
- get_stock requests the full daily series up to today, so trimming to the
  requested window is the only thing keeping bars after end_date out of a
  historical run
- the trim caught every exception, warned, and returned the untrimmed body, so
  a parse failure fed future prices into a backtest with no usable signal that
  it had happened
- let a parse failure propagate instead: the routing layer already logs the
  vendor failure, falls through to the next vendor, and surfaces the real error
  if none can serve
2026-09-07 21:28:52 +00:00
Yijia-Xiao
260c899c72 chore: drop the lint exclude for a directory not in the repo
- ruff's extend-exclude listed a path that is not part of the repository, so
  the entry never matched anything in CI
- keep the generated results/ exclude, which is a real runtime output directory
2026-09-07 20:54:19 +00:00
Yijia-Xiao
94113c8d11 test: stop the sentiment-analyst tests hitting the live network
- create_sentiment_analyst pre-fetches news, StockTwits and Reddit before
  prompting, and TestSentimentAnalystAgent invoked it unstubbed, so every run
  made live requests and a real 429 stalled the suite for minutes
- stub the three sources as the sibling prompt tests already do; the file drops
  from ~84s to under a second, and the suite no longer depends on Reddit or
  Yahoo being reachable
2026-09-07 20:54:19 +00:00
Yijia-Xiao
7cc478ad07 fix(dataflows): report a failed Reddit fetch as unavailable, not silence
- a failed fetch and an empty search both returned [], so a 429 rendered as
  'no posts found' and the sentiment analyst read throttling as real silence;
  when every subreddit was throttled the summary asserted it outright
- a failed fetch now returns None and renders as unavailable, and the summary
  only claims silence for subreddits actually searched
- raise the headerless-429 back-off to 60s, which is where a retry starts
  succeeding; pay it at most once per run so three throttled subreddits do not
  stall the analysis, and match the Retry-After cap to it #1295
2026-09-07 20:54:19 +00:00
Yijia-Xiao
1c44dd1ffc fix(agents): require absolute price levels from the Trader
- asking the Trader for concrete entry/stop levels invited a percentage
  (stop_loss: '15%'), which is not a price and failed the whole structured
  parse, dropping the run to a free-text retry
- state the requirement in the prompt and in both field descriptions
- a percentage now nulls that field instead of failing the proposal; it is
  never salvaged, since 15% must not become a 15 stop. Human-formatted
  prices with a currency symbol or thousands separator parse #1288
2026-09-07 20:54:19 +00:00
Yijia-Xiao
96111aa368 fix(dataflows): withhold the live profile from historical fundamentals
- both fundamentals vendors accepted curr_date and ignored it, serving a
  present-day company profile into a run dated in the past: yfinance via
  Ticker.info, Alpha Vantage via OVERVIEW
- that profile has no historical vintage, not even name/sector/industry (which
  move when a company renames or is reclassified), so a past curr_date now
  withholds it and says why; live runs are unchanged
- the rule lives once in date_window next to the existing look-ahead helpers,
  so switching data_vendors between the two cannot reintroduce the leak, and
  the guard runs before the request rather than discarding a paid-for response
- point-in-time fundamentals for a past date already come from the balance
  sheet, income statement and cash flow tools, which filter on curr_date #1300
2026-09-07 20:54:19 +00:00
Yijia Xiao
9dee508c44 Merge pull request #1285 from TauricResearch/v0.4.1
Post-v0.4.0 fixes: FRED vintage, Reddit 429, debate neutrality, feed bound
2026-09-01 00:38:45 -05:00
Yijia-Xiao
5a26ae17a1 harden(dataflows): bound the Reddit feed read before parsing
- ElementTree does not resolve external entities, so the reported XXE flag
  doesn't apply; the real residual is an unbounded read of untrusted network XML
- cap both the RSS and JSON reads at 5 MiB; overflow degrades to empty / RSS
  fallback through the existing failure paths #1206 #1276
2026-09-01 05:14:23 +00:00
Yijia-Xiao
a4acd8a174 fix(agents): stop the debate managers forcing a direction under ambiguity
- the managers reserved Hold only for "genuinely balanced" evidence and were
  told to "be decisive", pressuring a directional call on ambiguous, conflicting,
  or insufficient inputs; which side it landed on was model-prior-dependent
- allow Hold for balanced, conflicting, ambiguous, or insufficient evidence in
  both manager prompts and both structured rating fields, and weigh cases
  independent of speaking order; rating definitions and debate ordering unchanged #1196
2026-09-01 05:08:49 +00:00
Yijia-Xiao
2322dd9baa fix(dataflows): honour Reddit Retry-After: 0 and jitter 429 backoff
- a valid Retry-After: 0 means retry at once but was treated as absent
  (`or 5.0`) and waited 5s; honour it exactly now
- jitter our own headerless fallback and the inter-subreddit pacing so several
  analyses sharing an IP don't retry in lockstep and re-collide on the limit;
  keep the single-retry ceiling (more retries can't fix an exhausted IP budget) #1193
2026-09-01 05:02:36 +00:00
Yijia-Xiao
70b58c21dc fix(dataflows): clamp the FRED vintage pin to FRED's own clock
- the unconditional realtime pin 400s when curr_date is ahead of FRED's
  US-Central date (a live run's local date), which the router then degrades to
  a silent DATA_UNAVAILABLE — an Asia/Pacific run loses macro data
- clamp realtime_start/end to min(curr_date, FRED-today) via pytz Chicago;
  a past curr_date pins unchanged, so historical look-ahead safety is preserved
- name the vintage in the empty-result message: widening the window can't fix a
  series with no vintage coverage #1275
2026-09-01 04:58:53 +00:00
Yijia Xiao
2448d0a125 Merge pull request #1280 from TauricResearch/v0.4.0
Release v0.4.0
v0.4.0
2026-08-30 22:07:21 -05:00
Yijia-Xiao
c95f83dfaf chore: release v0.4.0
- look-ahead / point-in-time fixes across FRED macro, social sentiment, and the
  decision-log memory; clearer decision signals; CLI checkpoint resume; Trader
  price grounding
- GPT-5.6 / GLM-5.3 models
2026-08-31 03:02:39 +00:00
Yijia-Xiao
ecbe3e3a21 feat(llm): add the GPT-5.6 family and GLM-5.3
- GPT-5.6 (sol/terra/luna) is GA and OpenAI's recommended default; add it and
  make gpt-5.6 (deep) / gpt-5.6-luna (quick) the defaults
- add GLM-5.3 and GLM-5.3-Flash, Zhipu's current flagship line
2026-08-31 02:55:21 +00:00
Yijia-Xiao
e93c5c53c2 fix(agents): ground the Trader in the technical market report
- the Trader received only the digested investment plan, so its entry / stop /
  sizing levels were not anchored to real price structure (ATR, support and
  resistance, current price)
- inject the market report and instruct the Trader to take concrete price levels
  from it and direction/strategy from the plan; when the market analyst was not
  selected the report is empty, so the section and grounding note are omitted #1167
2026-08-31 02:35:50 +00:00
Yijia-Xiao
45c1744b86 fix(llm): apply DeepSeek capabilities to OpenRouter-namespaced models
- OpenRouter exposes DeepSeek as deepseek/<id>, which matched neither the exact
  IDs nor the patterns, so a thinking model like deepseek/deepseek-v4-flash fell
  through to _DEFAULT and had object-form tool_choice forced on it
- strip the official deepseek/ namespace before lookup so it reuses the native
  quirks; deepseek/deepseek-chat still keeps tool_choice, and third-party
  finetunes on other publishers stay on _DEFAULT #1199
2026-08-31 02:15:32 +00:00
Yijia-Xiao
63be7fe7f1 fix(dataflows): don't silently drop the latest OHLCV bar
- the latest in-range bar with a NaN close was dropped before the curr_date
  cutoff, so the previous trading day looked like the latest; dates were also
  compared without timezone normalization
- normalize bar dates and curr_date to naive midnight (per element, so 5-year
  ranges spanning DST and non-US positive-offset markets keep their local date),
  then raise NoMarketDataError on a missing latest close rather than falling back
- split the fill step (_fill_price_gaps) from date/price normalization so the
  latest bar can be inspected before incomplete rows are dropped #1201
2026-08-31 02:08:31 +00:00
Yijia-Xiao
30d42abd5d fix(memory): don't settle a decision before its holding window trades
- _fetch_returns settled on min(holding_days, available), so a rerun a day or
  two after a decision reflected on a 1-2 day partial return as if final
- require the full holding window in both the stock and benchmark series before
  resolving; otherwise leave the entry pending to retry next run
- this also makes the #1251 resolution date the full-window date, not a partial
  bar's #1169
2026-08-31 01:55:31 +00:00
Yijia-Xiao
a2f51da917 chore: remove dead code found in the v0.4.0 review
- inline _in_news_window, a trivial passthrough left from extracting
  dataflows.date_window.in_window; call in_window directly
- drop SignalProcessor's orphaned quick_thinking_llm attribute (unused since
  rating extraction became a deterministic parse)
2026-08-31 01:29:14 +00:00
Yijia-Xiao
b43bc31479 fix(cli): resume a checkpoint without duplicating messages or leaking the saver
- on resume, the CLI and propagate re-passed the initial state to a thread with
  an existing checkpoint; nodes do not re-run, but the message reducer appended
  the initial messages again, duplicating them in the resumed state
- feed None on resume (checkpoint_input) so LangGraph continues the interrupted
  run, and wrap the CLI stream in try/finally so the checkpointer tears down even
  if the stream raises
- correct the _fetch_returns docstring to the 4-tuple return #1249
2026-08-31 01:29:14 +00:00
Yijia-Xiao
8db41f6bca fix(memory): gate past-context lessons to point-in-time in backtests
- get_past_context returned every resolved lesson regardless of the run date, so
  a historical run could learn from an outcome that had not happened yet
- record each resolved entry's resolution date (the last price bar used) and
  filter get_past_context(as_of=trade_date) on it for a historical run; a
  current-date run passes None so live behavior and pre-migration entries (no
  stored resolution date, conservatively excluded from backtests) are unaffected #1251
2026-08-30 07:03:06 +00:00
Yijia-Xiao
51a245dbe1 fix(cli): make --checkpoint actually resume on the CLI path
- checkpoint setup lived only inside propagate(); the CLI streamed the
  checkpointer-less graph with no thread_id, so --checkpoint neither saved nor
  resumed a run
- extract the lifecycle into reusable begin_checkpoint / end_checkpoint /
  clear_checkpoint_on_success (checkpoint_scope wraps them for propagate) and use
  them around the CLI stream #1249
2026-08-30 06:47:00 +00:00
Yijia-Xiao
43fc275b36 fix(rating): surface an unparseable rating as REVIEW, not a silent Hold
- an unrecognizable Portfolio Manager decision was coerced to Hold, emitting a
  tradeable neutral signal that masked a parsing failure; a fullwidth colon
  (Rating:X) defeated the label regex and hit the same path
- add extract_rating() -> str | None with NFKC normalization and whole-word
  matching; the graph signal now yields a REVIEW sentinel (with an is_review
  guard) when no rating is found
- parse_rating keeps its silent default for compat callers (e.g. the memory log) #1170
2026-08-30 06:38:15 +00:00
Yijia-Xiao
0ef56e6a33 feat(llm): add a configurable output-token cap
- some model/gateway combinations emit unbounded reasoning/output and hang or
  trip an idle timeout (e.g. some deepseek-v4-flash deployments)
- add an opt-in max_tokens config knob + TRADINGAGENTS_MAX_TOKENS, forwarded to
  every provider when set (Gemini takes it as max_output_tokens); int-coerced,
  rejects non-positive/boolean values #1204
2026-08-30 06:26:57 +00:00
Yijia-Xiao
539eae8fd6 fix(agents): stop debate openers from rebutting a nonexistent argument
- the first speaker in each debate round received an empty opponent response,
  yet the prompt demanded a rebuttal, so models fabricated the other side
- substitute an explicit opening marker when an opponent has not spoken, across
  all five debators (bull, bear, and the three risk analysts) #1176
2026-08-30 06:18:59 +00:00
Yijia-Xiao
9b98f09613 fix(dataflows): trim social sentiment sources to the analysis window
- StockTwits and Reddit were fetched with no date, so a historical run showed
  today's chatter as if it were from the as-of date
- pass the analysis window to both fetchers, filter to it, and emit a clear
  placeholder when nothing qualifies
- centralize the UTC half-open window rule in dataflows/date_window so news,
  StockTwits, and Reddit share one look-ahead-safe filter #1220
2026-08-30 06:18:59 +00:00
Yijia-Xiao
8b7ece8a3e fix(dataflows): pin the FRED data vintage to the as-of date
- FRED defaults both realtime bounds to today, so historical macro requests
  served the latest revision and leaked future information into backtests
- set realtime_start=realtime_end=curr_date on both the metadata and
  observations requests #1275
2026-08-30 06:18:59 +00:00
Yijia-Xiao
a33fd4c0f1 docs: streamline README header 2026-07-18 15:55:04 +00:00
Yijia-Xiao
7bbe33ab1d docs: add trending badge 2026-07-18 15:23:59 +00:00
Yijia-Xiao
030b434585 fix(agents): stop priming tool calls in schema-only structured agents
- with_structured_output binds a single tool (the schema), so a primed model emitted
  an unknown web_search call and the attempt was discarded for a free-text retry,
  costing an extra round trip and the typed output
- drop the tool-range wording from the no-tool sentiment analyst and state the
  constraint once via a shared NO_EXTERNAL_TOOLS #1130
2026-07-18 06:28:38 +00:00
Yijia-Xiao
3f6c082695 fix(cli): report an unusable terminal instead of a prompt_toolkit traceback
- Windows terminals without a console buffer raised NoConsoleScreenBufferError
  before the first prompt, surfacing a raw traceback with no guidance
- gate the Windows-only import on sys.platform so a broken prompt_toolkit still
  surfaces there, and the handler stays inert on other platforms #1138
2026-07-18 06:28:38 +00:00
Yijia-Xiao
d78c698d0e fix(dataflows): refresh the same-day OHLCV cache
- the per-day cache was reused unconditionally, so a run started before the day's
  bar was final served that snapshot to every later run, feeding a stale close
  into technical analysis
- a present row is not sufficient either, since Yahoo publishes a partial intraday
  candle; a TTL now governs every current-day cache while historical caches stay
  immutable #1150
2026-07-18 06:28:38 +00:00
Yijia-Xiao
40774ca042 fix(dataflows): make the Yahoo news window UTC and end-exclusive
- the upper bound was inclusive, so an article stamped exactly midnight after
  end_date leaked into a historical run
- flat epoch timestamps were parsed in host-local time and offset-aware stamps had
  tzinfo stripped without converting, making filtering machine-dependent
- normalize every operand to UTC and use a half-open [start, end + 1 day) #1126
2026-07-18 06:28:38 +00:00
Yijia-Xiao
01477f9afb chore: release v0.3.1
- correctness/stability patch: look-ahead filter, router crash-safety, checkpoint
  identity, crypto sentiment sources, configurable retries, Bedrock API-key auth
- adds Claude Sonnet 5 / Fable 5 support
v0.3.1
2026-07-05 14:29:07 +00:00
Yijia-Xiao
0f70af2f31 feat(llm): add Claude Sonnet 5 and Fable 5 to the catalog
- refresh the Anthropic lineup to the current GA set (Fable 5, Opus 4.8,
  Sonnet 5, Opus 4.7, Haiku 4.5)
- extend the effort gate to single-number Claude 5 IDs (claude-sonnet-5,
  claude-fable-5) so their effort setting is honored
2026-07-05 14:29:07 +00:00
Yijia-Xiao
43bd32befa feat(llm): support Bedrock API-key auth via AWS_BEARER_TOKEN_BEDROCK
- pass the token to ChatBedrockConverse as api_key so langchain-aws prefers bearer
  auth and an ambient AWS_PROFILE can't override it; no AWS access keys required #1103
2026-07-05 14:29:07 +00:00
Yijia-Xiao
a102afa090 fix(dataflows): map crypto to StockTwits/Reddit sentiment symbols
- crypto reached StockTwits as Yahoo's BTC-USD (404) instead of BTC.X, and Reddit
  searched the dashed pair that barely matches; both now resolve the base via a
  shared crypto_base() helper, restoring crypto sentiment
- also fixes a StockTwits resilience test class that pytest never collected #1113
2026-07-05 14:29:07 +00:00
Yijia-Xiao
daf1da9c35 fix(graph): key checkpoints on graph shape and expose the LLM retry budget
- checkpoint resume keyed only by ticker+date silently continued the old graph
  under a different analyst selection / depth / asset mode; fold a run signature
  into the thread id #1089
- add llm_max_retries + TRADINGAGENTS_LLM_MAX_RETRIES, forwarded to every provider
  when set (int-coerced, rejects negatives/booleans), so a 429 burst can't abort
  a run #1091
2026-07-05 14:29:07 +00:00
Yijia-Xiao
b47a828a4f fix(graph): give the shared debate/risk routers a complete path_map
- should_continue_debate (2 edges) and should_continue_risk_analysis (3 edges)
  each returned more targets than any one edge mapped; a fall-through under
  prompt/i18n/refactor drift crashed LangGraph mid-run
- share a complete DEBATE_PATH_MAP / RISK_ANALYSIS_PATH_MAP across every edge #1088
2026-07-05 14:29:07 +00:00