One of the app's features lets you select abrdn ETFs in the Watchlist and aggregate their holdings to see how often each ticker appears across the selected funds. Repeated holdings make overlapping exposure visible: the more selected funds include a ticker, the greater its potential influence on the portfolio; gains in that holding may help, while declines may hurt, and actual impact also depends on each fund's position size. Another feature makes it faster and easier to find funds with stronger growth over different periods, higher dividend yields or distributions, greater Total Return (price performance plus dividends), and other key performance metrics. A single-file client-side tool that reads the generated ./api/aberdeen static feed (official Aberdeen Investments catalog, NAV, expenses, yields, portfolio holdings and month-/quarter-end NAV performance; SEC EDGAR N-PORT-P holdings fallback; Yahoo Finance market-price history and dividend fallback) into a searchable ETF/asset-class catalog with per-fund tabs, watchlist aggregation, ticker copy and CSV/TXT export — the same look, feel, columns and business logic as the sibling applications.
bunx degit daggerok/aberdeen#main ./12345 && cd $_
bunx serve . -p 1234
open http://0:1234The application URL is https://daggerok.github.io/aberdeen/.
Publication is pending merge and Pages activation. During review use the feature branch feat/aberdeen-plan-recovery instead of main; PR #1 remains open.
Run the updater with Bun:
bun test scripts/update-data.test.ts
./scripts/update-data.tsRun ./scripts/update-data.ts -h (or --help) to print the effective configuration and usage examples. The updater has no runtime dependencies.
Defaults live next to the updater in scripts/update-data.config.json. With no overrides the updater refreshes the entire discovered US ETF catalog (MAX_FETCHES=0, TICKERS=""), keeps published data when a provider fails, and writes only meaningful changes. It does not skip fetching a fund merely because yesterday's data exists. Unchanged reruns do not create timestamp-only diffs.
The Update abrdn ETF data GitHub Actions workflow exposes the same settings as manual inputs. All supplied filters use AND logic. It runs Sundays at 00:00 UTC and on manual dispatch, with no push trigger; the schedule becomes active after the workflow reaches the default branch.
| Block | Source |
|---|---|
| Catalog (all US abrdn ETFs), official NAV | POST https://www.aberdeeninvestments.com/api/gateway/funds/overview and /prices, with fund_product_type=Exchange Traded Fund, pagination, and no date override. The public entry points are the ETF page and fund finder. |
| Per-fund facts and exchange price | Official fund page __NEXT_DATA__.props.pageProps.pageData.fundDetailsData, plus POST /api/gateway/funds/fundDetailsKeyInformation and /fundDetailsCodes. Example: AGEM. |
| Full securities holdings | POST /api/gateway/funds/breakdown/dailyHoldings with the holding type enabled in the fund's own detail configuration, all pages through totalResults. The official /breakdown/dailyHoldingsSheet XLSX download was independently verified; the updater uses its structured JSON counterpart. Top-ten lists are never substituted for full holdings. |
| NAV total returns | POST /api/gateway/funds/performance/annualized and /performance/cumulative, quarterly=false for month-end, quarterly=true for quarter-end. Use the NAV category, not benchmark or market-price returns. Reporting dates come from the response, even if stale. |
| Market-price history and dividends | Yahoo Finance public chart API https://query1.finance.yahoo.com/v8/finance/chart/{TICKER} with daily bars and dividend events. Adjusted close is rounded to 2 decimals. These are not official NAV history rows. |
| Holdings fallback | SEC fund-ticker/series map, series Atom feed, registrant submissions/full-text discovery, and N-PORT-P XML. Shared parsers follow JPMorgan; each filing must match the requested series (or exact normalized fund name). abrdn Funds filings associate AGEM/AFSC/ASCI/AMUN with CIK 0001413594 (1, 1); other mappings are discovered from SEC, not guessed. |
| Last resort | Existing committed meta.json, holdings and history pages. An unavailable endpoint must not erase published data. |
The generated snapshot verified on 2026-09-27 contains 11 ETFs, 328 securities positions, and 27,067 daily history rows. Source as-of dates remain attached to each fund and each series.
Each fund carries the same derived metrics object as the sibling sites:
ytd/tr1y— official returns when published; gaps derived from Yahoo adjusted closes at the same reporting date.cagr3y/cagr5y/cagr10y— official annualized NAV returns first.tr3y/tr5y/tr10y—(1 + CAGR)^n - 1; a real zero stays zero.siAnn— official annualized since-inception return, or adequately covered Yahoo history; range-limited history is not called since-inception.dividendYield— indicated latest distribution × annual payment frequency ÷ market price.secYield— official subsidized 30-day SEC yield when available; otherwise previously published value or null.
Known limitations
- Physical trusts: GLTR, PALL, PPLT, SGOL and SIVR do not expose a securities-holdings tab in the verified API. They remain in the catalog with facts/performance/history, but their securities portfolio is marked
not-applicable; no synthetic bullion rows or invented tickers are generated. Physical bar lists are not converted into securities positions. - SEC live access: this environment returned HTTP 403 for SEC lookup/submissions endpoints. The fallback is implemented and fixture-tested, including wrong-series rejection, but live SEC retrieval has not been validated here. Official holdings supply all six securities ETFs in the initial snapshot; no third-party holdings scraper was needed. If all holdings sources fail, published holdings are kept.
- History/distributions: a usable official daily NAV-history/dividend-series endpoint was not found during this implementation. Yahoo market-price history and distributions fill that role. Official cumulative growth charts and calendar-year returns are not misrepresented as daily NAV or trailing one-year returns.
- Dates and inception: a converted ETF can publish its predecessor fund's inception and historical NAV returns. These official dates are preserved rather than replaced by its first Yahoo trading day. NAV and market-price dates can differ; premium/discount is not computed across unmatched dates.
- Network/CI: provider schemas, throttling and CDN availability can change. Conservative request pacing and bounded retries apply. Tests are offline; a passing test suite does not imply every live provider is reachable. GitHub-hosted Actions execution is pending publication of the workflow to the default branch.
- Client dependencies: like the sibling UI, the browser loads Tailwind/Babel from CDNs and needs network access for them. No server backend or runtime package installation is required for the app.
Precedence:
- Built-in safe defaults.
scripts/update-data.config.json(committed, non-secret defaults).- Actions
advancedJSON overrides. - Explicit nonblank individual Actions inputs.
CONCURRENCYandTICKERSare separate primary inputs.
For local execution, environment variables override the file; ABERDEEN_<NAME> overrides the unprefixed name. No credentials belong in the config file. Actions exposes 24 individual controls plus advanced, respecting GitHub's 25-input limit. SEC_UA, VERBOSE, STORE_RAW_DOWNLOADS, and SKIP_ABERDEEN are available through advanced; JSON may override any canonical control. Invalid keys, invalid ranges, non-scalar values and newline injection are rejected before requests.
Blank individual inputs mean inherit, not clear. To clear a file's ticker restriction in Actions, use {"TICKERS":""} in advanced.
| Environment variable | Default | Meaning |
|---|---|---|
MAX_FETCHES |
0 |
Batch size; positive resumes cursor, 0 refreshes the selected universe and resets cursor. |
REQUEST_SLEEP |
1 |
Seconds between request starts including retries; conservative shared gate. |
CONCURRENCY |
2 |
Parallel fund workers; request starts remain conservatively paced. |
AUM |
: |
Net assets min:max in USD; K/M/B/T or nano/micro/small/mid/large preset. |
TER |
: |
Gross expense ratio percent min:max. |
DIVIDEND_YIELD |
: |
Indicated dividend yield percent min:max. |
SEC_YIELD |
: |
30-day SEC yield percent min:max. |
TICKERS |
all |
Ticker allowlist separated by spaces, commas or semicolons; empty means all. |
HOLDINGS_PAGE_SIZE |
250 |
Rows per holdings JSON page. |
HISTORY_PAGE_SIZE |
1000 |
Rows per market-price history JSON page. |
MAX_RETRIES |
2 |
Retries after the first request; 0 disables retries. |
HISTORY_RANGE |
max |
Yahoo daily history range: max or Ny (e.g. 5y); preserves prior history. |
STORE_RAW_DOWNLOADS |
false |
Save source JSON under api/aberdeen/raw. |
SEC_UA |
daggerok Aberdeen ETF feed (https://github.com/daggerok/aberdeen) |
SEC User-Agent; supply a real identifying contact for automated access. |
SKIP_YAHOO |
false |
Skip Yahoo history and dividends; retain published data. |
SKIP_ABERDEEN |
false |
Use published catalog/details; only fallback providers are called. |
EDGAR_FALLBACK |
true |
Enable SEC N-PORT holdings fallback; never use an unrelated series. |
VERBOSE |
false |
Print per-request failures and fallback diagnostics. |
PERFORMANCE_YTD |
: |
Annualized YTD return percent min:max. |
PERFORMANCE_1Y |
: |
Annualized 1Y return percent min:max. |
PERFORMANCE_3Y |
: |
Annualized 3Y return percent min:max. |
PERFORMANCE_5Y |
: |
Annualized 5Y return percent min:max. |
PERFORMANCE_10Y |
: |
Annualized 10Y return percent min:max. |
TOTAL_RETURN_YTD |
: |
Cumulative YTD return percent min:max. |
TOTAL_RETURN_1Y |
: |
Cumulative 1Y return percent min:max. |
TOTAL_RETURN_3Y |
: |
Cumulative 3Y return percent min:max. |
TOTAL_RETURN_5Y |
: |
Cumulative 5Y return percent min:max. |
TOTAL_RETURN_10Y |
: |
Cumulative 10Y return percent min:max. |
TICKERS combines with all other filters. Excluded and failed funds keep their previous published files and index entries. A bounded batch counts selected funds, follows deterministic ticker order, and does not advance its cursor if the batch has failures. A successful full pass removes the cursor.
# Entire catalog, using committed defaults
bun scripts/update-data.ts
# Primary runtime controls
TICKERS="AGEM AMUN SGOL" CONCURRENCY=2 bun scripts/update-data.ts
MAX_FETCHES=3 bun scripts/update-data.ts
AUM="1B:" TER=":0.5" bun scripts/update-data.ts
PERFORMANCE_1Y="15:" bun scripts/update-data.ts
STORE_RAW_DOWNLOADS=1 VERBOSE=1 bun scripts/update-data.tsManual Actions advanced example (leave individual inputs blank to inherit):
{"CONCURRENCY":2,"TICKERS":"AGEM BCD SGOL","VERBOSE":true,"STORE_RAW_DOWNLOADS":false}The scoped command TICKERS="AGEM AMUN SGOL" VERBOSE=1 bun scripts/update-data.ts was live-tested twice in an isolated copy: three funds processed, zero failures, byte-identical rerun, and all eight nonselected funds preserved. See the recorded smoke-test evidence and run/config summary. This did not refresh the committed production feed.
Use your real identifying contact in SEC_UA when running SEC automation. A User-Agent change does not guarantee that an execution environment's HTTP 403 will disappear.
The browser app is intentionally build-free: index.html carries the markup, styles and bootstrap, and app.tsx is TypeScript compiled in the browser with Babel standalone — no build step, no bundler, no tsconfig.json needed. Bun runs TypeScript out of the box.
Verification before every publish: bun install --frozen-lockfile, bun test, and git diff --check.
Additional transpilation checks: bun build --target=bun scripts/update-data.ts --outfile=/dev/null and bun build app.tsx --outfile=/dev/null. These do not perform semantic TypeScript checking. Do not add tsc, a TypeScript dependency or a tsconfig.json.
The UI reference is daggerok/JPMorgan @ c1ef7858f61689f3d20636d6c83711d41faa722e.
| Brand | Where to get the data |
|---|---|
| abrdn (Aberdeen) | aberdeeninvestments.com | aberdeen |
| Amplify | amplifyetfs.com | Amplify |
| Capital Group | capitalgroup.com | Capital-Group |
| Fidelity | fidelity.com | Fidelity |
| First Trust | ftportfolios.com | First-Trust |
| Franklin Templeton | franklintempleton.com | Franklin |
| Global X | globalxetfs.com/explore | Global X |
| Goldman Sachs | am.gs.com | Goldman-Sachs |
| Invesco | invesco.com | Invesco |
| iShares | ishares.com | iShares |
| JPMorgan | am.jpmorgan.com | JPMorgan |
| NEOS | neosfunds.com | Neos |
| Northern Trust | etfs.ntam.northerntrust.com | Northern-Trust |
| ProShares | proshares.com | ProShares |
| Schwab | schwabassetmanagement.com | Schwab |
| SPDR | ssga.com | SPDR |
| VanEck | vaneck.com | VanEck |
| Vanguard | investor.vanguard.com | Vanguard |
| VictoryShares | vcm.com VictoryShares ETFs | VictoryShares |
| WisdomTree | wisdomtree.com | WisdomTree |
| Application | Data provider | Repository |
|---|---|---|
| abrdn (Aberdeen) | Official Aberdeen gateway + SEC N-PORT holdings fallback + Yahoo history/dividends | aberdeen |
| Amplify | Amplify ETFs (Firestore data feed) | Amplify |
| Capital Group | Official Capital Group fund data + SEC N-PORT holdings fallback + Yahoo history fallback | Capital-Group |
| Fidelity | SEC EDGAR N-PORT-P + Yahoo Finance | Fidelity |
| First Trust | ftportfolios.com official ETF list + fund summary, holdings, distribution and price-history export pages + SEC EDGAR N-PORT-P holdings fallback + Yahoo Finance history fallback | First-Trust |
| Franklin Templeton | franklintempleton.com ETF listings + product pages + SEC EDGAR N-PORT-P | Franklin |
| Global X | globalxetfs.com Next.js catalog and fund pages + dated full-holdings CSV | Global X |
| Goldman Sachs | am.gs.com fund finder + detail pages + SEC EDGAR N-PORT-P | Goldman-Sachs |
| Invesco | invesco.com CSV downloads + Yahoo Finance | Invesco |
| iShares | iShares (BlackRock) product workbooks | iShares |
| JPMorgan | am.jpmorgan.com fund explorer + product-data JSON | JPMorgan |
| NEOS | neosfunds.com lineup table + official fund pages + daily holdings CSV | Neos |
| Northern Trust | etfs.ntam.northerntrust.com funds list + per-fund CSV/JSON downloads | Northern-Trust |
| ProShares | proshares.com ETF finder + fund pages + official data host | ProShares |
| Schwab | schwabassetmanagement.com product pages + CSV exports | Schwab |
| SPDR | SSGA / State Street public feeds | SPDR |
| VanEck | vaneck.com ETF finder + product pages | VanEck |
| Vanguard | Vanguard product pages + SEC EDGAR N-PORT-P | Vanguard |
| VictoryShares | VCM VictoryShares catalog and product JSON + SEC EDGAR N-PORT-P holdings fallback + Yahoo Finance adjusted-market-price history | VictoryShares |
| WisdomTree | WisdomTree product table + SEC EDGAR N-PORT-P + Yahoo Finance | WisdomTree |
abrdn®, Aberdeen and the fund names/tickers referenced here are trademarks of their respective owners. This is an independent, unofficial tool; it is not affiliated with, endorsed by, or sponsored by abrdn or Aberdeen Investments. Data is obtained from the official public fund site, public SEC filings when accessible, and Yahoo Finance for research purposes. All other trademarks, including index names, belong to their respective owners.