Commit Graph
1119 Commits
Author SHA1 Message Date
Haozhe Wu 96e43b6e1d Merge pull request #858 from HKUDS/codex/fix-847-hash-lock
fix(deps): repair cold hash-locked installs
2026-07-26 13:23:01 +08:00
Haozhe Wu 0a690913c2 Merge pull request #852 from HKUDS/dependabot/npm_and_yarn/frontend/npm-minor-patch-3c68efc824
build(deps): bump the npm-minor-patch group in /frontend with 5 updates
2026-07-26 13:13:31 +08:00
Haozhe Wu 10d1b69aaf Merge pull request #851 from HKUDS/dependabot/github_actions/actions/setup-python-7.0.0
build(deps): bump actions/setup-python from 6.3.0 to 7.0.0
2026-07-26 13:13:08 +08:00
Haozhe Wu 453951ee1a Merge pull request #850 from HKUDS/dependabot/github_actions/actions-minor-patch-7a5a078ad4
build(deps): bump actions/checkout from 7.0.0 to 7.0.1 in the actions-minor-patch group
2026-07-26 13:12:37 +08:00
Haozhe Wu 2c1ccd7678 fix(alpha): disclose benchmark universe degradation 2026-07-26 13:03:57 +08:00
santhreal 5ed1eb5472 fix(journal): treat BTCUSDT-style symbols as crypto markets
Concatenated pairs like BTCUSDT are alphabetic, so isalpha() labeled them
as US equities. Recognize USDT/USDC/BUSD suffixes before that branch.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:55:00 -07:00
Haozhe Wu 8aa7a13bfe fix(deps): repair cold hash-locked installs 2026-07-26 12:53:22 +08:00
santhreal 0a59f57f9e fix(journal): strip currency symbols before float coerce
Broker CSV cells like $1,234.56 or ¥1000 failed float() after only commas
were stripped, so price/fee silently became 0.0. Strip common currency
tokens and unicode minus too.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:52:41 -07:00
santhreal 8a4f6260bb fix(tools): decode UTF-16 BOM text before latin-1 fallback
Notepad/Excel Unicode text exports start with a UTF-16 BOM; latin-1 never
raises so those bytes were accepted as mojibake. Detect BOM and decode as
utf-16 first.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:50:16 -07:00
santhreal 34a9fd4302 fix(metrics): annualize lowercase 1h/1d and yahoo like loaders
After loaders started accepting 1h/4h/1d, calc_bars_per_year still keyed
only 1H/1D, so hourly runs were annualised as daily (Sharpe/vol wrong).
Normalize interval case and alias yahoo→yfinance / binance→ccxt.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:48:25 -07:00
santhreal fe04869194 fix(skills): keep CJK characters in skill directory slugs
Non-ASCII skill names such as 动量策略 were scrubbed to "--", so distinct
Chinese names collided into one directory and overwrote each other.
Allow the same non-Latin ranges as persistent memory, and hash when the
slug would otherwise be only hyphens.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:46:55 -07:00
santhreal b13243afd6 fix(journal): accept UTF-16 BOM CSV exports in load_dataframe
Excel "CSV UTF-16" / Unicode CSV writes a BOM that utf-8/gbk cannot
decode, so analyze_trade_journal rejected the file. Try utf-16 in the
encoding fallback before raising.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:46:53 -07:00
dependabot[bot] d8accd822c build(deps): bump the npm-minor-patch group in /frontend with 5 updates
Bumps the npm-minor-patch group in /frontend with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.25.0` | `1.26.0` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.2.7` | `19.2.8` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.2.7` | `19.2.8` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.10` | `17.0.11` |
| [postcss](https://github.com/postcss/postcss) | `8.5.20` | `8.5.23` |


Updates `lucide-react` from 1.25.0 to 1.26.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.26.0/packages/lucide-react)

Updates `react` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react)

Updates `react-dom` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom)

Updates `react-i18next` from 17.0.10 to 17.0.11
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.10...v17.0.11)

