Edge
Get Edge to manage all of your crypto assets. The most secure way to buy, store and trade crypto under your control Accounts Created + 0 MM Assets Supported + 0 Languages Supported 0 Countries Support
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Banks make the calls. We grade them.
GradedCalls Analysts is the GradedCalls scorecard for sell-side recommendations. It ranks analysts and bank desks by how their ratings and price targets lined up with later prices, and it shows the arithmetic on every call.
The calls in this ledger come from public news sources. Each call links to that page. This repository does not scrape ranking sites, it is not affiliated with any bank or ratings publisher, and it is not investment advice. Past accuracy does not predict future results.
Brand rules: read BRAND.md before any UI change; deviations are an automatic MUST-FIX.
Requires Node.js 20 or newer. npm test passes on Node 20+ without a browser.
The grade-pill contrast check is optional. It runs inside npm test only when Node provides a global WebSocket (Node 22 or newer), Google Chrome, and ffmpeg are all installed. If any of those are missing, that one test skips with a message and the rest of the suite still passes. Screenshots from the check are written under artifacts/ (gitignored).
npm install
npm run db:reset
npm run dev
npm run dev also creates the SQLite database if it is missing. Open http://localhost:3000.
Other commands:
| Command | What it does |
|---|---|
npm test | Scoring, 90-day supersession, and CSV-parser checks. The pill-contrast check runs only when Node 22, Chrome, and ffmpeg are available |
npm run db:seed | Reload the ledger into SQLite |
npm run db:reset | Recreate the SQLite file and seed it |
npm run build | Generate the client, push the schema, seed, and build Next.js |
npm start | Serve the production build |
npm run import:calls -- data/your-feed.csv | Upsert a CSV feed |
npm run import:calls -- data/your-feed.csv --replace | Replace the database contents with that CSV |
npm run calls:validate | Check the call ledger against the grade rules |
npm run calls:export | Rewrite data/calls/calls.json from the CSV |
npx tsx scripts/scan-supersession-report.ts | Recount 90-day same-ticker pairs in the current database |
npm install && npm run build is enough for a production build. The prebuild step creates prisma/banktruth.db (gitignored) before next build.
| Route | What it shows |
|---|---|
/ | Hero, leaderboards, a best and worst followed call |
/leaderboards | Top analysts, top banks, worst offenders. Filter by 2W / 30D / 60D / 90D / 1Y and sector |
/analysts and /analysts/[slug] | Directory and a scorecard: overall factor, active book, superseded history |
/banks and /banks/[slug] | Firm rollup, sector mix, roster |
/tickers and /tickers/[symbol] | Direction for grading versus who was right on that name |
/calls and /calls/[id] | The call book, then one call: recommendation, desk rating, direction for grading, target, prices, source link, and the grade at each horizon |
/about | What the ledger is: public news sources, historical prices, and a formula that is not advice |
/methodology | The formula, read from the same constants the scorer uses |
/search | Analyst, bank, or ticker |
/watchlist | Saved in this browser only (localStorage). No account |
/disclaimer | Not advice, no client relationship, sourced calls, historical prices |
/terms | Draft terms: license, scraping, IP, DMCA, liability, governing law |
/donate | Draft donations page: gifts do not buy grades; no checkout in this build |
The full write-up is the Methodology page at /methodology. In short:
|price at horizon − target| / price at call. Inside a tight band it adds 30 points; past a wide band it adds none; in between it fades linearly. No target means the direction score is scaled to 100.src/lib/overall-factor.ts). The GC score is the same factor placed on the GC Scale. Superseded calls do not enter it. Leaderboards sort on this factor. The tube grades are STRONG, WEAK, PROVISIONAL, and EXIT LIQUIDITY.The score is not market-adjusted. A buy in a rising tape can hit without insight. That limit is stated on the methodology page.
SQLite via Prisma, file at prisma/banktruth.db.
Bank, Analyst, Ticker, Coverage, Callsrc/lib/scoring.ts). They are not baked into the row, so a formula change does not require a reseedsrc/lib/supersession.ts) for every call in the database, including the seeded ledger and CSV imports. Nullified rows are not stored as a separate flagprisma/seed.ts loads data/calls/calls.json. Prices are Yahoo Finance adjusted closes (adjusted for splits and dividends). A missing quote aborts the seed. A horizon that runs past 26 Oct 2026 is stored blank and left ungraded. Notes restate the rating and target from the public source. They are not a quotation of a research report.
data/calls/calls.csv is the source of truth for analyst calls. npm run calls:export rewrites data/calls/calls.json, and the seed loads that file into SQLite. Pages still compute each grade at render time, so the JSON carries the call, the rating, the target, the prices, and the source URL, not a stored GC score.
Rows in the live ledger use data_source=public. That value means a public news source, not a licensed feed. A public row needs a routable source_url, must match the analyst and firm registry, must match pricesForCall, cannot be dated after the price history, and cannot be labelled verified. data_source=licensed stays available for a later feed you have the rights to. Only a licensed row may be labelled verified, and it needs a source_url. The validator rejects any row that is not public or licensed. Do not scrape TipRanks, Bloomberg, or X, and do not call a paid market-data or rankings API.
Grades use the same rules as the board. 70 and above is STRONG, 40 up to 70 is PROVISIONAL (69.9 stays PROVISIONAL), under 40 is WEAK, and a graded 0 is EXIT LIQUIDITY. A horizon with no price reads "Not graded yet". The label is exactly GC Scale.
Each week:
data/calls/calls.csv. One row per call. Leave a horizon price blank until that window has closed. Prices must match the adjusted closes already in the repo. Do not invent a price.npm run calls:validate. A failure stops the export.npm run calls:export. An unchanged CSV produces a byte-identical JSON file.gradeCall) and do not hard-code a row count.npm run import:calls remains a separate adapter for a one-off feed. It is not the ledger the site seeds.
Do not scrape a rankings site. Use a price history and a call archive you have the rights to.
Produce a CSV with one row per call. Required columns:
call_id,date,bank_slug,bank_name,analyst_slug,analyst_name,ticker,company,sector,action,rating_to,price_at_call
Optional columns:
bank_short,headquarters,analyst_title,industry,exchange,rating_from,price_target_from,price_target_to,price_14d,price_30d,price_60d,price_90d,price_1y,note
Dates are YYYY-MM-DD. rating_to is the desk rating, not the headline: strong_buy, buy, overweight, outperform, hold, neutral, equal_weight, underperform, underweight, sell. action is initiate, upgrade, downgrade, reiterate, target_raise, or target_cut. The screen builds the recommendation from those two fields: Initiate Buy, Upgrade to Overweight, Downgrade to Neutral, Reiterate Outperform, Maintain Hold (a reiteration of Hold, Neutral, or Equal-Weight), Target raise, Target cut. A target_raise with rating_to=sell is labeled Target raise. Sell appears only as the direction for grading. Outcome prices are the print 14, 30, 60, 90, and 365 calendar days after the call. Leave an outcome blank when that window has not elapsed.
A two-row example lives at data/import-example.csv. It is not loaded by the seed.
Import:
npm run import:calls -- data/your-feed.csv --replace
--replace deletes the banks, analysts, tickers, and calls first. Without it, rows upsert by call_id and can sit beside the ledger, which you usually do not want.
The import path is the adapter boundary:
src/lib/imports/types.ts — RawCallRecord and CallFeedAdaptersrc/lib/imports/csv-feed.ts — CsvCallFeed and JsonCallFeedsrc/lib/imports/apply.ts — applyCallFeed(), which upserts into Prismascripts/import-calls.ts — CLIA future licensed API is another class with pull(): Promise<RawCallRecord[]>, passed to applyCallFeed. The pages do not care where the rows came from. Keep on the call so a public row and a licensed row stay distinguishable.
Import the GitHub repository. No environment variables and no secrets. The database is created during the build and does not call a market-data API.
Use these settings. The defaults already match; do not override the build command.
| Setting | Value |
|---|---|
| Framework preset | Next.js |
| Root directory | ./ (repository root) |
| Node.js version | 22.x |
| Install command | npm install (leave the default) |
| Build command | npm run build (leave the default) |
| Output directory | leave the Next.js default |
| Environment variables | none required |
The public origin is https://analysts.gradedcalls.com. The header mark opens the hub at https://www.gradedcalls.com. Sports is https://www.gradedcalls.com/sports, FinTwit is https://fintwit.gradedcalls.com, and GCBot is https://bot.gradedcalls.com. NEXT_PUBLIC_SITE_URL, NEXT_PUBLIC_HUB_URL, NEXT_PUBLIC_FINTWIT_URL, and NEXT_PUBLIC_BOT_URL override those origins. Leave them unset and a preview deployment still publishes the gradedcalls.com hosts.
npm run build runs prebuild first: Prisma generates the client, creates prisma/banktruth.db, and seeds it. That file is traced into the server bundle. On Vercel the filesystem is read-only except /tmp, so each instance copies the seed to /tmp/banktruth.db before reading it. Do not change the build command to bare next build — that skips the seed and the live routes will have no database.
Do not set DATABASE_URL for this deploy. Do not commit a .env. When that variable is unset and no .env file is present, the build scripts pass Prisma the local SQLite path (file:./banktruth.db, resolved beside schema.prisma). Copy .env.example to .env only if you want a different path. Do not set NODE_ENV yourself. A postgresql:// DATABASE_URL is only for a later hosted database, and it also requires changing the Prisma datasource provider to postgresql.
This deploy is read-only. A writable production feed should use Postgres rather than SQLite on serverless disk.
GradedCalls Analysts is independent. It is not investment advice. Past accuracy does not predict future results. Figures in this ledger are the sourced calls and the adjusted closes used to grade them. GradedCalls Analysts is not affiliated with those firms or with any rankings publisher.
sourcePostgres, if you outgrow the file: point DATABASE_URL at a postgresql:// URL, change the Prisma datasource provider to postgresql, and run prisma db push. src/lib/db.ts already uses a Postgres URL when it sees one, and falls back to the SQLite file otherwise. Outcome prices still have to be supplied by your feed; this app does not call a market-data vendor.