尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证ThinkFin Research Platform
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A research platform that explains why a mutual fund should or should not be considered for a portfolio — performance quality, risk survival, portfolio DNA, overlap, manager skill, and stress behaviour — rather than just ranking funds by returns.
This is a zero-budget, modular-monolith build. See docs/BUILD_PLAN.md for the
full Phase 0 architecture, database ERD, API plan, and development roadmap.
frontend/ Next.js app
backend/ FastAPI app (app/api, app/models, app/schemas, app/services, app/repositories, app/core)
analytics/ Deterministic financial calculation modules (Phase 4+)
data_pipeline/ Source adapters + ingestion/validation/normalization (Phase 3+)
database/ Alembic migrations + seed data (top-level, shared by backend)
docs/ BUILD_PLAN.md and (later) architecture/methodology docs
.github/workflows/ CI
Either run Postgres via Docker:
docker compose up -d
or use a local Postgres install with a thinkfin database matching
backend/.env's DATABASE_URL.
cd backend
python3 -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
cp .env.example .env # adjust DATABASE_URL if needed
alembic upgrade head
uvicorn app.main:app --reload --port 8000
Health check: curl http://localhost:8000/api/health → {"status":"ok","database":"ok"}
Run tests: pytest -q
cd frontend
npm install
cp .env.local.example .env.local
npm run dev
Visit http://localhost:3000 — the dashboard shell renders the backend's live
health-check response, confirming the full stack is wired end-to-end.
NEXT_PUBLIC_API_URL to the deployed backend URL)DATABASE_URL in the backend's environment; schema is standard PostgreSQL with no Supabase-specific features)analytics/, from Phase 4 onward).data_sources, data_ingestion_runs).analytics_version so methodology changes are traceable over time.The core schema ships empty. To exercise it end to end with a small set of
entirely fictional, clearly-labelled sample funds (see the file header
in database/seeds/seed_sample_data.py for exactly what is and isn't real):
cd backend && source .venv/bin/activate
python ../database/seeds/seed_sample_data.py # idempotent
python ../database/seeds/seed_sample_data.py --reset # wipe + reseed
This creates 2 sample AMCs, 4 schemes, 8 scheme variants (direct/regular × growth), synthetic NAV and benchmark history (seeded random walk, not real market data), sample portfolio holdings, managers, and market regimes.
Deterministic financial calculations live in analytics/ at the repo root
(never in the frontend, never computed by an LLM — see Rule 4). Covered so
far: CAGR/simple returns, rolling returns + benchmark consistency,
annualized volatility, Sharpe, Sortino, max drawdown + recovery, upside/
downside capture, beta and Jensen's alpha. Full methodology — formulas,
assumptions, limitations — is in docs/analytics-methodology.md.
cd backend && source .venv/bin/activate
pytest tests/analytics -q
data_pipeline/ implements the AMFI NAVAll.txt adapter end to end: fetch
(sources/amfi/client.py) -> parse (sources/amfi/parser.py) -> validate
(validation/nav_validation.py) -> map to existing schemes
(normalization/scheme_mapping.py) -> upsert + log
(storage/database_writer.py, ingestion/nav_ingestion.py). Every run is
logged to data_ingestion_runs with accept/reject counts, success or
failure. Full source documentation, including exactly what has and hasn't
been verified live, is in docs/data-sources.md.
cd backend && source .venv/bin/activate
pytest tests/unit/test_amfi_parser.py tests/unit/test_nav_validation.py \
tests/unit/test_amfi_client.py tests/integration/test_nav_ingestion.py -q
# Run for real once network access + Phase 2 seed data are available:
python -m data_pipeline.orchestration.daily_pipeline
GET /api/funds, /api/funds/{id}, /api/funds/{id}/{returns,risk, rolling-returns,drawdown,intelligence} — structured, validated JSON built
on the Phase 4 analytics engine. Full documentation, including the fund/
variant identity model and design decisions, is in docs/api.md. Try it
live at http://localhost:8000/docs once the backend is running.
cd backend && source .venv/bin/activate
pytest tests/api/test_funds.py -q
The Next.js frontend now has a real Research section, not just the health
check shell: /research (search/browse funds) and /research/[fundId]
(the fund intelligence page — returns, risk, a NAV-vs-benchmark chart,
rolling-return distribution with benchmark consistency, and drawdown, with
direct/regular and growth/IDCW plan toggles). Built against a small
Phase-6 addition to the API, GET /api/funds/{id}/nav-history, since
charting needs the raw series, not just computed metrics.
# with the backend running on :8000
cd frontend && npm run dev
# visit http://localhost:3000/research
Verified in a real browser (Playwright + the pre-installed Chromium) against
live seeded data, including the search/filter form, plan/option toggles,
the rolling-returns window selector, the insufficient-history and
no-such-variant states, and a themed 404 page. See docs/api.md for the
new endpoint.
GET /api/funds/{id}/portfolio — top holdings, sector allocation,
market-cap allocation, and concentration (HHI + top-5/top-10 weight),
computed by analytics/concentration.py from the Phase 2 seed portfolio
snapshots. Scheme-level (not variant-specific: holdings don't depend on
plan/option). Required a small schema addition,
securities.market_cap_category (nullable — null for bonds and
anything unclassified, grouped as "unclassified" rather than guessed).
Wired into the fund detail page as a "Portfolio DNA & Concentration"
section. See docs/analytics-methodology.md for the HHI methodology and
docs/api.md for the endpoint.
cd backend && source .venv/bin/activate
pytest tests/analytics/test_concentration.py tests/api/test_portfolio.py -q
Cross-fund "hidden concentration" (seeing the same stock/sector overexposure across several funds an investor holds) is explicitly out of scope here — that needs the Overlap Engine, Phase 8.
GET /api/funds/{id}/overlap?compare_to={other_id} — pairwise overlap
between two funds: common holdings (weight in each), weighted overlap %
(the standard "shared exposure" methodology), sector overlap, an overlap
label (documented as a practitioner heuristic, not an official standard —
unlike HHI's DOJ/FTC thresholds), and return correlation. Implemented in
analytics/{overlap,correlation}.py. A new /research/compare page lets
you pick any two funds and see the full breakdown, linked from every fund
detail page ("Compare with…"). See docs/analytics-methodology.md for
the overlap methodology and docs/api.md for the endpoint.
cd backend && source .venv/bin/activate
pytest tests/analytics/test_overlap.py tests/analytics/test_correlation.py tests/api/test_overlap.py -q
Multi-fund (3+) "hidden concentration" and combined-portfolio analysis — the rest of Section 9/11 — need Phase 9's Portfolio Analysis engine.
POST /api/portfolio/analyse — combine 2-10 funds by weight into a single
hypothetical portfolio: look-through combined holdings, sector/market-cap
allocation, concentration (HHI on the combined exposure), pairwise
overlap between every constituent pair, and portfolio-level volatility/
Sharpe/Sortino/drawdown computed from the weight-combined return series.
Built entirely from existing Phase 4/7/8 analytics via
analytics/portfolio.py's combination formulas — no new risk/
concentration math. Stateless: no auth system exists yet, so this
takes funds+weights in the request rather than reading/writing a
persisted "my portfolio" (see docs/api.md for why).
A new /portfolio page lets you build a hypothetical portfolio from 2-10
funds with a weight per fund and see the full breakdown — linked from the
main nav on every page.
cd backend && source .venv/bin/activate
pytest tests/analytics/test_portfolio.py tests/api/test_portfolio_analysis.py -q
GET /api/funds/{id}/market-regimes — fund vs. benchmark return,
volatility and max drawdown within each defined market regime, plus a
deterministic (templated, not LLM-written) outperform/underperform
summary per regime and an overall "beat benchmark in N of M periods"
rollup. GET /api/market/regimes lists the regimes themselves. Built on
analytics/market_regime.py, which reuses the existing returns/risk/
drawdown functions restricted to each regime's date window — simple
(non-annualized) return rather than CAGR, since regimes are often
sub-annual.
Data provenance, stated plainly: the sample dataset's regimes are
illustrative windows shaped to match the synthetic seed's own
trajectory, not verified real market classifications — every response
carries this as methodology_note, and it's documented in
docs/data-sources.md.
Wired into the fund detail page as a "Market-Cycle Behaviour" section,
and into a new /market page (finally a real destination for the
previously-placeholder "Market Intelligence" nav item — sector trends and
a broader risk-environment view remain unbuilt).
cd backend && source .venv/bin/activate
pytest tests/analytics/test_market_regime.py tests/api/test_market_regime.py -q
GET /api/funds/{id}/stress-test — hypothetical scenario impact
estimates for the 7 scenarios named in the product spec. 3 are
computed: a broad-market decline (via the fund's beta to its
benchmark), a mid-cap-segment decline and a sector decline (via disclosed
exposure from Phase 7). 4 are honestly marked unmodeled — interest
rates rising, recession, INR depreciation, inflation shock — each with a
specific reason naming the data this platform doesn't have yet (bond
duration, currency exposure, a macro factor model). No invented
sensitivity coefficients stand in for missing data; see
docs/analytics-methodology.md for why, and the configurable
SCENARIOS table in analytics/stress_testing.py.
Wired into the fund detail page as a "Stress Test" section, right after Market-Cycle Behaviour.
cd backend && source .venv/bin/activate
pytest tests/analytics/test_stress_testing.py tests/api/test_stress_test.py -q
GET /api/funds/{id}/ai-summary — a human-readable summary of a fund's
already-computed figures (returns, risk, drawdown, rolling returns,
market-regime behaviour, concentration). The AI computes nothing: it's
given a small, flat, named dict built entirely from the existing tested
endpoints above (app/services/ai_explanation_service.build_fund_facts),
and every number in its output is checked against that same dict before
being returned — a fabricated number gets the whole summary discarded,
not softened or ignored. On the frontend it's an opt-in "Generate AI
Summary" button on the fund page (not auto-loaded — an LLM call costs
real money, and this is a zero-budget project).
Known limitation: api.anthropic.com is reachable from this dev
environment (confirmed — an invalid key correctly gets HTTP 401, not a
connection failure) but no ANTHROPIC_API_KEY is provisioned for the
application. Everything up to that boundary is tested with the LLM call
mocked; set the key in .env to enable the live path, no code changes
needed. See docs/api.md for the full architecture diagram.
cd backend && source .venv/bin/activate
pytest tests/unit/test_ai_explanation_service.py tests/api/test_ai_summary.py -q
.github/workflows/ci.yml — runs the full backend test suite (159 tests,
against a throwaway Postgres service container — no secrets needed) and
the frontend build/lint on every push and PR. Verified by actually
running the same sequence against a genuinely fresh database before
committing it, not assumed to work.
.github/workflows/daily-nav-ingestion.yml — built and ready, but its
schedule: trigger is deliberately commented out: it needs a real,
persistent DATABASE_URL secret pointing at a provisioned database,
which doesn't exist yet. Fails fast with a clear error if triggered
without it, rather than a cryptic connection failure. See
docs/deployment.md for exactly how to turn it on once that database
exists.
A monthly holdings/factsheet workflow was deliberately not built.
There's no real holdings-ingestion source yet (AMC factsheets aren't
parsed — see docs/data-sources.md), and a scheduled job with nothing
real to call would be automation theater, not automation.
Bug found and fixed along the way: data_pipeline/orchestration/ daily_pipeline.py's documented invocation (python -m data_pipeline. orchestration.daily_pipeline) had never actually been run — Phase 3's
tests exercised the ingestion logic via pytest and the API, not this CLI
entry point. Running it for the first time while building this phase's
workflow immediately hit ModuleNotFoundError: No module named 'app'
(the script imports app.core.database but nothing had put backend/
on sys.path). Fixed with the same sys.path bootstrap already used by
backend/conftest.py and database/migrations/env.py, then re-verified:
it now runs, connects to the database, and fails cleanly at the already-
documented AMFI network boundary — exactly the intended behaviour.
Phase 0 through 13 complete. Phase 3 (NAV ingestion) and
Phase 12 (AI Explanation Layer) are each architecturally complete and
fully tested down to their respective network/credential boundary; Phase
13's scheduled ingestion workflow is built and tested logically but not
yet turned on, pending real database infrastructure — see Known
limitations and docs/deployment.md for exactly what remains.
This completes the phases in the original build plan (docs/BUILD_PLAN.md).
What's next is either provisioning the real infrastructure the remaining
gaps need (a database reachable from CI, an LLM API key, a factsheet
source for holdings) or extending the product itself (Section 15's
qualitative Strengths/Risks/Portfolio-role framework, deliberately
deferred throughout since it needs signal from engines like Manager
Skill that don't exist yet).
postcss dependency (via the pinned next version) has 2
known vulnerabilities per npm audit (1 high, 1 moderate) — build-time
CSS processing issues, not runtime user-input handling. The fix is a
breaking major Next.js upgrade that needs its own review pass; tracked
in docs/deployment.md rather than forced through unreviewed.amfiindia.com (and api.mfapi.in) is
blocked by this sandbox's network policy (confirmed via a 403 policy
denial on the proxy's CONNECT attempt). Everything downstream of the
fetch — parsing, validation, scheme mapping, storage, idempotency,
failure logging — is tested end-to-end against the real database using
a synthetic fixture in place of the live download (see
backend/tests/integration/test_nav_ingestion.py). Running
python -m data_pipeline.orchestration.daily_pipeline from an
environment with outbound internet access, and confirming it inserts
real NAV rows, is the one remaining step before Phase 3 can be marked
fully done.scheme_variants that already exist
in the database (matched by AMFI code or ISIN) — it deliberately never
creates a new scheme from a NAV file alone (see
data_pipeline/normalization/scheme_mapping.py). Onboarding new schemes
needs curated identity data (AMC, category, plan/option), which is a
separate, not-yet-built workflow.DATABASE_URL secret, which hasn't been provisioned — adding a workflow
that can't actually run against real infrastructure would violate the
"run and verify before moving on" rule this build follows.