SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%
2.5 KB · 59 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import { extract, renderResult, shrink } from '../src/format.js';3import { rateFromHeaders } from '../src/client.js';4import { bars } from './helpers.js';56const rate = rateFromHeaders(new Headers({ 'x-ratelimit-remaining-requests': '7', 'x-ratelimit-limit-requests': '30' }));78describe('extract', () => {9  it('understands the v1 envelope', () => {10    const e = extract({ count: 2, data: [{ a: 1 }, { a: 2 }] });11    expect(e.rows).toHaveLength(2);12    expect(e.meta.count).toBe(2);13  });14  it('understands the v2 envelope and keeps meta', () => {15    const e = extract({ data: [{ a: 1 }], meta: { count: 1, next_cursor: 'abc', roll_dates: ['2025-03-14'] } });16    expect(e.rows).toHaveLength(1);17    expect(e.meta.next_cursor).toBe('abc');18  });19  it('keeps non-tabular payloads in rest', () => {20    const e = extract({ asset: 'stock', count: 3, tickers: ['A', 'B', 'C'] });21    expect(e.rows).toBeNull();22    expect(e.rest.tickers).toEqual(['A', 'B', 'C']);23  });24});2526describe('renderResult', () => {27  it('renders small tables in full as columns/rows', () => {28    const text = renderResult({ status: 200, url: 'u', body: { count: 3, data: bars(3) }, rate, ms: 1 }, { title: 'T' });29    expect(text.startsWith('T\n')).toBe(true);30    const json = JSON.parse(text.split('\n')[1]);31    expect(json.row_count).toBe(3);32    expect(json.columns).toEqual(['ticker', 'datetime', 'open', 'high', 'low', 'close', 'volume']);33    expect(json.rows).toHaveLength(3);34    expect(json.truncated).toBeUndefined();35    expect(text).toContain('Rate limit: requests 7/30 left');36  });3738  it('summarises large tables with head/tail, numeric ranges and a hint', () => {39    const text = renderResult({ status: 200, url: 'u', body: { data: bars(600), meta: { count: 600, next_cursor: 'n' } }, rate, ms: 1 });40    const json = JSON.parse(text.split('\n')[0]);41    expect(json.truncated).toBe(true);42    expect(json.row_count).toBe(600);43    expect(json.first_rows).toHaveLength(15);44    expect(json.last_rows).toHaveLength(15);45    expect(json.numeric_summary.close.min).toBe(100.5);46    expect(json.numeric_summary.close.max).toBe(699.5);47    expect(json.hint).toContain('Narrow');48    expect(json.next_cursor).toBe('n');49    expect(text.length).toBeLessThan(6000);50  });5152  it('shrinks long arrays inside non-tabular payloads', () => {53    const s = shrink({ tickers: Array.from({ length: 1000 }, (_, i) => `T${i}`) }, 100) as any;54    expect(s.tickers.count).toBe(1000);55    expect(s.tickers.first).toHaveLength(100);56    expect(s.tickers.truncated).toBe(true);57  });58});59