CI / Test & Type-Check (push) Canceled after 0s
Snapshot of in-progress module work across multiple slices: - Dealer Flow: dealerExposureEngine, dealerMapService, dealerMapExplain, dealerMapIntegrity, dealerMapReplay, dealerStudyEngine, hanStyleLevels - Mirror Portfolio (M21): fundRepository, captureIngest, mirrorAlertProducers, fund holdings strip, live book, position capture ingest - Options: BSM, NormalizedOptionSurface types, OptionsChainRouter, ConvexityGate, option legs panel - Alert producers: vixLevel, rotation, thesis, unlock, portfolioRisk, mirror (fund_capture, fund_13f, mirror_diff) - FINRA short interest adapter + queue integration - SEC company tickers adapter + ingest (symbol search index seed) - Vendor gate (rate-limit-first data plane, ADR-0009) - CUSIP registry, reverse 13F refresh, stock float service - LRU cache, portfolio backtest engine - Frontend: dealer-flow, funds, journal, lab, monitor, plan, portfolio, reports, screener, strategies, theses, guided-start, exits, more pages - Volume profile, workspace profile, visibility-aware poll - ADRs 0010 (mirror math not advice), 0011 (symbol search index) - VENDOR_INTEGRATIONS.md, END_USER_TEST.md - .gitignore: exclude DBs, .DS_Store, local config, agent scratch
78 lines
3.0 KiB
TypeScript
78 lines
3.0 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
/**
|
|
* CLI: backfill stock_float table with sharesOutstanding / floatShares from Yahoo Finance.
|
|
*
|
|
* Usage (from app/server):
|
|
* npx tsx scripts/backfill-stock-float.ts
|
|
* npx tsx scripts/backfill-stock-float.ts --symbol IREN # single symbol
|
|
* npx tsx scripts/backfill-stock-float.ts --all # all symbols in DB
|
|
*
|
|
* Reads tracked fund positions and 13F filings to find symbols needing float data.
|
|
* Respects vendor rate limits; skips entries fetched within the last 24h.
|
|
*/
|
|
|
|
import { DatabaseSync } from 'node:sqlite';
|
|
import { resolve, dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { fetchAndPersistFloat, refreshAllStockFloats } from '../src/services/stockFloatService.ts';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const SERVER_ROOT = join(__dirname, '..');
|
|
const DB_PATH = resolve(SERVER_ROOT, 'data', 'investor-flow.db');
|
|
|
|
function arg(name: string): string | undefined {
|
|
const i = process.argv.indexOf(name);
|
|
if (i < 0 || i + 1 >= process.argv.length) return undefined;
|
|
return process.argv[i + 1];
|
|
}
|
|
|
|
async function main() {
|
|
const symbolArg = arg('--symbol');
|
|
const forceFlag = arg('--force') === 'true' || arg('--force') === '';
|
|
|
|
console.log('Backfilling stock float data from Yahoo Finance...');
|
|
console.log(`DB: ${DB_PATH}`);
|
|
if (symbolArg) console.log(`Symbol filter: ${symbolArg.toUpperCase()}`);
|
|
if (forceFlag && !symbolArg) console.log('Mode: force refresh all symbols');
|
|
|
|
const db = new DatabaseSync(DB_PATH);
|
|
|
|
try {
|
|
let result;
|
|
if (symbolArg) {
|
|
// Single symbol backfill.
|
|
console.log(`Fetching float for ${symbolArg.toUpperCase()}...`);
|
|
await fetchAndPersistFloat(db, symbolArg.toUpperCase());
|
|
const row = db.prepare(
|
|
`SELECT shares_outstanding, float_shares FROM stock_float WHERE symbol = ? ORDER BY as_of DESC LIMIT 1`
|
|
).get(symbolArg.toUpperCase()) as { shares_outstanding: number | null; float_shares: number | null } | undefined;
|
|
|
|
console.log(` sharesOutstanding: ${row?.shares_outstanding ?? 'null'}`);
|
|
console.log(` floatShares: ${row?.float_shares ?? 'null'}`);
|
|
result = { refreshed: 1, skipped: 0, errors: [] };
|
|
} else if (forceFlag) {
|
|
// Force refresh all symbols regardless of TTL.
|
|
result = await refreshAllStockFloats(db, { forceRefresh: true });
|
|
} else {
|
|
// Default: refresh stale entries only.
|
|
result = await refreshAllStockFloats(db);
|
|
}
|
|
|
|
console.log('\nDone.');
|
|
console.log(` Refreshed: ${result.refreshed}`);
|
|
console.log(` Skipped (fresh): ${result.skipped}`);
|
|
if (result.errors.length > 0) {
|
|
console.log(`\nErrors (${result.errors.length}):`);
|
|
for (const err of result.errors.slice(0, 10)) console.log(` - ${err}`);
|
|
if (result.errors.length > 10) console.log(` ... and ${result.errors.length - 10} more`);
|
|
}
|
|
} finally {
|
|
db.close();
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('Backfill failed:', err);
|
|
process.exit(1);
|
|
});
|