mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-26 01:24:59 +02:00
* feat(economic): add ME grocery basket price index Adds a grocery basket price comparison panel for 9 Middle East countries (UAE, KSA, Qatar, Kuwait, Bahrain, Oman, Egypt, Jordan, Lebanon) using EXA AI to discover prices from regional e-commerce sites (Carrefour, Lulu, Noon, Amazon) and Yahoo Finance for FX rates. - proto: ListGroceryBasketPrices RPC with CountryBasket/GroceryItemPrice messages - seed: seed-grocery-basket.mjs, 90 EXA calls/run, 150ms delay, hardcoded FX fallbacks for pegged GCC currencies, 6h TTL - handler: seed-only RPC reading economic:grocery-basket:v1 - gateway: static cache tier for the new route - bootstrap/health: groceryBasket key in SLOW tier, 720min stale threshold - frontend: GroceryBasketPanel with scrollable table, cheapest/priciest column highlighting, styles moved to panels.css - panel disabled by default until seed is run on Railway * fix(generated): restore @ts-nocheck in economic service codegen * fix(grocery-basket): tighten seed health staleness and seed script robustness - Set maxStaleMin to 360 (6h) matching CACHE_TTL so health alerts on first missed run - Use ?? over || for FX fallback to handle 0-value rates correctly - Add labeled regex patterns with bare-number warning in extractPrice - Replace conditional delay logic with unconditional per-item sleep * fix(grocery-basket): fix EXA API format and price extraction after live validation - Use contents.summary format (not top-level summary) — previous format returned no data - Support EXA_API_KEYS (comma-separated) in addition to EXA_API_KEY - Extract price from plain-text summary string (EXA returns text, not JSON schema) - Remove bare-number fallback — too noisy (matched "500" from "pasta 500g" as SAR 500) - Fix LBP FX rate zero-guard: use fallback when Yahoo returns 0 for ultra-low-value currencies Validated locally: 9 countries seeded, Redis write confirmed, ~111s runtime * fix(grocery-basket): validate extracted currency against expected country currency - matchPrice now returns the currency code alongside the price - extractPrice rejects results where currency != expected country currency (prevents AED prices from being treated as JOD prices on gcc.luluhypermarket.com) - Tighten item queries (white granulated sugar, spaghetti pasta, etc.) to reduce irrelevant product matches like Stevia on sugar queries - Replace Jordan's gcc.luluhypermarket.com (GCC-only) with carrefour.jo + ounasdelivery.com - Sync scripts/shared/grocery-basket.json * feat(bigmac): add Big Mac Index seed + drop grocery basket includeDomains Grocery basket: - Remove includeDomains restriction — EXA neural search finds better sources than hardcoded domain lists; currency validation prevents contamination - Tighten query strings (supermarket retail price suffix) Big Mac seed (scripts/seed-bigmac.mjs): - Two-tier search: specialist sites (theburgerindex.com, eatmyindex.com) first, fall back to open search for countries without per-country indexed pages - Handle thousands-separator prices (480,000 LBP) - Accept USD prices from cost-of-living index sites as fallback - Exclude ranking/average pages (Numbeo country_price_rankings, Expatistan) - Validated live: 7/9 countries with confirmed prices UAE=19AED, KSA=19SAR, QAR=22QAR, KWD=1.4KWD, EGP=135EGP, JOD=3JOD, LBP=480kLBP * feat(economic): expand grocery basket to 24 global countries, drop Big Mac tier-2 search Grocery basket: extend coverage from 9 MENA to 24 countries across all regions (US, UK, DE, FR, JP, CN, IN, AU, CA, BR, MX, ZA, TR, NG, KR, SG, PK, AE, SA, EG, KE, AR, ID, PH). Add FX fallbacks and fxSymbols for all 23 new currencies. CCY regex in seed script updated to match all supported currency codes. Big Mac: remove tier-2 open search (too noisy, non-specialist pages report combo prices or global averages). Specialist sites only (theburgerindex.com, eatmyindex.com) for clean per-country data. * feat(bigmac): wire Big Mac Index RPC, proto, bootstrap, health Add ListBigMacPrices RPC end-to-end: - proto/list_bigmac_prices.proto: BigMacCountryPrice + request/response - service.proto: register ListBigMacPrices endpoint (GET /list-bigmac-prices) - buf generate: regenerate service_server.ts + all client stubs - server/list-bigmac-prices.ts: seed-only handler reads economic:bigmac:v1 - handler.ts: wire listBigMacPrices into EconomicServiceHandler - api/bootstrap.js: bigmac key in BOOTSTRAP_CACHE_KEYS + SLOW_KEYS - api/health.js: bigmac key in BOOTSTRAP_KEYS + SEED_META (maxStaleMin: 1440) - _bootstrap-cache-key-refs.ts: groceryBasket + bigmac refs * feat(bigmac): add BigMacPanel + register in panel layout BigMacPanel renders a country-by-country Big Mac price table sorted by USD price (cheapest/most expensive highlighted). Wired into bootstrap hydration, refresh scheduler, and panel registry. Registered in panels.ts (enabled: false, to be flipped once seed data is verified). Also updates grocery basket i18n from ME-specific to global wording. * fix(bigmac): register bigmac in cache-keys and RPC_CACHE_TIER Add bigmac to BOOTSTRAP_CACHE_KEYS and BOOTSTRAP_TIERS in server/_shared/cache-keys.ts, and to RPC_CACHE_TIER (static tier) in gateway.ts. Both were caught by bootstrap and RPC tier parity tests. * fix(generated): restore @ts-nocheck in all generated service files after buf regenerate buf generate does not emit @ts-nocheck. Previous convention restores it manually post-generate to suppress strict type errors in generated code. * fix(grocery-basket): restore includeDomains per country, add userLocation, fix currency symbol parsing Root cause of 0-item countries (UK, JP, IN, NG): removing includeDomains caused EXA neural search to return USD-priced global comparison pages (Numbeo, Tridge, Expatistan) which currency validation correctly rejected. Fixes: - Add per-country sites[] in grocery-basket.json (researched local supermarket/retailer domains: tesco.com, kaufland.de, bigbasket.com, etc.) - Pass includeDomains: country.sites to restrict EXA to local retailers - Pass userLocation: country.code (ISO) to bias results to target country - Add currency symbol fallback regex (£→GBP, €→EUR, ¥→JPY, ₹→INR, ₩→KRW, ₦→NGN, R$→BRL) — sites like BigBasket use ₹ not INR - Summary query now explicitly requests ISO currency code - Simplify item queries (drop country name — context from domains) Smoke test results: UK sugar → GBP 1.09 (tesco.com) ✓ IN rice → ₹66 (bigbasket.com) ✓ JP rice → JPY 500 (kakaku.com) ✓ * fix(grocery-basket): add Firecrawl fallback, parallel items, bulk caps, currency floors - Add Firecrawl as JS-SPA fallback after EXA (handles noon.com, coupang, daraz, tokopedia, lazada) - Parallelize item fetching per country with 200ms stagger: runtime 38min to ~4.5min - Add CURRENCY_MIN floors (NGN:50, IDR:500, KRW:1000, etc.) to reject product codes as prices - Add ITEM_USD_MAX bulk caps (sugar:8USD, salt:5USD, rice:6USD, etc.) applied to both EXA and Firecrawl - Fix SA: use noon.com/saudi-en + carrefour.com.sa (removes luluhypermarket cross-country pollution) - Fix EG: use carrefouregypt.com + spinneys.com.eg + seoudi.com (removes GCC luluhypermarket) - Expand sites for DE, MX, ZA, TR, NG, KR, IN, PK, AR, ID, PH to improve coverage - Sync scripts/shared/grocery-basket.json with shared/grocery-basket.json * fix(grocery-basket): address PR review comments P1+P2 P1 - fix ranking with incomplete data: only include countries with >=70% item coverage (>=7/10) in cheapest/mostExpensive ranking — prevents a country with 4/10 items appearing cheapest due to missing data P1 - fix regex false-match on pack sizes / weights: try currency-first pattern (SAR 8.99) before number-first to avoid matching pack counts; use matchAll and take last match P2 - mark seed-miss responses as non-cacheable: add upstream_unavailable to proto + return true on empty seed so gateway sets Cache-Control: no-store on cold deploy * fix(generated): update EconomicService OpenAPI docs for upstream_unavailable field
1120 lines
44 KiB
YAML
1120 lines
44 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: EconomicService API
|
|
version: 1.0.0
|
|
paths:
|
|
/api/economic/v1/get-fred-series:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetFredSeries
|
|
description: GetFredSeries retrieves time series data from the Federal Reserve Economic Data.
|
|
operationId: GetFredSeries
|
|
parameters:
|
|
- name: series_id
|
|
in: query
|
|
description: FRED series ID (e.g., "GDP", "UNRATE", "CPIAUCSL").
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: limit
|
|
in: query
|
|
description: Maximum number of observations to return. Defaults to 120.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
format: int32
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetFredSeriesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/list-world-bank-indicators:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: ListWorldBankIndicators
|
|
description: ListWorldBankIndicators retrieves development indicator data from the World Bank.
|
|
operationId: ListWorldBankIndicators
|
|
parameters:
|
|
- name: indicator_code
|
|
in: query
|
|
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: country_code
|
|
in: query
|
|
description: Optional country filter (ISO 3166-1 alpha-2).
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: year
|
|
in: query
|
|
description: Optional year filter. Defaults to latest available.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
format: int32
|
|
- name: page_size
|
|
in: query
|
|
description: Maximum items per page.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
format: int32
|
|
- name: cursor
|
|
in: query
|
|
description: Cursor for next page.
|
|
required: false
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ListWorldBankIndicatorsResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-energy-prices:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetEnergyPrices
|
|
description: GetEnergyPrices retrieves current energy commodity prices from EIA.
|
|
operationId: GetEnergyPrices
|
|
parameters:
|
|
- name: commodities
|
|
in: query
|
|
description: Optional commodity filter. Empty returns all tracked commodities.
|
|
required: false
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetEnergyPricesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-macro-signals:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetMacroSignals
|
|
description: GetMacroSignals computes 7 macro signals from 6 upstream sources with BUY/CASH verdict.
|
|
operationId: GetMacroSignals
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetMacroSignalsResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-energy-capacity:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetEnergyCapacity
|
|
description: GetEnergyCapacity retrieves installed capacity data (solar, wind, coal) from EIA.
|
|
operationId: GetEnergyCapacity
|
|
parameters:
|
|
- name: energy_sources
|
|
in: query
|
|
description: |-
|
|
Energy source codes to query (e.g., "SUN", "WND", "COL").
|
|
Empty returns all tracked sources (SUN, WND, COL).
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: years
|
|
in: query
|
|
description: Number of years of historical data. Default 20 if not set.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
format: int32
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetEnergyCapacityResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-bis-policy-rates:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetBisPolicyRates
|
|
description: GetBisPolicyRates retrieves central bank policy rates from BIS.
|
|
operationId: GetBisPolicyRates
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetBisPolicyRatesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-bis-exchange-rates:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetBisExchangeRates
|
|
description: GetBisExchangeRates retrieves effective exchange rates from BIS.
|
|
operationId: GetBisExchangeRates
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetBisExchangeRatesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-bis-credit:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetBisCredit
|
|
description: GetBisCredit retrieves credit-to-GDP ratio data from BIS.
|
|
operationId: GetBisCredit
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetBisCreditResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-fred-series-batch:
|
|
post:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetFredSeriesBatch
|
|
description: GetFredSeriesBatch retrieves multiple FRED series in a single call.
|
|
operationId: GetFredSeriesBatch
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetFredSeriesBatchRequest'
|
|
required: true
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetFredSeriesBatchResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/list-grocery-basket-prices:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: ListGroceryBasketPrices
|
|
description: ListGroceryBasketPrices retrieves grocery basket price comparison across 24 countries worldwide.
|
|
operationId: ListGroceryBasketPrices
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ListGroceryBasketPricesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/list-bigmac-prices:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: ListBigMacPrices
|
|
description: ListBigMacPrices retrieves Big Mac Index prices across Middle East countries.
|
|
operationId: ListBigMacPrices
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ListBigMacPricesResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
/api/economic/v1/get-national-debt:
|
|
get:
|
|
tags:
|
|
- EconomicService
|
|
summary: GetNationalDebt
|
|
description: GetNationalDebt retrieves national debt clock data for all countries.
|
|
operationId: GetNationalDebt
|
|
responses:
|
|
"200":
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GetNationalDebtResponse'
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ValidationError'
|
|
default:
|
|
description: Error response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
components:
|
|
schemas:
|
|
Error:
|
|
type: object
|
|
properties:
|
|
message:
|
|
type: string
|
|
description: Error message (e.g., 'user not found', 'database connection failed')
|
|
description: Error is returned when a handler encounters an error. It contains a simple error message that the developer can customize.
|
|
FieldViolation:
|
|
type: object
|
|
properties:
|
|
field:
|
|
type: string
|
|
description: The field path that failed validation (e.g., 'user.email' for nested fields). For header validation, this will be the header name (e.g., 'X-API-Key')
|
|
description:
|
|
type: string
|
|
description: Human-readable description of the validation violation (e.g., 'must be a valid email address', 'required field missing')
|
|
required:
|
|
- field
|
|
- description
|
|
description: FieldViolation describes a single validation error for a specific field.
|
|
ValidationError:
|
|
type: object
|
|
properties:
|
|
violations:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/FieldViolation'
|
|
description: List of validation violations
|
|
required:
|
|
- violations
|
|
description: ValidationError is returned when request validation fails. It contains a list of field violations describing what went wrong.
|
|
GetFredSeriesRequest:
|
|
type: object
|
|
properties:
|
|
seriesId:
|
|
type: string
|
|
minLength: 1
|
|
description: FRED series ID (e.g., "GDP", "UNRATE", "CPIAUCSL").
|
|
limit:
|
|
type: integer
|
|
format: int32
|
|
description: Maximum number of observations to return. Defaults to 120.
|
|
required:
|
|
- seriesId
|
|
description: GetFredSeriesRequest specifies which FRED series to retrieve.
|
|
GetFredSeriesResponse:
|
|
type: object
|
|
properties:
|
|
series:
|
|
$ref: '#/components/schemas/FredSeries'
|
|
description: GetFredSeriesResponse contains the requested FRED series data.
|
|
FredSeries:
|
|
type: object
|
|
properties:
|
|
seriesId:
|
|
type: string
|
|
minLength: 1
|
|
description: Series identifier (e.g., "GDP", "UNRATE", "CPIAUCSL").
|
|
title:
|
|
type: string
|
|
description: Series title.
|
|
units:
|
|
type: string
|
|
description: Unit of measurement.
|
|
frequency:
|
|
type: string
|
|
description: Data frequency (e.g., "Monthly", "Quarterly").
|
|
observations:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/FredObservation'
|
|
required:
|
|
- seriesId
|
|
description: FredSeries represents a FRED time series with metadata.
|
|
FredObservation:
|
|
type: object
|
|
properties:
|
|
date:
|
|
type: string
|
|
description: Observation date as YYYY-MM-DD string.
|
|
value:
|
|
type: number
|
|
format: double
|
|
description: Observation value.
|
|
description: FredObservation represents a single data point from a FRED economic series.
|
|
ListWorldBankIndicatorsRequest:
|
|
type: object
|
|
properties:
|
|
indicatorCode:
|
|
type: string
|
|
minLength: 1
|
|
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
|
|
countryCode:
|
|
type: string
|
|
description: Optional country filter (ISO 3166-1 alpha-2).
|
|
year:
|
|
type: integer
|
|
format: int32
|
|
description: Optional year filter. Defaults to latest available.
|
|
pageSize:
|
|
type: integer
|
|
format: int32
|
|
description: Maximum items per page.
|
|
cursor:
|
|
type: string
|
|
description: Cursor for next page.
|
|
required:
|
|
- indicatorCode
|
|
description: ListWorldBankIndicatorsRequest specifies filters for retrieving World Bank data.
|
|
ListWorldBankIndicatorsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/WorldBankCountryData'
|
|
pagination:
|
|
$ref: '#/components/schemas/PaginationResponse'
|
|
description: ListWorldBankIndicatorsResponse contains World Bank indicator data.
|
|
WorldBankCountryData:
|
|
type: object
|
|
properties:
|
|
countryCode:
|
|
type: string
|
|
minLength: 1
|
|
description: ISO 3166-1 alpha-2 country code.
|
|
countryName:
|
|
type: string
|
|
description: Country name.
|
|
indicatorCode:
|
|
type: string
|
|
minLength: 1
|
|
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
|
|
indicatorName:
|
|
type: string
|
|
description: Indicator name.
|
|
year:
|
|
type: integer
|
|
format: int32
|
|
description: Data year.
|
|
value:
|
|
type: number
|
|
format: double
|
|
description: Indicator value.
|
|
required:
|
|
- countryCode
|
|
- indicatorCode
|
|
description: WorldBankCountryData represents a World Bank indicator value for a country.
|
|
PaginationResponse:
|
|
type: object
|
|
properties:
|
|
nextCursor:
|
|
type: string
|
|
description: Cursor for fetching the next page. Empty string indicates no more pages.
|
|
totalCount:
|
|
type: integer
|
|
format: int32
|
|
description: Total count of items matching the query, if known. Zero if the total is unknown.
|
|
description: PaginationResponse contains pagination metadata returned alongside list results.
|
|
GetEnergyPricesRequest:
|
|
type: object
|
|
properties:
|
|
commodities:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: Optional commodity filter. Empty returns all tracked commodities.
|
|
description: GetEnergyPricesRequest specifies which energy commodities to retrieve.
|
|
GetEnergyPricesResponse:
|
|
type: object
|
|
properties:
|
|
prices:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EnergyPrice'
|
|
description: GetEnergyPricesResponse contains energy price data.
|
|
EnergyPrice:
|
|
type: object
|
|
properties:
|
|
commodity:
|
|
type: string
|
|
minLength: 1
|
|
description: Energy commodity identifier.
|
|
name:
|
|
type: string
|
|
description: Human-readable name (e.g., "WTI Crude Oil", "Henry Hub Natural Gas").
|
|
price:
|
|
type: number
|
|
format: double
|
|
description: Current price in USD.
|
|
unit:
|
|
type: string
|
|
description: Unit of measurement (e.g., "$/barrel", "$/MMBtu").
|
|
change:
|
|
type: number
|
|
format: double
|
|
description: Percentage change from previous period.
|
|
priceAt:
|
|
type: integer
|
|
format: int64
|
|
description: 'Price date, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
|
|
required:
|
|
- commodity
|
|
description: EnergyPrice represents a current energy commodity price from EIA.
|
|
GetMacroSignalsRequest:
|
|
type: object
|
|
description: GetMacroSignalsRequest requests the current macro signal dashboard.
|
|
GetMacroSignalsResponse:
|
|
type: object
|
|
properties:
|
|
timestamp:
|
|
type: string
|
|
description: ISO 8601 timestamp of computation.
|
|
verdict:
|
|
type: string
|
|
description: 'Overall verdict: "BUY", "CASH", or "UNKNOWN".'
|
|
bullishCount:
|
|
type: integer
|
|
format: int32
|
|
description: Number of bullish signals.
|
|
totalCount:
|
|
type: integer
|
|
format: int32
|
|
description: Total number of evaluated signals (excluding UNKNOWN).
|
|
signals:
|
|
$ref: '#/components/schemas/MacroSignals'
|
|
meta:
|
|
$ref: '#/components/schemas/MacroMeta'
|
|
unavailable:
|
|
type: boolean
|
|
description: True when upstream data is unavailable (fallback result).
|
|
description: GetMacroSignalsResponse contains the full macro signal dashboard with 7 signals and verdict.
|
|
MacroSignals:
|
|
type: object
|
|
properties:
|
|
liquidity:
|
|
$ref: '#/components/schemas/LiquiditySignal'
|
|
flowStructure:
|
|
$ref: '#/components/schemas/FlowStructureSignal'
|
|
macroRegime:
|
|
$ref: '#/components/schemas/MacroRegimeSignal'
|
|
technicalTrend:
|
|
$ref: '#/components/schemas/TechnicalTrendSignal'
|
|
hashRate:
|
|
$ref: '#/components/schemas/HashRateSignal'
|
|
priceMomentum:
|
|
$ref: '#/components/schemas/PriceMomentumSignal'
|
|
fearGreed:
|
|
$ref: '#/components/schemas/FearGreedSignal'
|
|
description: MacroSignals contains all 7 individual signal computations.
|
|
LiquiditySignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"SQUEEZE", "NORMAL", or "UNKNOWN".'
|
|
value:
|
|
type: number
|
|
format: double
|
|
description: JPY 30d ROC percentage, absent if unavailable.
|
|
sparkline:
|
|
type: array
|
|
items:
|
|
type: number
|
|
format: double
|
|
description: Last 30 JPY close prices.
|
|
description: LiquiditySignal tracks JPY 30d rate of change as a liquidity proxy.
|
|
FlowStructureSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"PASSIVE GAP", "ALIGNED", or "UNKNOWN".'
|
|
btcReturn5:
|
|
type: number
|
|
format: double
|
|
description: BTC 5-day return percentage.
|
|
qqqReturn5:
|
|
type: number
|
|
format: double
|
|
description: QQQ 5-day return percentage.
|
|
description: FlowStructureSignal compares BTC vs QQQ 5-day returns.
|
|
MacroRegimeSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"RISK-ON", "DEFENSIVE", or "UNKNOWN".'
|
|
qqqRoc20:
|
|
type: number
|
|
format: double
|
|
description: QQQ 20d ROC percentage.
|
|
xlpRoc20:
|
|
type: number
|
|
format: double
|
|
description: XLP 20d ROC percentage.
|
|
description: MacroRegimeSignal compares QQQ vs XLP 20-day rate of change.
|
|
TechnicalTrendSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"BULLISH", "BEARISH", "NEUTRAL", or "UNKNOWN".'
|
|
btcPrice:
|
|
type: number
|
|
format: double
|
|
description: Current BTC price.
|
|
sma50:
|
|
type: number
|
|
format: double
|
|
description: 50-day simple moving average.
|
|
sma200:
|
|
type: number
|
|
format: double
|
|
description: 200-day simple moving average.
|
|
vwap30d:
|
|
type: number
|
|
format: double
|
|
description: 30-day volume-weighted average price.
|
|
mayerMultiple:
|
|
type: number
|
|
format: double
|
|
description: Mayer multiple (BTC price / SMA200).
|
|
sparkline:
|
|
type: array
|
|
items:
|
|
type: number
|
|
format: double
|
|
description: Last 30 BTC close prices.
|
|
description: TechnicalTrendSignal evaluates BTC price vs moving averages and VWAP.
|
|
HashRateSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"GROWING", "DECLINING", "STABLE", or "UNKNOWN".'
|
|
change30d:
|
|
type: number
|
|
format: double
|
|
description: Hash rate change over 30 days as percentage.
|
|
description: HashRateSignal tracks Bitcoin hash rate momentum.
|
|
PriceMomentumSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: '"STRONG", "MODERATE", "WEAK", or "UNKNOWN".'
|
|
description: PriceMomentumSignal uses the Mayer Multiple (price/SMA200) as a market-adaptive signal.
|
|
FearGreedSignal:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
description: Classification label (e.g., "Extreme Fear", "Greed").
|
|
value:
|
|
type: integer
|
|
format: int32
|
|
description: Current index value (0-100).
|
|
history:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/FearGreedHistoryEntry'
|
|
description: FearGreedSignal tracks the Crypto Fear & Greed index.
|
|
FearGreedHistoryEntry:
|
|
type: object
|
|
properties:
|
|
value:
|
|
type: integer
|
|
maximum: 100
|
|
minimum: 0
|
|
format: int32
|
|
description: Index value (0-100).
|
|
date:
|
|
type: string
|
|
description: Date string (YYYY-MM-DD).
|
|
description: FearGreedHistoryEntry is a single day's Fear & Greed index reading.
|
|
MacroMeta:
|
|
type: object
|
|
properties:
|
|
qqqSparkline:
|
|
type: array
|
|
items:
|
|
type: number
|
|
format: double
|
|
description: Last 30 QQQ close prices for sparkline.
|
|
description: MacroMeta contains supplementary chart data.
|
|
GetEnergyCapacityRequest:
|
|
type: object
|
|
properties:
|
|
energySources:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: |-
|
|
Energy source codes to query (e.g., "SUN", "WND", "COL").
|
|
Empty returns all tracked sources (SUN, WND, COL).
|
|
years:
|
|
type: integer
|
|
format: int32
|
|
description: Number of years of historical data. Default 20 if not set.
|
|
GetEnergyCapacityResponse:
|
|
type: object
|
|
properties:
|
|
series:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EnergyCapacitySeries'
|
|
EnergyCapacitySeries:
|
|
type: object
|
|
properties:
|
|
energySource:
|
|
type: string
|
|
name:
|
|
type: string
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EnergyCapacityYear'
|
|
EnergyCapacityYear:
|
|
type: object
|
|
properties:
|
|
year:
|
|
type: integer
|
|
format: int32
|
|
capacityMw:
|
|
type: number
|
|
format: double
|
|
GetBisPolicyRatesRequest:
|
|
type: object
|
|
description: GetBisPolicyRatesRequest requests central bank policy rates.
|
|
GetBisPolicyRatesResponse:
|
|
type: object
|
|
properties:
|
|
rates:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BisPolicyRate'
|
|
description: GetBisPolicyRatesResponse contains BIS policy rate data.
|
|
BisPolicyRate:
|
|
type: object
|
|
properties:
|
|
countryCode:
|
|
type: string
|
|
description: ISO 2-letter country code (US, GB, JP, etc.)
|
|
countryName:
|
|
type: string
|
|
description: Country or region name.
|
|
rate:
|
|
type: number
|
|
format: double
|
|
description: Current policy rate percentage.
|
|
previousRate:
|
|
type: number
|
|
format: double
|
|
description: Previous period rate percentage.
|
|
date:
|
|
type: string
|
|
description: Date as YYYY-MM.
|
|
centralBank:
|
|
type: string
|
|
description: Central bank name (e.g. "Federal Reserve").
|
|
description: BisPolicyRate represents a central bank policy rate from BIS.
|
|
GetBisExchangeRatesRequest:
|
|
type: object
|
|
description: GetBisExchangeRatesRequest requests effective exchange rates.
|
|
GetBisExchangeRatesResponse:
|
|
type: object
|
|
properties:
|
|
rates:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BisExchangeRate'
|
|
description: GetBisExchangeRatesResponse contains BIS effective exchange rate data.
|
|
BisExchangeRate:
|
|
type: object
|
|
properties:
|
|
countryCode:
|
|
type: string
|
|
description: ISO 2-letter country code.
|
|
countryName:
|
|
type: string
|
|
description: Country or region name.
|
|
realEer:
|
|
type: number
|
|
format: double
|
|
description: Real effective exchange rate index.
|
|
nominalEer:
|
|
type: number
|
|
format: double
|
|
description: Nominal effective exchange rate index.
|
|
realChange:
|
|
type: number
|
|
format: double
|
|
description: Percentage change from previous period (real).
|
|
date:
|
|
type: string
|
|
description: Date as YYYY-MM.
|
|
description: BisExchangeRate represents effective exchange rate indices from BIS.
|
|
GetBisCreditRequest:
|
|
type: object
|
|
description: GetBisCreditRequest requests credit-to-GDP ratio data.
|
|
GetBisCreditResponse:
|
|
type: object
|
|
properties:
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BisCreditToGdp'
|
|
description: GetBisCreditResponse contains BIS credit-to-GDP data.
|
|
BisCreditToGdp:
|
|
type: object
|
|
properties:
|
|
countryCode:
|
|
type: string
|
|
description: ISO 2-letter country code.
|
|
countryName:
|
|
type: string
|
|
description: Country or region name.
|
|
creditGdpRatio:
|
|
type: number
|
|
format: double
|
|
description: Total credit as percentage of GDP.
|
|
previousRatio:
|
|
type: number
|
|
format: double
|
|
description: Previous quarter ratio.
|
|
date:
|
|
type: string
|
|
description: Date as YYYY-QN.
|
|
description: BisCreditToGdp represents total credit as percentage of GDP from BIS.
|
|
GetFredSeriesBatchRequest:
|
|
type: object
|
|
properties:
|
|
seriesIds:
|
|
type: array
|
|
items:
|
|
type: string
|
|
maxItems: 10
|
|
minItems: 1
|
|
description: FRED series IDs (e.g., "WALCL", "FEDFUNDS"). Max 10.
|
|
maxItems: 10
|
|
minItems: 1
|
|
limit:
|
|
type: integer
|
|
format: int32
|
|
description: Maximum number of observations per series. Defaults to 120.
|
|
description: GetFredSeriesBatchRequest looks up multiple FRED series in a single call.
|
|
GetFredSeriesBatchResponse:
|
|
type: object
|
|
properties:
|
|
results:
|
|
type: object
|
|
additionalProperties:
|
|
$ref: '#/components/schemas/FredSeries'
|
|
description: Map of series_id -> FRED series for found series.
|
|
fetched:
|
|
type: integer
|
|
format: int32
|
|
description: Number of series successfully fetched.
|
|
requested:
|
|
type: integer
|
|
format: int32
|
|
description: Number of series requested.
|
|
description: GetFredSeriesBatchResponse contains the requested FRED series data.
|
|
ResultsEntry:
|
|
type: object
|
|
properties:
|
|
key:
|
|
type: string
|
|
value:
|
|
$ref: '#/components/schemas/FredSeries'
|
|
ListGroceryBasketPricesRequest:
|
|
type: object
|
|
ListGroceryBasketPricesResponse:
|
|
type: object
|
|
properties:
|
|
countries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/CountryBasket'
|
|
fetchedAt:
|
|
type: string
|
|
cheapestCountry:
|
|
type: string
|
|
mostExpensiveCountry:
|
|
type: string
|
|
upstreamUnavailable:
|
|
type: boolean
|
|
CountryBasket:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
name:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
flag:
|
|
type: string
|
|
totalUsd:
|
|
type: number
|
|
format: double
|
|
fxRate:
|
|
type: number
|
|
format: double
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/GroceryItemPrice'
|
|
GroceryItemPrice:
|
|
type: object
|
|
properties:
|
|
itemId:
|
|
type: string
|
|
itemName:
|
|
type: string
|
|
unit:
|
|
type: string
|
|
localPrice:
|
|
type: number
|
|
format: double
|
|
usdPrice:
|
|
type: number
|
|
format: double
|
|
currency:
|
|
type: string
|
|
sourceSite:
|
|
type: string
|
|
available:
|
|
type: boolean
|
|
ListBigMacPricesRequest:
|
|
type: object
|
|
ListBigMacPricesResponse:
|
|
type: object
|
|
properties:
|
|
countries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BigMacCountryPrice'
|
|
fetchedAt:
|
|
type: string
|
|
cheapestCountry:
|
|
type: string
|
|
mostExpensiveCountry:
|
|
type: string
|
|
BigMacCountryPrice:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
name:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
flag:
|
|
type: string
|
|
localPrice:
|
|
type: number
|
|
format: double
|
|
usdPrice:
|
|
type: number
|
|
format: double
|
|
fxRate:
|
|
type: number
|
|
format: double
|
|
sourceSite:
|
|
type: string
|
|
available:
|
|
type: boolean
|
|
GetNationalDebtRequest:
|
|
type: object
|
|
description: GetNationalDebtRequest requests national debt data for all countries.
|
|
GetNationalDebtResponse:
|
|
type: object
|
|
properties:
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/NationalDebtEntry'
|
|
seededAt:
|
|
type: string
|
|
description: ISO 8601 timestamp when seed data was written.
|
|
unavailable:
|
|
type: boolean
|
|
description: True when upstream data is unavailable (fallback result).
|
|
description: GetNationalDebtResponse wraps the full list of national debt entries.
|
|
NationalDebtEntry:
|
|
type: object
|
|
properties:
|
|
iso3:
|
|
type: string
|
|
description: ISO3 country code (e.g. "USA").
|
|
debtUsd:
|
|
type: number
|
|
format: double
|
|
description: Total debt in USD at baseline_ts.
|
|
gdpUsd:
|
|
type: number
|
|
format: double
|
|
description: GDP in USD (nominal, latest year).
|
|
debtToGdp:
|
|
type: number
|
|
format: double
|
|
description: Debt as % of GDP.
|
|
annualGrowth:
|
|
type: number
|
|
format: double
|
|
description: Year-over-year debt growth percent (2023->2024).
|
|
perSecondRate:
|
|
type: number
|
|
format: double
|
|
description: Deficit-derived accrual in USD per second.
|
|
perDayRate:
|
|
type: number
|
|
format: double
|
|
description: Deficit-derived accrual in USD per day.
|
|
baselineTs:
|
|
type: string
|
|
format: int64
|
|
description: UTC ms timestamp anchoring the debt_usd figure (2024-01-01T00:00:00Z).
|
|
source:
|
|
type: string
|
|
description: Human-readable source string.
|
|
description: NationalDebtEntry holds debt data for a single country.
|