import type { StockDatabase, StockKey } from "./stockdb.interfaces.js"; import type { Aggregate } from "./interfaces.js"; import { clickhouse, query } from "./lib/clickhouse.js"; function makeStockDatabase(): StockDatabase { const stockDatabase: Omit = { getKeys: async ({ date }) => { return ( await query(` SELECT DISTINCT symbol FROM stock_aggregates WHERE toDate(tsStart) = '${date}' `) ).map(({ symbol }) => symbol); }, getAggregates: async ({ key: symbol, date }) => { return ( await query, "key">>(` SELECT toUnixTimestamp(tsStart) as tsStart, open, close, high, low FROM stock_aggregates WHERE symbol = '${symbol}' AND toDate(tsStart) = '${date}' ORDER BY tsStart ASC `) ).map((aggregate) => ({ ...aggregate, tsStart: aggregate.tsStart * 1000, // unfortunately, `toUnixTimestamp` only returns second-precision })); }, insertAggregates: async (aggregates) => { // stock existence is taken care of by clickhouse materialized view await clickhouse.insert({ table: "stock_aggregates", values: aggregates.map(({ key, tsStart, open, close, high, low }) => ({ symbol: key, tsStart, open, close, high, low, })), }); }, getClosingPrice: async ({ key }) => { // no-op: not used since stocks don't have a "closing" price, unlike options. return 0; }, }; return { ...stockDatabase, getSymbols: stockDatabase.getKeys, }; } export const stockDatabase: StockDatabase = makeStockDatabase();