You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
Explanatory intro on every stock data tab — each tab on the stock page (price, holdings, short interest, short volume, fails-to-deliver, financials, SEC documents, insider trading, proposed sales, fund holdings, fund operations, exempt offerings, congressional trades) now opens with a short description of what the data is and where it comes from, rendered via a shared _TabIntro partial. PR #3165.
Investment advisers (SEC Form ADV) — browse SEC-registered investment advisers at /advisers (name search, ranked largest-by-assets, paginated) with a per-firm profile at /advisers/{crd} showing regulatory assets under management (discretionary / non-discretionary / total), main office, employee count and fee structure. Data comes from the SEC's bulk Form ADV download, refreshed monthly by a background worker and keyed by Organization CRD number. Two MCP tools expose the same data to assistants: SearchInvestmentAdvisers (by name) and GetInvestmentAdviser (full profile by CRD). Issue #1866 (PRs #2867, #2868, #2869, #2870, #2871).
Fund portfolio holdings (SEC Form NPORT) — parses funds' monthly portfolio filings in the worker, exposes a fund's holdings via MCP, and adds a "Fund holdings" tab to the stock page listing the largest positions with value and percentage of net assets (capped, showing the largest N of M). Issue #1868 (PRs #2860, #2861, #2862, #2863).
Registered-fund annual operations (SEC Form N-CEN) — parses N-CEN filings in the worker, exposes them via MCP, and adds a "Fund operations" tab to the stock page surfacing each tracked fund/ETF's service providers (auditor, custodian, transfer agent, principal underwriter, etc.). Issue #1869 (PRs #2856, #2857, #2858, #2859).
Form D exempt offerings (private placements) — parses Form D notices in the worker, exposes them via the GetExemptOfferings MCP tool, and adds an "Exempt offerings" tab to the stock page with offering amount, amount sold, minimum investment, investor count and claimed Regulation D exemptions (offering amounts reported as "Indefinite" are preserved). Issue #1867 (PRs #2851, #2852, #2853, #2855).
Form 144 proposed insider sales — parses Form 144 notices (an insider's intent to sell restricted or control stock) in the worker, exposes them via the GetProposedSales MCP tool, and adds a "Proposed sales" tab to the stock page showing seller, relationship, shares, aggregate market value and approximate sale date. Issue #1865 (PRs #2846, #2847, #2849, #2850).
Raw XBRL filing artifacts — the worker now captures and stores the original iXBRL/XBRL document for each financial filing on ingest, preserving the machine-readable source alongside the parsed facts. PRs #2864, #2865.
Fund scoring — a scoring engine rates 13F filers on risk-adjusted performance (alpha versus a benchmark), recomputed by a background worker, with scores surfaced and sortable in the institutions portal. PRs #2837, #2838, #2839, #2841.
Smart Money Index page in the institutions portal — aggregates the highest-scoring funds into a single consensus signal. PRs #2843, #2845.
Bollinger Bands on the stock price chart and via a GetBollingerBands MCP tool, computed by the technical-indicator service. PRs #2833, #2834, #2835.
Moving-average cross (golden/death cross) and consecutive up/down price-streak detection, shown as badges on the stock Technicals tab. PRs #2827, #2828.
Price performance versus SPY on the stock price tab — trailing and calendar-window returns benchmarked against the S&P 500. PRs #2825, #2826.
Location and AUM / position-count range filters on the institutions index. PRs #2823, #2824.
Global search results are now sorted by date, most recent first. PR #2842.
Contributor License Agreement (CLA.md) based on Project Harmony HA-CLA-I-ANY 1.0. Contributors must sign via CLA Assistant before pull requests can be merged. Enables Equibles to remain AGPL-3.0 while sharing code with the commercial offering.
Optional configureOptions callback on AddEquiblesDbContext<TContext> (applied after the standard Npgsql + lazy-loading setup) so a host can adjust context-level DbContextOptions — e.g. suppress a specific warning — without replacing the registration helper. Default behavior unchanged. PR #2279.
Most-shorted stocks leaderboard at /most-shorted — ranks stocks by FINRA short interest for a selected bi-monthly settlement date (current short position, change vs. previous, days to cover, average daily volume), with a settlement-date selector, server-side sort, and pagination; each row links to the per-stock short-interest tab. Issue #2536 (PR #2755).
Largest short volume page at /short-volume — ranks stocks by FINRA consolidated daily short volume for a selected trading day, with a trading-day selector, sort, and pagination. Issue #2644 (PR #2753).
GetLargestShortVolume MCP tool — market-wide ranking of the largest daily short volume for a trading day (defaults to the latest available). PR #2646.
Per-quarter 13F aggregate snapshot tables, with background rebuild + drain workers and first-boot backfill, backing the holdings stats/trends pages. PRs #2463, #2468, #2473, #2476.
Segmented stock-section navbar with summary metrics on the Technicals tab. PR #2534.
Short-volume-percentage line overlaid on the per-stock short volume chart. PR #2533.
Typeahead institution picker on the overlap matrix page. PR #2524.
Exact-ticker search submissions now redirect straight to the stock page. PR #2529.
Cmd/Ctrl+K global search shortcut (replacing /) to match the commercial portal. PR #2510.
Insider-trading per-share prices are cross-checked against Yahoo and flagged when implausible.
Schedule 13D/13G beneficial-ownership filings — parses 13D/13G XML, ingests filings from the EDGAR daily index plus a realtime sweep, and adds a filing-type filter to the institutional holders table so activist/passive stakes can be isolated. PRs #3566, #3567, #3568, with parser robustness follow-ups (PRs #3580, #3611, #3617, #3626, #3678, #3679).
Off-exchange (OTC/ATS) volume — scrapes FINRA's OTC Transparency weekly volume data and exposes it via the GetOffExchangeVolume MCP tool. PRs #3569, #3570, #3571.
Investor relations news and events — the worker discovers each stock's IR page URL, classifies the IR platform, and scrapes news, events, and the earnings calendar from Nasdaq IR Insight and Q4 Inc sites (with a per-stock discovery cooldown); GetInvestorRelationsNews and GetInvestorRelationsEvents MCP tools expose the data. PRs #3572, #3574, #3595, #3596, #3598, #3600, #3601, #3604, #3608.
Dimensional XBRL facts — financial facts now carry a dimensions key, an extraction service sweeps captured XBRL envelopes into dimensional facts, and the GetRevenueBreakdown MCP tool surfaces segment/product/geography revenue splits. PRs #3613, #3614, #3615, #3621, #3629.
Composite short-squeeze score — rates stocks from stored short data (short interest, days to cover, short-volume ratio, fails-to-deliver), exposed via the GetShortSqueezeScores MCP tool. PRs #3623, #3624.
Reverse fund-ownership lookup — the GetFundsHoldingStock MCP tool lists the funds holding a given stock from NPORT portfolio data, backed by a new CUSIP index and reverse-lookup queries. PRs #3610, #3625.
Per-holder quarterly AUM snapshots materialised by the snapshot worker, backing faster institution history reads. PR #3628.
Institutional ownership trend chart on the stock holdings tab — per-quarter holder count and aggregate position trend. PRs #3634, #3635.
FRED economic release calendar — imported during the scraper cycle and exposed via the GetEconomicCalendar MCP tool. PRs #3647, #3648, #3649.
Congressional annual financial disclosures — parses House Clerk annual reports (Form A) with column-aware schedule extraction and Senate eFD annual reports, rolls assets and liabilities up into net-worth bands, and exposes them via the GetMemberNetWorth MCP tool. PRs #3653, #3655, #3658, #3662, #3663.
DEF 14A proxy statements — new document type included in the scraper form set, with multi-word form types accepted by the HTML normalizer. PRs #3671, #3672.
8-K item numbers are captured on ingest and saved documents are announced on the bus. PR #3575.
Percent-of-class on institutional holdings, parsed from 13D/G cover pages. PR #3565.
NPORT-P filings are reprocessed to backfill fund holdings ingested before the parser landed. PR #3498.
Changed
Multi-context module system. Split EquiblesDbContext into an abstract EquiblesDbContextBase (module iteration, no Postgres extensions) plus a concrete EquiblesFinancialDbContext (enables pgvector; ParadeDB stays in the Npgsql options). Renamed EquiblesDbContext → EquiblesFinancialDbContext. Added IFinancialModule / ICustomerModule markers so a host can scan for either domain; every OSS module implements IFinancialModule. BaseRepository is now generic over the context (BaseRepository<TEntity, TContext>) with a one-arg shim binding to the financial context, so existing repositories are unchanged. AddEquiblesDbContext is generic over the context with a per-context ModuleConfigurationSet<TContext> (no shared module list); added the AddEquiblesFinancialDbContext convenience overload. Unlocks deployments running a second context (e.g. a customer database) over the same module system. PR #2258.
No transactional outbox in OSS standalone.AddMessaging no longer registers the EF outbox and gains a configureBus hook so a host can opt a context into one. OSS consumers must therefore be idempotent (no inbox/dedup ships). CommonStockManager.SetCusip now publishes afterSaveChanges to avoid phantom events on rollback. PR #2258.
Holdings snapshot rebuilds are now throttled and coalesced.Filings13FImportedConsumer no longer rebuilds the AUM/sector snapshots inline — it marks the affected quarter dirty via a new DirtyAt timestamp on AumQuarterlySnapshot. A new AumSnapshotDrainWorker ticks every 5 minutes and rebuilds any quarter whose dirty flag has been set for more than an hour, using optimistic-concurrency clear so a consumer event landing mid-rebuild isn't lost. During 13F filing-season burst windows hundreds of imports per day for the same quarter now produce one rebuild per cooldown window instead of one per import. The daily safety-net AumSnapshotRebuildWorker is narrowed to the four most recent quarters (older quarters are effectively frozen — amendments trigger their own consumer event). First-boot backfill of every quarter is unchanged.
Holdings stats and trends pages (/holdings/stats, /holdings/trends) now read the per-quarter snapshots instead of recomputing aggregates on each request. PR #2479.
Per-stock quarterly 13F activity backing the conviction heat map is now materialized by the snapshot worker instead of recomputed per request, so the heat map renders from precomputed rows. PR #3238.
Stock data tabs clamp their history to the configured minimum sync date (Worker__MinSyncDate), so price, short-data, holdings, insider, and congressional views never show partially-backfilled periods. PRs #3638, #3639, #3640.
13F and NPORT data-set processing is version-stamped, so rows imported by an older parser are reprocessed automatically after a parser fix instead of staying wrong until a manual backfill.
SEC rate-limit handling — a 429 now pauses all SEC requests for the full block window, in-flight successes no longer produce a false "cleared" signal, and block/clear transitions publish bus events for observability.
The historical XBRL backfill worker now defaults off — the one-time sweep of legacy documents has drained; new filings capture their XBRL on ingest. PR #3622.
Fixed
Insider-trading values for companies listed via American Depositary Shares (ADS/ADR) are no longer overstated. These Form 4 filings report the share count in the issuer's underlying ordinary shares but quote the price per ADS, so the dashboard's shares × price read far too high — e.g. SaverOne (SVRE) appeared as an ~$8.6B insider buy when the real value was ~$200K. The price is now restated to a per-ordinary basis (from the filing's footnotes) whenever the share count is an exact multiple of the ADS ratio, leaving the as-filed price preserved. Existing rows are corrected on the next filing reprocess.
XBRL financial values wrapped in parentheses and carrying an explicit sign="-" are no longer double-negated — a parenthesised negative now resolves to a single negative value. PR #2819.
Financial tables with merged rowspan/colspan cells are expanded to a rectangular grid before parsing, so values land in the correct row and column. PR #2820.
CFTC Commitments-of-Traders ingestion looks up CSV columns by the headers cftc.gov actually ships rather than by fixed position, so a column reorder no longer mismaps positioning data. PR #2478.
Short-interest pages (the /most-shorted leaderboard and the per-stock settlement-date selector) load faster: ShortInterestRepository.GetAllSettlementDates now walks the distinct settlement dates with a recursive loose index scan instead of SELECT DISTINCT, which scanned the whole SettlementDate index on every request and spiked on a cold buffer cache. Falls back to the DISTINCT query on non-relational providers.
CommonStockManager.SetCusip publishes StockCusipChanged via the root IBus instead of the scoped IPublishEndpoint. A commercial host that enables a bus outbox on a different DbContext (the customer database) would otherwise capture this publish into that context and never deliver it — the flow only saves the financial context. Tests updated to substitute IBus. PR #2271.
Culture-invariance hardening — MCP tool tables, web date/number formatting, SEC/CFTC/FINRA date parsing, and worker interval logging now consistently use the invariant culture, so output and parsing no longer depend on the server locale. Numerous PRs (e.g. #2748, #2735, #2724, #2705, #2661, #2464, #2460).
Ticker normalization uses ToUpperInvariant across the web StocksController and the Holdings / InsiderTrading MCP resolvers. PRs #2609, #2517.
Version comparison handles v-prefixed tags so the new-version banner doesn't misfire. PR #2621.
CBOE put/call ingestion switched to the daily-page scraper and now persists incrementally so a cold start populates. PRs #2526, #2751.
House congressional PTR PDFs are parsed via page geometry so Representatives land in the right columns. PR #2530.
SEC Form 4 transaction-code mapping corrected (I/W). PR #2469.
Investment-adviser name search treats LIKE wildcards (%, _) in the query as literal characters, so a search containing them no longer matches unintended advisers. Issue #2905 (PR #3010).
The FINRA daily short-volume scraper now guards against the parent CommonStock disappearing between the per-cycle ticker-map read and the per-batch write — the same guard already applied to the Yahoo, FTD, and FinancialFacts scrapers. A cold-start tick alongside CompanySyncService could otherwise trip FK_*_CommonStock_CommonStockId and fail the entire insert batch (poisoning rows for surviving stocks too); stale IDs are now re-validated against the live CommonStock table per batch and dropped with a warning so the surviving rows still persist. Issue #3288 (follow-up to #1591).
Form 4 insider trades are attributed to the issuer of the traded security instead of the reporting owner's own ticker, and the insider dashboard no longer inflates totals with derivative prices or chain-duplicated filings. PRs #3500, #3502.
13F filings that duplicate the position value into the share-count column are repaired on import. PR #3499.
SEC document normalizer no longer promotes "Part … of …" / "Item … of …" prose sentences to headings (including after page breaks), unwraps spaced inline content divs, and matches list-item wrapper classes as whole tokens. PRs #3484, #3487, #3488, #3491, #3531, #3532, #3553.
MCP tools clamp client-supplied maxResults so out-of-range values can no longer produce a negative SQL LIMIT or oversized result sets. PRs #3540, #3541, #3544.
MCP tool calls with a missing or wrongly-typed required argument return a structured "Invalid parameters" result naming the tool instead of an opaque internal error. PRs #3609, #3680.
Fund Operations and Fund Holdings tabs are shown only for funds/ETFs. PR #3503.
Backtest CAGR is no longer annualized for windows under 90 days, and the Double-Down Report excludes degenerate prior bases. PRs #3494, #3495.
CBOE put/call ingestion stitches the chunked Next.js RSC payload back together before extracting the JSON, fixing empty imports after CBOE's site change. PR #3607.
Senate eFD search and row dates are parsed culture-pinned, so congressional ingestion works on non-English-locale servers. Issues #3659, #3660 (PRs #3665, #3668).
FTD feed symbols are resolved to class-share tickers when seeding CUSIPs, and EDGAR ticker rows without an exchange are skipped when parsing active companies. PRs #3616, #3618.
Field truncation no longer splits UTF-16 surrogate pairs (filing fields and XBRL file names). PRs #3481, #3529.
13F filing summaries collapse to one row per accession before upsert, and FINRA's zero-volume days-to-cover sentinel is dropped from the squeeze score. PRs #3650, #3651.
Filings whose primaryDocDescription is missing are kept instead of skipped. PR #3354.
Container healthchecks give startup migrations time to complete before failing. PR #3492.
Security
Neutralized the javascript: scheme in Markdown autolinks. PR #2633.
Baseline security response headers and HSTS on the web portal. PR #3542.