Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ FRED_API_KEY=
# 给调度器一份「每天去给哪些指数拍成分快照」的点名册:逗号分隔指数代码,留空=禁用调度
# (后台循环不起,constituent_snapshot 表保持空,panel_score 传 index_code 一律走 non-PIT 降级)。
#
# 为什么要它:akshare 只回**当前**成分、免费历史拿不到 → 唯一 PIT 路径是从启用日起每日把
# 为什么要它:免费源只回**当前**成分、历史成分拿不到 → 唯一 PIT 路径是从启用日起每日把
# 当前成分落库、向前累积。**覆盖从配置那天起向前增长,不回填历史,越早配可用于无偏回测的历史越长。**
#
# 目前 connector 走 akshare 中证接口,只支持 **A股指数代码**(美股/港股成分快照需另接数据源,未做):
# 目前 connector 对三大核心指数优先走 Baostock,其余 A股指数回退 AkShare 中证接口;
# 美股/港股成分快照需另接数据源,未做:
# 000300 沪深300 / 000905 中证500 / 000016 上证50 / 000852 中证1000 / 399006 创业板指
# 不预设市场:按你实际要回测的指数填,别贪多(akshare 是爬虫接口,抓越多越易被封)。
# 不预设市场:按你实际要回测的指数填,别贪多(公开接口抓越多越容易限流)。
# 手动 POST /constituents/snapshot 不受本项影响(仍可随时按需落一份)。
CONSTITUENT_SNAPSHOT_INDICES=
# 调度检查间隔(小时,默认 12)。幂等:每轮只补「今天还没快照」的指数,<24h 不会重复打源站;
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ Inalpha splits *scheduling* from *compute*. The agent runtime fans out the grid
A deep dive doesn't hand you one "correct answer." Beyond the usual technical, fundamental, and sentiment analysts, you can convene a panel of master personas — Buffett (value / moats), Lynch (GARP growth), Wood (disruptive innovation), Burry (contrarian / bubbles), Druckenmiller (macro trends), Marks (cycles / risk): each argues in their own style, naturally forming opposing views that feed a synthesized judgment.

- **Opt-in, cost-controlled.** A plain deep dive costs the same as before; you only pay for the masters you actually convene.
- **Views grounded in data.** Each persona reads technicals / fundamentals / web intel with `as_of` pinned to *now* — no passing a stale forecast off as the present. Fundamentals are read point-in-time, filtered by report period and release lag so a backtest never sees a number before it was public (akshare today; yfinance v1 not yet PIT, flagged in place).
- **Views grounded in data.** Each persona reads technicals / fundamentals / web intel with `as_of` pinned to *now* — no passing a stale forecast off as the present. Fundamentals are read point-in-time, filtered by report period and release lag so a backtest never sees a number before it was public (Baostock today; yfinance v1 not yet PIT, flagged in place).
- **Structured bull / bear / risk debate — now live.** Beyond the parallel analysts, opposing-stance bull and bear researchers argue across rounds while a risk researcher stress-tests both — triggered only when the analysts genuinely disagree, with a soft early-stop when arguments stop changing and the full decision chain (why it debated, why it stopped, how it was synthesized) persisted for replay.