Updates `postcss` from 8.5.20 to 8.5.23
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.20...8.5.23)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor-patch
- dependency-name: react
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-minor-patch
- dependency-name: react-dom
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.0.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-minor-patch
- dependency-name: postcss
  dependency-version: 8.5.23
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:13:25 +00:00
dependabot[bot] ed61a2aaeb build(deps): bump actions/setup-python from 6.3.0 to 7.0.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.3.0 to 7.0.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/ece7cb06caefa5fff74198d8649806c4678c61a1...5fda3b95a4ea91299a34e894583c3862153e4b97)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:12:37 +00:00
dependabot[bot] 422d2f918c build(deps): bump actions/checkout in the actions-minor-patch group
Bumps the actions-minor-patch group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:12:34 +00:00
Haozhe Wu 93d666c5e6 docs(readme): add 2026-07-25 news across all 5 READMEs, keep 3 visible entries 2026-07-25 23:01:23 +08:00
Gordon Lee 84eff84a6a fix(backtest): consume historical USD-M funding + round settlement jitter (#819)
Two fixes that make historical funding actually flow into perp backtests:

1. Loader: Binance funding settlement timestamps carry millisecond
   jitter (e.g. 2026-05-05T08:00:00.011Z). The raw timestamps never
   intersect bar timestamps, so the missing-settlement guard raises
   'funding settlement data is missing' for most real fetches. Round
   settlement timestamps to the second before aligning.

2. Engine: the loader writes a historical funding_rate column into the
   frame, but calc_crypto_funding_fee still charges the fixed config
   rate (default 0.0001) — the fetched data is never consumed. Prefer
   the bar's historical rate when present and finite; fall back to the
   fixed rate otherwise (spot-proxy and daily-fallback paths keep
   their existing behaviour).

Verified against live Binance USD-M data (BTC/ETH -USDT-PERP, 4H,
Jan-Jul 2026): fixed-rate short returned +44.5%, historical-funding
short +39.1% — the ~5pp delta matches 2026's predominantly negative
funding regime where shorts pay.

Tests: jitter alignment test in test_ccxt_perpetual_loader.py; three
override/fallback tests in test_crypto_engine.py.

AI-assisted-by: Claude (Anthropic)

Signed-off-by: Gordon Lee <xnegra80@gmail.com>
2026-07-25 22:54:00 +08:00
Amir Fathi 283752d908 fix(cli): forward universe meta into alpha bench JSON/HTML output (#841)
bench_runner.run_bench forwards the sp500 loader's survivorship_bias flag
as result["meta"] (bench_runner.py L319-347), and
alpha_routes._result_for_wire already keeps that key for the SSE/frontend
path (alpha_routes.py L777). cmd_alpha_bench built its own JSON envelope
and HTML report context from hand-enumerated dict literals that never
included "meta", so the CLI and the HTML report silently dropped the
disclosure while the web UI kept it.

Forward result.get("meta") into both dict literals when present, mirroring
how the wire path already treats it: an opaque passthrough, not a new
rendered field. Verified with a fresh regression test
(agent/tests/test_alpha_bench_meta_survivorship.py) that fails on main and
passes on this branch, plus a third case asserting the key stays absent
when the loader supplies no meta.

Fixes #797

Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
2026-07-25 22:53:57 +08:00
ShaunMandShaunM b2bac34888 fix(mcp): handle dataclass tool results in _make_jsonable (#849)
_make_jsonable only converted Pydantic BaseModel instances (via
model_dump), list, and dict. fastmcp's client auto-types
CallToolResult.data from a tool's output schema via
json_schema_to_type, which produces a plain stdlib dataclass (not a
BaseModel) whenever the schema doesn't set additionalProperties: true
-- the common case for a typical Pydantic-model tool return type. Such
an instance fell through to the final `return value` unconverted, so
json.dumps's `default` callback received the same unconvertible object
back and raised ValueError: Circular reference detected (its cycle
detector can't distinguish "default() gave up" from an actual cycle).

Adds a dataclasses.is_dataclass branch that recurses per-field (not a
raw asdict(), which would leave nested datetime/dataclass values
unconverted), plus a datetime/date branch, since a date-time schema
field validates to a real datetime object and would hit the same
failure one level down.

Reproduced against the real fastmcp dependency using an MCP tool's
output schema shaped like this (plain object properties, no
additionalProperties, nested datetime field): old _make_jsonable raises
the reported Circular reference detected error; the patched version
serializes correctly, verified both from direct construction and via
pydantic.TypeAdapter validation (the path fastmcp's client actually
uses).

Signed-off-by: ShaunM <echoandelementwebsites@gmail.com>
Co-authored-by: ShaunM <echoandelementwebsites@gmail.com>
2026-07-25 22:53:54 +08:00
Hongi Nagaputra c5540a92e3 feat(backtest): define perpetual margin state contracts (#798)
Pure, immutable state and risk contracts for historical USD-M perpetual
backtests: MaintenanceBracket/MaintenanceSchedule, PositionState,
AccountState, ExecutionFrame, MarketRiskFrame. No engine wiring yet — that's
a later slice.

Reapplied against the current data contract rather than cherry-picked from
the old codex/perp-engine-fidelity branch, which predates #757 and still
carries the pre-#470 loader shape. Two real changes from that branch's
version:

- MaintenanceBracket gains bracket_tier (ordering) and optional
  notional_coefficient, matching the loader's validated artifact tier
  fields exactly (backtest.loaders.ccxt_loader._validate_bracket_artifact).
- MaintenanceSchedule drops its own independent SHA-256 hash computation
  in favor of a single caller-supplied version string — the loader's
  maintenance_bracket_version content hash. Content integrity is already
  checked once, at the artifact-validation boundary; this class only
  re-checks structural invariants (tier and notional-cap ordering) as
  defense in depth, not a second, incompatible hash scheme.
  MaintenanceSchedule.from_loader_columns(symbol, maintenance_brackets,
  maintenance_bracket_version) builds a schedule straight from the
  loader's DataFrame columns.

MarketRiskFrame.schedule is Optional: a -PERP fetch without a supplied
bracket artifact still produces a usable execution/mark/funding frame.

Part of #462's PR 2 (margin-risk model), sliced small per maintainer
guidance. Isolated/cross liquidation logic and engine integration are
separate follow-up slices.

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>
2026-07-25 22:31:37 +08:00
Santh 3f7e9a1c2a fix(tools): keep empty cells when parsing report_audit tables (#807)
Dropping blank cells shifted later values onto earlier column headers.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:31:32 +08:00
卫斯李 6da76b7e01 fix(cli): show account label in broker_sdk balances view (#843)
broker_sdk connectors (Longbridge, etc.) return a balances list but no
accounts key, causing the CLI to print "Accounts: (none)" before the
balances table. Fall back to result.profile_id — which _with_profile()
always injects — so the label is informative.

Closes #846

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>
2026-07-25 22:31:28 +08:00
Santh e109ae69c8 fix(channels): keep empty edge columns in Slack md tables (#801)
str.strip('|') dropped leading/trailing empty cells, so Slack table
conversion mislabeled row-label columns and dropped trailing cell values.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:31:25 +08:00
Santh 8374fc4cf1 fix(channels): keep empty edge columns in Signal md tables (#800)
str.strip('|') dropped leading/trailing empty cells in pipe tables, so
row-label columns and trailing blanks collapsed when rendering for Signal.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:31:21 +08:00
Santh 1b6420d804 fix(channels): keep empty edge columns in Telegram md tables (#799)
str.strip('|') dropped leading/trailing empty cells in pipe tables, so
row-label columns and trailing blanks collapsed when rendering for Telegram.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:31:17 +08:00
Santh e04c08bf79 fix(connectors): map MT5 1H/4H/1D periods to hour/day bars (#806)
Project-style period tokens were falling through to daily TIMEFRAME_D1.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:29:40 +08:00
Santh 96f7bc58b4 fix(connectors): map Binance 1H/4H periods to ccxt timeframes (#805)
Project-style hour tokens were passed raw to ccxt, which expects lowercase unified timeframes.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:29:37 +08:00
Santh 7b6d219a53 fix(loaders): keep lowercase 1h/4h/1w as ccxt hour/week bars (#804)
* fix(loaders): keep lowercase 1h/4h/1w as ccxt hour/week bars

Lowercase project tokens previously missed _INTERVAL_MAP and fell through to silent daily bars.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* style(test): drop narrating comment on ccxt interval aliases

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

---------

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:29:33 +08:00
Santh 457ebebdaa fix(connectors): reject unsupported Dhan history periods (#803)
Unknown periods such as 1H were silently served as daily candles. Fail
closed with an explicit unsupported-period error instead.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:29:29 +08:00
Santh 4e8271a0b9 fix(connectors): map Futu 1H/4H periods to hour bars (#802)
Project-style 1H fell through to daily K lines, and 4h incorrectly mapped
to K_60M instead of K_240M.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:29:26 +08:00
Santh dfdbefd0ea fix(journal): normalize Excel serials in generic datetime columns (#810)
Generic CSV/XLSX loads stringify serial day numbers, which then failed
to parse and became NaT in the standardized journal frame.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:28:54 +08:00
Santh b71427a829 fix(journal): normalize stringified Excel serials in Futu dates (#809)
load_dataframe reads CSV/XLSX as strings, so Date serials never hit the
numeric Excel path and stayed as raw "45321.0".

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:27:57 +08:00
Santh ebc1ff8d85 fix(journal): normalize stringified Excel serials in Tonghuashun dates (#808)
load_dataframe reads CSV/XLSX as strings, so serial day numbers never
hit the numeric Excel path and stayed as raw "45321.375".

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 22:27:08 +08:00
Haozhe Wu 65bab10f32 docs(readme): add 2026-07-24 news across all 5 READMEs 2026-07-24 22:46:19 +08:00
shadowinlifeandQoder b9507ee12b feat(memory): implement Tier 2 structural organization (#815)
* feat(memory): implement Tier 2 structural organization

Add four independent modules for memory structural organization:
- H-MEM hierarchical directory routing (hierarchy.py)
- A-MEM semantic linking via BM25 (semantic_links.py)
- Auto-compression pipeline via TF-IDF (compression.py)
- FTS5 full-text search index (search_index.py)

Integration:
- 4 feature flags in MemoryConfig (default: disabled)
- MemoryEntry extended with category + compression_level fields
- persistent.py wired with hierarchy routing, FTS5 search, link expansion
- lifecycle.py triggers compression in GC cycle
- remember_tool.py attaches related links in recall results
- FTS5 CJK bigram+unigram indexing for better Chinese recall
- Lazy auto-rebuild on first FTS5 search

Testing:
- 163 unit tests + 9 integration tests + 23 benchmarks (all passing)
- Benchmark evaluated on 200 real production memories + 50 labeled queries
- Compression retention: daily 91.4%, digest 97.1%
- Hierarchy routing: 93.3% P@5 parity with full scan

Closes #732 (Tier 2 scope)

Signed-off-by: shadowinlife <shadowinlife@gmail.com>

Co-Authored-By: Qoder <noreply@qoder.com>
AI-Contributed/Feature: 1582/1871
AI-Contributed/UT: 2123/2159

* feat(memory): add VT_MEMORY=off|on|full business-friendly preset

Simplify memory configuration from 7 individual boolean flags to a
single business-friendly environment variable:
  - off:  all features disabled (default, backward compatible)
  - on:   Tier 1 quality + decay + garbage collection
  - full: Tier 1 + Tier 2 hierarchy + links + compression + FTS

Individual VT_MEMORY_* flags still work as explicit overrides with
higher priority than the preset baseline.

Also adds a dependency-conflict warning in lifecycle.py when
compression is enabled without GC.

Signed-off-by: shadowinlife <shadowinlife@gmail.com>

AI-Contributed/Feature: 0/138
AI-Contributed/UT: 0/0

* docs: add Memory Tier 2 and VT_MEMORY preset to CHANGELOG

Document the new structural organization features (hierarchy, semantic
links, compression, FTS5) and the business-friendly VT_MEMORY=off|on|full
configuration preset.

Signed-off-by: shadowinlife <shadowinlife@gmail.com>

AI-Contributed/Feature: 0/15
AI-Contributed/UT: 0/0

---------

Co-authored-by: Qoder <noreply@qoder.com>
2026-07-24 22:13:16 +08:00
Yufeng He 97083c618b feat(backtest): composable weight constraints for any optimizer (#818)
Portfolio Studio step 2 (#456): per-name cap, per-name floor, and per-group exposure caps as a shared layer on top of every optimizer, not just turnover_aware's built-in bounds. Configured via constraints in config.json, off by default.

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-07-24 22:13:10 +08:00
dffa8fe03f Add allow_nonpositive_prices: open on negative-price bars, still reject zero (#816)
Markets like European day-ahead power clear negative routinely, but the
loader's validate_ohlc drops any bar with a non-positive OHLC value and the
engine rejects any open at price <= 0. On real EU power data this silently
deletes ~27% of DE-LU days (every bar with a sub-zero hourly-derived low),
punching holes in rolling statistics (e.g. a z-score entry signal) with no
warning.

Add an opt-in `allow_nonpositive_prices` flag (default False — existing
behavior byte-identical for all positive-price markets):

- loaders/base.py: validate_ohlc gains the flag. Structural invariants
  (high<low, high/low bracketing open/close) always enforced; when the flag
  is set, negative prices pass through and only an exactly-zero price is
  rejected. Zero is genuinely undefined for `size = notional / price` and
  margin; a negative price is well-defined via abs().
- engines/base.py: BaseEngine reads the flag from config. _plan_open_order
  rejects an exactly-zero open always, negatives only when the flag is off.
  _calc_raw_size / _calc_margin divide by abs(price) so a negative entry
  price yields a positive size magnitude (direction carries the sign) and
  positive collateral — unchanged for positive prices. _calc_pnl already
  uses a price difference, well-defined through zero.

Tests open a position on a negative-price bar and assert size/margin/PnL are
well-defined through zero, that an exactly-zero price is still rejected with
the flag on, and that the default still rejects negatives. A regression test
pins *why* zero stays dropped rather than kept: a surviving 0.00 close yields
inf at the `close.pct_change().fillna(0.0)` sites in benchmark.py and
engines/base.py (fillna fills NaN, not inf), so keeping it would corrupt the
return series. Fixture carries the 5 real non-positive-close bars from a 2025
NO2/DE-LU window (ENTSO-E via Energy-Charts / Bundesnetzagentur | SMARD,
CC BY 4.0). Existing engine and OHLC-validation suites pass unchanged
(140 tests total).

Co-authored-by: Ali Emadi <ali@gatekeeperai.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 22:13:05 +08:00
Santh 830122cffa fix(journal): normalize Excel day-count serials in Eastmoney dates (#811)
load_dataframe reads cells as strings, so day-count serials like
"44941.0" skipped the YYYYMMDD float path and stayed as raw date text.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:59 +08:00
Santh e5a99c778e fix(loaders): map Yahoo 4H to 1h like yfinance (#812)
Yahoo chart has no 4h interval; project 4H was lowercased to 4h and
sent unsupported to the API. Match yfinance's 4H → 1h approximation.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:55 +08:00
Santh 6d9079c162 fix(loaders): reject unsupported BaoStock history intervals (#813)
Docs say daily-only, but 1H/4H still logged in and returned frequency=d
bars. Reject non-daily intervals before login (tencent/fmp parity).

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:50 +08:00
Santh 9fdb316f3a fix(loaders): reject unsupported Alpha Vantage history intervals (#814)
TIME_SERIES_DAILY is daily-only, but 1H/4H still hit the API and
returned day bars. Reject non-daily intervals before the request.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:43 +08:00
Santh 960f595f31 fix(loaders): reject unsupported Finnhub history intervals (#823)
Finnhub always called resolution=D even for 1H/4H, so intraday runs
silently got day bars and stopped the fallback chain.

Reject unsupported intervals like the other daily-only loaders.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:38 +08:00
Santh bcdaaf5e8f fix(loaders): reject unsupported Tiingo history intervals (#824)
Tiingo always hit the daily EOD endpoint even for 1H/4H, so intraday
runs silently got day bars and stopped the fallback chain.

Reject unsupported intervals like the other daily-only loaders.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:33 +08:00
Santh eac1e92755 fix(loaders): reject unsupported Stooq history intervals (#825)
Stooq always fetched the daily CSV even for 1H/4H, so intraday runs
silently got day bars and stopped the fallback chain.

Reject unsupported intervals like tencent/fmp/india-broker.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:28 +08:00
Santh 4ab478cb56 fix(loaders): map OKX lowercase 1h/4h instead of silent daily (#826)
Connector-style 1h/4h fell through the uppercase-only allowlist and were
substituted with 1D. Map the aliases like the OKX connector bar map, and
reject unknown intervals instead of silently fetching daily bars.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:24 +08:00
Santh e14e627d9b fix(loaders): treat QVeris 1m/5m/15m/30m as intraday granularity (#827)
Lowercasing first left 1m/5m/15m/30m with empty wanted tokens, so daily
OHLCV capabilities outranked minute ones. Match minute tokens
case-sensitively and keep 1M as monthly.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:17 +08:00
Santh a4e9222235 fix(loaders): reject non-daily intervals for AKShare US/HK/ETF/forex (#828)
* fix(loaders): reject non-daily intervals for AKShare US/HK/ETF/forex

A-share already raised on unsupported intervals, but US/HK/ETF/forex
always called the daily endpoints, so interval=1H returned day bars
under a 1H cache key and stopped the fallback chain.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* fix(loaders): tighten AKShare daily-only interval gate comment

---------

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:12 +08:00
Santh c3b284055f fix(loaders): accept lowercase 1h/1d in India broker interval map (#829)
Connector-style 1h/1d were rejected while project 1H/1D mapped to the
same broker tokens, so market_data and mixed-vocabulary callers got
empty frames for valid hour/day bars.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:07 +08:00
Santh bca8ecf91b fix(loaders): accept lowercase 1h/4h/1d in Futu interval map (#830)
Connector-style hour/day tokens raised unsupported while 1H/4H/1D
already mapped to K_60M/K_240M/K_DAY, so mixed-vocabulary callers lost
intraday Futu history.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:12:02 +08:00
Santh be32143bc4 fix(loaders): accept daily aliases in FMP interval gate (#831)
* fix(loaders): accept daily aliases in FMP interval gate

The gate compared interval != \"1D\" exactly, so connector-style 1d/day
returned empty while sina/tencent treat those as daily.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* fix(loaders): drop narrating FMP daily-alias gate comment

---------

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-24 22:11:57 +08:00