Files
Toolbox/src/server/market_skills/fred_curl.js
T

53 lines
2.1 KiB
JavaScript

/**
* FRED (Federal Reserve Economic Data) CSV fetcher via curl.exe
*
* Why curl.exe instead of axios:
* Node.js axios → FRED's Akamai CDN times out on SP500, DGS2, DGS10 series.
* curl.exe → same URL returns data in ~1s.
*
* Why date range params (cosd/coed):
* Full DGS2/DGS10 datasets (daily from 1962) are huge → Akamai times out.
* Limiting to recent years solves this. All calculations only need ≤3 years.
*
* Root cause: Akamai CDN differentiates by TLS fingerprint AND URL pattern.
*/
const { execFile } = require('child_process')
const FRED_BASE = 'https://fred.stlouisfed.org/graph/fredgraph.csv'
/**
* Fetch FRED CSV data using curl.exe with a date range limit
* @param {string} seriesId - FRED series ID (e.g. 'SP500', 'FEDFUNDS')
* @param {object} [opts]
* @param {number} [opts.timeout=20] - curl --max-time seconds
* @param {number} [opts.lookbackYears=3] - years to look back from today
* @param {string} [opts.coed] - custom observation end date YYYY-MM-DD (default today)
* @param {string} [opts.cosd] - custom observation start date YYYY-MM-DD (default coed - lookbackYears)
* @returns {Promise<string>} raw CSV text
*/
const fetchFredCurl = (seriesId, opts = {}) => {
const timeout = opts.timeout || 20
const lookbackYears = opts.lookbackYears || 3
const now = new Date()
const coed = opts.coed || now.toISOString().slice(0, 10)
const cosd = opts.cosd || (new Date(now.getTime() - lookbackYears * 365 * 24 * 60 * 60 * 1000)).toISOString().slice(0, 10)
const url = `${FRED_BASE}?id=${encodeURIComponent(seriesId)}&cosd=${cosd}&coed=${coed}`
return new Promise((resolve, reject) => {
execFile('curl.exe', ['-s', '--max-time', String(timeout), url], {
encoding: 'utf8',
timeout: (timeout + 10) * 1000,
maxBuffer: 10 * 1024 * 1024,
windowsHide: true
}, (err, stdout, stderr) => {
if (err) {
const msg = stderr ? stderr.trim() : err.message
return reject(new Error(`curl failed for ${seriesId}: ${msg}`))
}
resolve(stdout)
})
})
}
module.exports = { fetchFredCurl }