### 6. Skills — absorb outside research playbooks
Expand Down Expand Up @@ -234,7 +234,7 @@ Where each capability stands today. Live module inventory and the end-to-end dec
| ✅ Shipped | Bull / bear researcher debate | D-9 | opposing-stance researchers under `services/research` |
| ✅ Shipped | Scheduler / cron agent mode | D-9 | `scheduler_jobs` + advisory lock + `/api/scheduler/*` management plane |
| ✅ Shipped | RiskGuard per-account isolation | D-9.1a | `RiskGuardFactory` removes cross-account state bleed |
| ✅ Shipped | Multi-market data sources — web search + financial fundamentals | D-10 | zero-key DDGS web search · akshare (A-shares/HK) + yfinance (global) fundamentals · analyst integration + fallback · per-market lookbackDays |
| ✅ Shipped | Multi-market data sources — web search + financial fundamentals | D-10 | zero-key DDGS web search · `baostock` is the logical A-share venue: Tencent HTTPS bars/ticker + Baostock fundamentals/calendar/constituents; yfinance covers global markets including HK · analyst integration + fallback · per-market lookbackDays |
| ✅ Shipped | Risk engine — all 5 rules live in HTTP path | D-9 closed | `closed_trades` writes from HTTP order flow; `RoutingCalendar` for US equity + crypto; all trade-based rules trigger on real data |
| ✅ Shipped | `askUserChoice` — `ask` permission path | D-11 (issue #2) | pending-permission flow resolves the `ask` state (no longer a workaround) |
| ✅ Shipped | `permissions.yaml` configuration | D-11 (issue #4) | `config/permissions.default.yaml` + `yaml_loader.ts` replace the hard-coded `defaults.ts` |
Expand All @@ -249,7 +249,7 @@ Where each capability stands today. Live module inventory and the end-to-end dec
| ✅ Shipped | Factor discovery — L1 | D-12 | restricted qlib-style DSL (zero eval/exec) · `factor_candidates` pool · multiple-testing correction + null-IC benchmark · discovery workflow → propose; register is dashboard-only |
| ✅ Shipped | Cross-sectional factor scoring | D-12 | `factor.panel_score` · `POST /panel/score` · cross-sectional Rank IC (rank the pool each period vs forward cross-sectional return) · native Alpha101 a1/a3 · orthogonal to single-name timing |
| ✅ Shipped | Time-series cross-validation — anti-overfitting | D-12 | WalkForward / PurgedKFold / Combinatorial Purged CV + Deflated Sharpe · `POST /backtest/cv` · test fold always includes the latest bar · auto-fallback to walk-forward when samples are short |
| ✅ Shipped | Point-in-time fundamentals | D-12 | akshare financials filtered by report-period + release lag · `GET /fundamentals?as_of=` · prevents look-ahead (yfinance v1 not yet PIT, explicitly flagged) |
| ✅ Shipped | Point-in-time fundamentals | D-12 | Baostock financials filtered by actual publication date · `GET /fundamentals?as_of=` · prevents look-ahead (yfinance v1 not yet PIT, explicitly flagged) |
| 🗓️ Planned | Strategy evolution — E2 | E2 | multi-generation loop + MAP-Elites + Island Model + `unified-diff` mutations (E1 single-generation closed loop already shipped in D-9) |
| 🗓️ Planned | Factor discovery — L2 / L3 | L2 / L3 | multi-agent factor crew (L2) + weekly automated scans (L3), on top of the L1 DSL pipeline already shipped |
| 🗓️ Planned | Automated decay handling | TBD | reflection-driven backtest + auto-trim of decaying factors — today the decay patrol only alerts, never moves the book |
Expand Down
6 changes: 3 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ Inalpha 把*调度*和*算力*分开:agent runtime 负责扇出网格、聚合
一次深度研究不只给你一个"标准答案"。除了技术面、基本面、情绪面的常规 analyst,你还能叫上一支"大师团"——巴菲特(价值 / 护城河)、林奇(GARP 成长)、伍德(颠覆创新)、伯里(逆向 / 泡沫)、德鲁肯米勒(宏观趋势)、马克斯(周期 / 风险):各按自己的风格给观点,天然形成对立视角,再汇进综合判断。

- **按需启用,成本可控。** 不点名时普通研究成本不变;点了哪几位大师,才多跑那几次。
- **观点要落到数据。** 大师视角接技术面 / 基本面 / web 情报,`as_of` 是真现在,不许拿过时预测当现在。财报按 point-in-time 读取,依报告期 + 发布滞后过滤,回测看不到尚未公开的数字(akshare 已生效;yfinance v1 尚未 PIT,已就地标注)。
- **观点要落到数据。** 大师视角接技术面 / 基本面 / web 情报,`as_of` 是真现在,不许拿过时预测当现在。财报按 point-in-time 读取,依实际披露日期过滤,回测看不到尚未公开的数字(Baostock 已生效;yfinance v1 尚未 PIT,已就地标注)。
- **bull / bear / risk 结构化辩论——已上线。** 在并行 analyst 之外,立场对抗的多头与空头研究员多轮交锋,风险官同时压测双方——只在 analyst 真出现分歧时才触发,论点不再变化时软早停,完整决策链路(为什么辩、为什么停、如何综合)全程落盘可复盘。

### 6. Skills · 吸收外部投研方法论
Expand Down Expand Up @@ -232,7 +232,7 @@ Inalpha 把*调度*和*算力*分开:agent runtime 负责扇出网格、聚合
| ✅ 已上线 | Bull / Bear 研究员辩论 | D-9 | `services/research` 立场对抗研究员 |
| ✅ 已上线 | Scheduler / cron agent 模式 | D-9 | `scheduler_jobs` + advisory lock + `/api/scheduler/*` 管理面 |
| ✅ 已上线 | RiskGuard 账户级隔离 | D-9.1a | `RiskGuardFactory` 去除跨账户状态串联 |
| ✅ 已上线 | 多市场数据源 — web 搜索 + 财报基本面 | D-10 | DDGS 零 key web search · akshare(A股/港股)+ yfinance(全球)基本面 · analyst 接入 + 兜底 · lookbackDays 按市场分化 |
| ✅ 已上线 | 多市场数据源 — web 搜索 + 财报基本面 | D-10 | DDGS 零 key web search · `baostock` 是 A 股逻辑 venue:腾讯 HTTPS 行情/最新价 + Baostock 基本面/日历/成分;yfinance 覆盖全球(含港股)· analyst 接入 + 兜底 · lookbackDays 按市场分化 |
| ✅ 已上线 | 风控引擎 — 5 条规则全在 HTTP 路径激活 | D-9 收口 | `closed_trades` 由 HTTP 订单流写入;`RoutingCalendar` 覆盖美股 + crypto;trade-based 规则全在真实数据上触发 |
| ✅ 已上线 | `askUserChoice` — `ask` 权限路径 | D-11(issue #2) | pending-permission 流程把 `ask` 状态从 workaround 救回(已收口) |
| ✅ 已上线 | `permissions.yaml` 配置化 | D-11(issue #4) | `config/permissions.default.yaml` + `yaml_loader.ts` 替代 `defaults.ts` 硬编码 |
Expand All @@ -247,7 +247,7 @@ Inalpha 把*调度*和*算力*分开:agent runtime 负责扇出网格、聚合
| ✅ 已上线 | 因子发现 — L1 | D-12 | 受限 qlib 风格 DSL(零 eval/exec)· `factor_candidates` 候选池 · 多重检验校正 + null IC 基准 · discovery workflow → propose;register 仅 dashboard 人工 |
| ✅ 已上线 | 横截面因子打分 | D-12 | `factor.panel_score` · `POST /panel/score` · 横截面 Rank IC(每期对全池按因子排序 vs 跨标的前瞻收益)· Alpha101 a1/a3 原生 · 与单标的择时口径正交 |
| ✅ 已上线 | 时序交叉验证 — 防过拟合 | D-12 | WalkForward / PurgedKFold / Combinatorial Purged CV + Deflated Sharpe · `POST /backtest/cv` · test 段始终含最新 bar · 样本不足自动回落 walk-forward |
| ✅ 已上线 | 财报 point-in-time | D-12 | akshare 财报按报告期 + 发布滞后过滤 · `GET /fundamentals?as_of=` · 防前视(yfinance v1 尚未 PIT,已显式标注) |
| ✅ 已上线 | 财报 point-in-time | D-12 | Baostock 财报按实际披露日期过滤 · `GET /fundamentals?as_of=` · 防前视(yfinance v1 尚未 PIT,已显式标注) |
| 🗓️ 已规划 | 策略进化 — E2 | E2 | 多代演化 + MAP-Elites + Island Model + `unified-diff` 变异(E1 单代闭环已在 D-9 上线) |
| 🗓️ 已规划 | 因子发现 — L2 / L3 | L2 / L3 | 多 agent 因子小组(L2)+ 每周自动扫描(L3),建立在已上线的 L1 DSL pipeline 之上 |
| 🗓️ 已规划 | 因子衰减自动处置 | 待定 | 反思驱动回测 + 衰减因子自动剔除——当前衰减巡检只告警、绝不替你动仓 |
Expand Down
4 changes: 2 additions & 2 deletions docs/04-current-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ manager 综合已覆盖)、debate 轮内并行化、reasoning 进活动流前
Sharpe 分布 + DSR;`POST /backtest/cv`(cpcv 数据不足自动回落 walk_forward,整体甩
ProcessPool 不阻塞事件循环);`paper.cv_backtest` tool。**单策略报 DSR、不报 PBO**(CSCV-PBO
需多配置作输入,留 grid 层)。
- **财报 / bar Point-in-Time(阶段 A)**(ADR-0053 · #100):akshare 财报按"报告期末 + 120 天
发布滞后 ≤ as_of"过滤未披露报告期(防未来函数);`GET /fundamentals?as_of=`;paper
- **财报 / bar Point-in-Time(阶段 A)**(ADR-0053 · #100):Baostock 财报按实际公告日
`pubDate ≤ as_of` 过滤未披露报告期(防未来函数);`GET /fundamentals?as_of=`;paper
`DataClient.get_bars_pit` 把 bar 截断到 as_of。yfinance v1 不做 PIT 但响应显式标注;与 FRED
宏观 PIT(ADR-0044)口径对齐。

Expand Down
93 changes: 93 additions & 0 deletions infra/migrations/versions/0036_bars_a_share_symbol_canonical.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""规范化 A 股 bars 的历史 symbol 格式。

兼容期曾接受 ``SH.600519``、``600519.SH`` 等形式。venue 已统一为 ``baostock`` 后,
这些 symbol 仍会形成不同的持久化 namespace;本迁移将其合并为 ``sh.600519`` / ``sz.000001``。
"""

from __future__ import annotations

from alembic import op

revision: str = "0036"
down_revision: str | None = "0035"
branch_labels: str | tuple[str, ...] | None = None
depends_on: str | tuple[str, ...] | None = None

_PREFIX_SYMBOL_PATTERN = "^(sh|sz)[.][0-9][0-9][0-9][0-9][0-9][0-9]$"
_SUFFIX_SYMBOL_PATTERN = "^[0-9][0-9][0-9][0-9][0-9][0-9][.](sh|sz)$"

_CANONICAL_SYMBOL_SQL = f"""
CASE
WHEN btrim(symbol) ~* '{_PREFIX_SYMBOL_PATTERN}' THEN
lower(split_part(btrim(symbol), '.', 1)) || '.' ||
split_part(btrim(symbol), '.', 2)
WHEN btrim(symbol) ~* '{_SUFFIX_SYMBOL_PATTERN}' THEN
lower(substring(btrim(symbol) from '\\.([^.]+)$')) || '.' ||
regexp_replace(btrim(symbol), '\\.(sh|sz)$', '', 'i')
END
"""


def upgrade() -> None:
"""把旧 venue / symbol 组合合并到 canonical Baostock identity。"""
op.execute(
f"""
INSERT INTO bars (ts, venue, symbol, timeframe, open, high, low, close, volume)
SELECT DISTINCT ON (ts, canonical_symbol, timeframe)
ts,
'baostock',
canonical_symbol,
timeframe,
open,
high,
low,
close,
volume
FROM (
SELECT
ts,
venue,
symbol,
timeframe,
open,
high,
low,
close,
volume,
{_CANONICAL_SYMBOL_SQL} AS canonical_symbol
FROM bars
WHERE venue IN ('akshare', 'baostock')
AND (
btrim(symbol) ~* '{_PREFIX_SYMBOL_PATTERN}'
OR btrim(symbol) ~* '{_SUFFIX_SYMBOL_PATTERN}'
)
) AS candidates
WHERE canonical_symbol IS NOT NULL
AND NOT (venue = 'baostock' AND symbol = canonical_symbol)
ORDER BY
ts,
canonical_symbol,
timeframe,
CASE WHEN venue = 'baostock' THEN 0 ELSE 1 END,
symbol
ON CONFLICT (ts, venue, symbol, timeframe) DO NOTHING
"""
)
op.execute(
f"""
DELETE FROM bars
WHERE venue IN ('akshare', 'baostock')
AND (
btrim(symbol) ~* '{_PREFIX_SYMBOL_PATTERN}'
OR btrim(symbol) ~* '{_SUFFIX_SYMBOL_PATTERN}'
)
AND NOT (
venue = 'baostock'
AND symbol = ({_CANONICAL_SYMBOL_SQL})
)
"""
)


def downgrade() -> None:
"""symbol 原始大小写/前后缀不可无损恢复,降级保持 canonical 数据。"""
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fail 就 stop,不跨层补救**。同一结论要多源交叉验证,不信
| 公司名 → 可交易代码(一切个股研究的第一步) | `data.search_symbol`(A股返 sh./sz. 格式) |
| 实时价格 / 当日涨跌 | `data.get_ticker` |
| 历史 K 线(趋势 / 区间定位) | `data.get_bars`(保持默认 fresh) |
| PE_TTM / PB / ROE / 营收与利润增速 | `data.get_fundamentals`(venue=akshare) |
| PE_TTM / PB / ROE / 营收与利润增速 | `data.get_fundamentals`(venue=baostock) |
| 市场级财经快讯(盘面消息) | `data.get_market_news` |
| 行业板块涨跌幅榜(顺风 / 逆风) | `data.get_market_sectors` |
| 当日强势股 + 题材标签(主线确认) | `data.get_market_movers` |
Expand Down
6 changes: 3 additions & 3 deletions packages/orchestration/src/tools/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export const dataGetTickerTool = createTool({
取 venue/symbol 的"最新价"(单值,不是 K 线)。

- fresh=true(**默认**):直接调外部市场实时报价,绕过 DB 缓存。
**支持 venue**:binance / yfinance / alpaca;baostock / fred 不支持(返
**支持 venue**:binance / yfinance / alpaca / baostock;fred 不支持(返
FRESH_NOT_SUPPORTED_FOR_VENUE,hint 提示切 fresh=false)。
网络抖动 ~200-800ms;不要高频循环调(rate-limit)。
- fresh=false:从 DB 拿最新 1m → fallback 1h,任意 venue 都支持。
Expand All @@ -281,8 +281,8 @@ export const dataGetTickerTool = createTool({
何时不用:
- 要历史走势 / 做技术分析 → 用 data.get_bars
- 要 N 根 K 线 → 用 data.get_bars
- A 股 / FRED 想要"实时"价 → baostock/fred 没这能力,改 fresh=false 走 DB
cache(先 backfill_bars 灌一遍最新数据再调);港股走 yfinance 有实时 ticker
- A 股现价可用 baostock + fresh=true;FRED 没有盘中报价能力,改用 data.get_bars
或显式 fresh=false 读 DB cache。港股走 yfinance

坑:
- 默认 fresh=true!想要 DB cache 必须显式传 fresh:false
Expand Down
Loading
Loading