@mostlyrightmd/markets 0.1.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/trades/kalshi-client.ts","../../src/trades/types.ts","../../src/trades/kalshi.ts","../../src/trades/polymarket.ts","../../src/trades/cache.ts"],"sourcesContent":["// Phase 9 — Kalshi public REST client (TS port of `_kalshi_client.py`).\n//\n// Read-only public Kalshi market data at\n// https://api.elections.kalshi.com/trade-api/v2. No auth. 0.1s polite\n// floor matches Kalshi's documented 10 req/sec ceiling. Reuses the\n// fetchFn-injection pattern from packages-ts/markets/src/polymarket/\n// client.ts so vitest can mock the HTTP layer.\n\nimport { fetchWithRetry } from \"@mostlyrightmd/core\";\n\nexport const KALSHI_API_BASE = \"https://api.elections.kalshi.com/trade-api/v2\";\n\nconst DEFAULT_SLEEP_BETWEEN_MS = 100; // 0.1 s\nconst DEFAULT_USER_AGENT = \"mostlyright-ts/0.2.0 (+https://github.com/helloiamvu/tradewinds)\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_TRADES_PAGE_LIMIT = 1000;\nconst DEFAULT_MAX_TRADES_PAGES = 10_000;\n\nexport interface KalshiClientOptions {\n /** Politeness sleep between requests in ms. Default 100 (0.1 s). 0 to skip. */\n readonly sleepBetweenMs?: number;\n /** AbortSignal for the whole call. */\n readonly signal?: AbortSignal;\n /** Override fetch for tests. Defaults to global fetch. */\n readonly fetchFn?: typeof fetch;\n /** Per-attempt timeout. Default 30 000 ms. */\n readonly timeoutMs?: number;\n}\n\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n const onAbort = () => {\n cleanup();\n reject(signal?.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n function cleanup() {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n if (signal) {\n if (signal.aborted) {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", onAbort);\n }\n });\n}\n\nfunction buildUrl(\n path: string,\n params?: Record<string, string | number | boolean | null | undefined>,\n): string {\n const url = new URL(`${KALSHI_API_BASE}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n}\n\nasync function getJson(\n path: string,\n params: Record<string, string | number | boolean | null | undefined> | undefined,\n opts: KalshiClientOptions,\n): Promise<unknown> {\n const url = buildUrl(path, params);\n const headers: Record<string, string> = {\n \"User-Agent\": DEFAULT_USER_AGENT,\n Accept: \"application/json\",\n };\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n let resp: Response;\n if (opts.fetchFn !== undefined) {\n // Tests inject `fetchFn` — bypass fetchWithRetry to keep mocks simple.\n // The injected fn is responsible for any retry / timeout behavior the\n // test wants to exercise.\n const init: RequestInit = { method: \"GET\", headers };\n if (opts.signal) init.signal = opts.signal;\n resp = await opts.fetchFn(url, init);\n if (!resp.ok) {\n throw new Error(`kalshi GET ${url} failed: HTTP ${resp.status}`);\n }\n } else {\n const retryOpts: Parameters<typeof fetchWithRetry>[1] = {\n method: \"GET\",\n headers,\n timeoutMs,\n };\n if (opts.signal) retryOpts.signal = opts.signal;\n resp = await fetchWithRetry(url, retryOpts);\n }\n const json = await resp.json();\n const sleepMs = opts.sleepBetweenMs ?? DEFAULT_SLEEP_BETWEEN_MS;\n if (sleepMs > 0) {\n await sleep(sleepMs, opts.signal);\n }\n return json;\n}\n\n// Real Kalshi API (post-March-2026 migration) returns FixedPointDollars\n// strings (`_dollars` suffix) for prices and FixedPoint integer strings\n// (`_fp` suffix) for sizes. Legacy unsuffixed fields accepted as a\n// fallback for older endpoints / recorded fixtures. Field types are\n// `string | number` to cover both wire shapes.\nexport interface RawKalshiCandle {\n readonly end_period_ts?: number;\n readonly price?: {\n // New wire format: dollar strings like \"0.5600\".\n readonly open_dollars?: string;\n readonly high_dollars?: string;\n readonly low_dollars?: string;\n readonly close_dollars?: string;\n // Legacy integer cents.\n readonly open?: number | string;\n readonly high?: number | string;\n readonly low?: number | string;\n readonly close?: number | string;\n };\n // New wire format: FixedPoint integer strings.\n readonly volume_fp?: string;\n readonly open_interest_fp?: string;\n // Legacy ints.\n readonly volume?: number | string;\n readonly open_interest?: number | string;\n}\n\nexport interface RawKalshiTrade {\n readonly trade_id?: string;\n readonly created_time?: number | string;\n // New wire format: dollar strings + integer strings.\n readonly yes_price_dollars?: string;\n readonly no_price_dollars?: string;\n readonly count_fp?: string;\n readonly taker_outcome_side?: \"yes\" | \"no\";\n // Legacy unsuffixed.\n readonly yes_price?: number | string;\n readonly no_price?: number | string;\n readonly count?: number | string;\n readonly taker_side?: \"yes\" | \"no\";\n}\n\n// Orderbook level: real wire format is [price_dollar_string, count_fp_string];\n// legacy is [price_int, count_int]. Dict form tolerated for backward compat\n// with hand-authored fixtures.\ntype KalshiOrderLevel =\n | readonly [string | number, string | number]\n | {\n readonly price?: string | number;\n readonly size?: string | number;\n readonly contracts?: string | number;\n };\n\nexport interface RawKalshiOrderbook {\n // New wire format: orderbook_fp with yes_dollars / no_dollars arrays.\n readonly orderbook_fp?: {\n readonly yes_dollars?: ReadonlyArray<KalshiOrderLevel>;\n readonly no_dollars?: ReadonlyArray<KalshiOrderLevel>;\n };\n // Legacy: orderbook with yes / no arrays.\n readonly orderbook?: {\n readonly yes?: ReadonlyArray<KalshiOrderLevel>;\n readonly no?: ReadonlyArray<KalshiOrderLevel>;\n };\n}\n\nexport async function fetchCandlesticks(\n ticker: string,\n args: {\n startTs: number;\n endTs: number;\n periodIntervalMinutes: number;\n },\n opts: KalshiClientOptions = {},\n): Promise<ReadonlyArray<RawKalshiCandle>> {\n if (!ticker.includes(\"-\")) {\n throw new Error(\n `kalshi ticker must contain '-' to derive series prefix; got ${JSON.stringify(ticker)}`,\n );\n }\n const series = ticker.split(\"-\", 1)[0];\n const path = `/series/${series}/markets/${ticker}/candlesticks`;\n const payload = (await getJson(\n path,\n {\n start_ts: args.startTs,\n end_ts: args.endTs,\n period_interval: args.periodIntervalMinutes,\n },\n opts,\n )) as { candlesticks?: ReadonlyArray<RawKalshiCandle> } | null;\n return payload?.candlesticks ?? [];\n}\n\nexport interface FetchTradesArgs {\n readonly minTs?: number;\n readonly maxTs?: number;\n readonly limit?: number;\n readonly maxPages?: number;\n}\n\nexport async function fetchTrades(\n ticker: string,\n args: FetchTradesArgs = {},\n opts: KalshiClientOptions = {},\n): Promise<ReadonlyArray<RawKalshiTrade>> {\n const limit = args.limit ?? DEFAULT_TRADES_PAGE_LIMIT;\n const maxPages = args.maxPages ?? DEFAULT_MAX_TRADES_PAGES;\n const out: RawKalshiTrade[] = [];\n let cursor: string | undefined;\n let pages = 0;\n while (true) {\n const params: Record<string, string | number | boolean | null | undefined> = {\n ticker,\n limit,\n };\n if (args.minTs !== undefined) params.min_ts = args.minTs;\n if (args.maxTs !== undefined) params.max_ts = args.maxTs;\n if (cursor) params.cursor = cursor;\n const payload = (await getJson(\"/markets/trades\", params, opts)) as {\n trades?: ReadonlyArray<RawKalshiTrade>;\n cursor?: string;\n } | null;\n const trades = payload?.trades ?? [];\n if (trades.length > 0) out.push(...trades);\n cursor = payload?.cursor && payload.cursor.length > 0 ? payload.cursor : undefined;\n pages += 1;\n if (!cursor || trades.length === 0) break;\n if (pages >= maxPages) {\n throw new Error(\n `kalshi fetchTrades(${ticker}) exceeded maxPages=${maxPages}; narrow the window or raise the cap`,\n );\n }\n }\n return out;\n}\n\nexport async function fetchOrderbook(\n ticker: string,\n args: { depth?: number } = {},\n opts: KalshiClientOptions = {},\n): Promise<RawKalshiOrderbook> {\n const depth = args.depth ?? 50;\n if (depth < 1 || depth > 1000) {\n throw new Error(`depth out of range [1, 1000]: ${depth}`);\n }\n const path = `/markets/${ticker}/orderbook`;\n const payload = (await getJson(path, { depth }, opts)) as RawKalshiOrderbook | null;\n if (!payload || typeof payload !== \"object\") {\n throw new Error(`kalshi orderbook for ${ticker}: bad payload`);\n }\n return payload;\n}\n","// Phase 9 — shared row + result types for the trades surface.\n//\n// Mirrors the Python DataFrames in `mostlyright.markets.{kalshi_trades,\n// polymarket_trades}` row-for-row. The TS surface returns plain JS\n// objects (frozen `readonly` arrays) since `@mostlyrightmd/markets` does\n// not depend on a DataFrame library.\n\n/** Source string carried per row — load-bearing invariant for cross-frame joins.\n *\n * `polymarket.gamma` covers /events + /events/{id} (snapshot endpoint);\n * `polymarket.clob` covers /prices-history (history endpoint, on the CLOB\n * host — distinct from Gamma per architect iter-1 CRITICAL).\n */\nexport type TradesSource = \"kalshi\" | \"polymarket.gamma\" | \"polymarket.clob\";\n\nexport interface KalshiCandleRow {\n /** Bucket-end timestamp as ISO 8601 UTC string. */\n readonly ts: string | null;\n readonly open: number | null;\n readonly high: number | null;\n readonly low: number | null;\n readonly close: number | null;\n readonly volume: number | null;\n readonly openInterest: number | null;\n readonly source: \"kalshi\";\n}\n\nexport interface KalshiFillRow {\n readonly tradeId: string | null;\n readonly ts: string | null;\n readonly yesPrice: number | null;\n readonly noPrice: number | null;\n readonly count: number | null;\n readonly takerSide: \"yes\" | \"no\" | null;\n readonly source: \"kalshi\";\n}\n\nexport interface KalshiOrderbookRow {\n readonly side: \"yes\" | \"no\";\n readonly price: number | null;\n readonly size: number | null;\n readonly source: \"kalshi\";\n}\n\nexport interface PolymarketHistoryRow {\n readonly ts: string | null;\n /** Last-traded price in [0, 1] for the requested CLOB token. */\n readonly price: number | null;\n readonly volume: number | null;\n /** History rows live on the CLOB host (architect iter-1 CRITICAL fix). */\n readonly source: \"polymarket.clob\";\n}\n\nexport interface PolymarketSnapshotRow {\n readonly marketId: string | null;\n readonly outcome: string;\n readonly lastPrice: number | null;\n readonly volume: number | null;\n readonly liquidity: number | null;\n readonly source: \"polymarket.gamma\";\n}\n\n/** Envelope returned by every trades function — rows + metadata. */\nexport interface TradesResult<Row> {\n readonly rows: ReadonlyArray<Row>;\n readonly source: TradesSource;\n readonly retrievedAt: string; // ISO UTC\n /** Snapshot-style results may carry a snapshotAt distinct from retrievedAt. */\n readonly snapshotAt?: string;\n /** Echo of the input ticker / market-id for downstream attribution. */\n readonly ticker?: string;\n readonly marketId?: string;\n readonly eventId?: string;\n readonly interval?: string;\n readonly fidelityMinutes?: number;\n /** CLOB token id for polymarketHistory results (architect iter-1 fix). */\n readonly tokenId?: string;\n}\n\n/** Supported candle intervals — exact union mirrors Python `INTERVALS`. */\nexport const KALSHI_INTERVALS = [\"1m\", \"1h\", \"1d\"] as const;\nexport type KalshiInterval = (typeof KALSHI_INTERVALS)[number];\n","// Phase 9 — Kalshi trades public surface (TRADES-01..03, TS port of\n// packages/markets/src/mostlyright/markets/kalshi_trades.py).\n//\n// Row shapes mirror the Python DataFrames column-for-column. Every row\n// carries `source: \"kalshi\"` so cross-frame joins preserve source\n// identity (the v0.1.0 load-bearing invariant).\n\nimport {\n type KalshiClientOptions,\n type RawKalshiCandle,\n type RawKalshiOrderbook,\n type RawKalshiTrade,\n fetchCandlesticks,\n fetchOrderbook,\n fetchTrades,\n} from \"./kalshi-client.js\";\nimport {\n KALSHI_INTERVALS,\n type KalshiCandleRow,\n type KalshiFillRow,\n type KalshiInterval,\n type KalshiOrderbookRow,\n type TradesResult,\n} from \"./types.js\";\n\nconst SOURCE = \"kalshi\" as const;\n\nconst INTERVAL_TO_MINUTES: Record<KalshiInterval, number> = {\n \"1m\": 1,\n \"1h\": 60,\n \"1d\": 1440,\n};\n\nexport interface KalshiCandlesArgs {\n readonly interval: KalshiInterval;\n readonly from: Date;\n readonly to: Date;\n}\n\nexport interface KalshiFillsArgs {\n readonly since?: Date;\n readonly until?: Date;\n readonly maxPages?: number;\n}\n\nexport interface KalshiOrderbookArgs {\n readonly depth?: number;\n}\n\nfunction validateDate(d: Date, name: string): void {\n if (!(d instanceof Date) || Number.isNaN(d.getTime())) {\n throw new TypeError(`${name} must be a valid Date; got ${String(d)}`);\n }\n}\n\nfunction toIsoOrNull(epochSeconds: unknown): string | null {\n if (typeof epochSeconds === \"number\" && Number.isFinite(epochSeconds)) {\n return new Date(epochSeconds * 1000).toISOString();\n }\n return null;\n}\n\nfunction stringTsToIso(value: unknown): string | null {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return toIsoOrNull(value);\n }\n if (typeof value === \"string\") {\n const parsed = Date.parse(value);\n if (!Number.isNaN(parsed)) {\n return new Date(parsed).toISOString();\n }\n }\n return null;\n}\n\nfunction maybeNumber(v: unknown): number | null {\n if (v === null || v === undefined) return null;\n const n = typeof v === \"string\" ? Number(v) : (v as number);\n return typeof n === \"number\" && Number.isFinite(n) ? n : null;\n}\n\nfunction maybeInt(v: unknown): number | null {\n const n = maybeNumber(v);\n if (n === null) return null;\n return Math.trunc(n);\n}\n\n/**\n * Convert a Kalshi FixedPointDollars string (e.g. ``\"0.5600\"``) to cents\n * [0.0–100.0]. Subpenny precision is preserved (`\"0.567\"` → 56.7).\n * Canonical conversion per `packages/core/.../specs/candle.json`:\n * `cents = float(api_string) * 100`. Returns null on unparseable input.\n */\nfunction dollarsToCents(v: unknown): number | null {\n const n = maybeNumber(v);\n if (n === null) return null;\n return n * 100;\n}\n\n/**\n * Parse a Kalshi FixedPoint integer string (e.g. ``\"100\"`` or ``\"100.00\"``)\n * to int. Tolerates trailing-decimal forms; returns null on unparseable.\n */\nfunction fpStringToInt(v: unknown): number | null {\n const n = maybeNumber(v);\n if (n === null) return null;\n return Math.trunc(n);\n}\n\n/**\n * Read either `{base}_dollars` (new wire format, FixedPointDollars string)\n * or legacy unsuffixed `{base}` (integer cents) from a Kalshi payload\n * field and return a value in cents [0.0–100.0].\n */\nfunction pickPrice(d: Record<string, unknown> | undefined, base: string): number | null {\n if (d === undefined) return null;\n const dollarsKey = `${base}_dollars`;\n if (Object.prototype.hasOwnProperty.call(d, dollarsKey)) {\n return dollarsToCents(d[dollarsKey]);\n }\n return maybeNumber(d[base]);\n}\n\n/**\n * Read either `{base}_fp` (new wire format, FixedPoint integer string) or\n * legacy unsuffixed `{base}` (integer) from a Kalshi payload field.\n */\nfunction pickFp(d: Record<string, unknown> | undefined, base: string): number | null {\n if (d === undefined) return null;\n const fpKey = `${base}_fp`;\n if (Object.prototype.hasOwnProperty.call(d, fpKey)) {\n return fpStringToInt(d[fpKey]);\n }\n return maybeInt(d[base]);\n}\n\nexport async function kalshiCandles(\n ticker: string,\n args: KalshiCandlesArgs,\n opts: KalshiClientOptions = {},\n): Promise<TradesResult<KalshiCandleRow>> {\n validateDate(args.from, \"from\");\n validateDate(args.to, \"to\");\n if (args.from.getTime() >= args.to.getTime()) {\n throw new RangeError(\n `from (${args.from.toISOString()}) must be < to (${args.to.toISOString()})`,\n );\n }\n if (!KALSHI_INTERVALS.includes(args.interval)) {\n throw new RangeError(\n `interval must be one of ${JSON.stringify([...KALSHI_INTERVALS])}; got ${JSON.stringify(args.interval)}`,\n );\n }\n const raw = await fetchCandlesticks(\n ticker,\n {\n startTs: Math.trunc(args.from.getTime() / 1000),\n endTs: Math.trunc(args.to.getTime() / 1000),\n periodIntervalMinutes: INTERVAL_TO_MINUTES[args.interval],\n },\n opts,\n );\n // Kalshi API (post-March-2026): FixedPointDollars strings for prices,\n // FixedPoint integer strings for sizes (`_fp` suffix). Legacy unsuffixed\n // names accepted as a fallback. pickPrice converts dollars → cents\n // [0.0, 100.0] per canonical specs/candle.json.\n const rows: KalshiCandleRow[] = raw.map((c: RawKalshiCandle) => {\n const priceObj = c.price as Record<string, unknown> | undefined;\n const top = c as unknown as Record<string, unknown>;\n return {\n ts: toIsoOrNull(c.end_period_ts),\n open: pickPrice(priceObj, \"open\"),\n high: pickPrice(priceObj, \"high\"),\n low: pickPrice(priceObj, \"low\"),\n close: pickPrice(priceObj, \"close\"),\n volume: pickFp(top, \"volume\"),\n openInterest: pickFp(top, \"open_interest\"),\n source: SOURCE,\n };\n });\n return Object.freeze({\n rows: Object.freeze(rows),\n source: SOURCE,\n retrievedAt: new Date().toISOString(),\n ticker,\n interval: args.interval,\n });\n}\n\nexport async function kalshiFills(\n ticker: string,\n args: KalshiFillsArgs = {},\n opts: KalshiClientOptions = {},\n): Promise<TradesResult<KalshiFillRow>> {\n if (args.since !== undefined) validateDate(args.since, \"since\");\n if (args.until !== undefined) validateDate(args.until, \"until\");\n if (\n args.since !== undefined &&\n args.until !== undefined &&\n args.since.getTime() >= args.until.getTime()\n ) {\n throw new RangeError(\n `since (${args.since.toISOString()}) must be < until (${args.until.toISOString()})`,\n );\n }\n // exactOptionalPropertyTypes: omit undefined keys rather than passing them.\n const fetchArgs: { minTs?: number; maxTs?: number; maxPages?: number } = {};\n if (args.since) fetchArgs.minTs = Math.trunc(args.since.getTime() / 1000);\n if (args.until) fetchArgs.maxTs = Math.trunc(args.until.getTime() / 1000);\n if (args.maxPages !== undefined) fetchArgs.maxPages = args.maxPages;\n const raw = await fetchTrades(ticker, fetchArgs, opts);\n // Real Kalshi /markets/trades returns yes_price_dollars / no_price_dollars\n // / count_fp / taker_outcome_side. Legacy unsuffixed accepted as fallback.\n const rows: KalshiFillRow[] = raw.map((t: RawKalshiTrade) => {\n const obj = t as unknown as Record<string, unknown>;\n const takerRaw = (t.taker_outcome_side ?? t.taker_side) as unknown;\n const takerSide: \"yes\" | \"no\" | null =\n takerRaw === \"yes\" || takerRaw === \"no\" ? takerRaw : null;\n return {\n tradeId: t.trade_id ?? null,\n ts: stringTsToIso(t.created_time),\n yesPrice: pickPrice(obj, \"yes_price\"),\n noPrice: pickPrice(obj, \"no_price\"),\n count: pickFp(obj, \"count\"),\n takerSide,\n source: SOURCE,\n };\n });\n return Object.freeze({\n rows: Object.freeze(rows),\n source: SOURCE,\n retrievedAt: new Date().toISOString(),\n ticker,\n });\n}\n\nexport async function kalshiOrderbook(\n ticker: string,\n args: KalshiOrderbookArgs = {},\n opts: KalshiClientOptions = {},\n): Promise<TradesResult<KalshiOrderbookRow>> {\n const payload: RawKalshiOrderbook = await fetchOrderbook(ticker, args, opts);\n // Real Kalshi orderbook (post-March-2026): `orderbook_fp` with\n // `yes_dollars` / `no_dollars` arrays of [price_dollar_string,\n // count_fp_string]. Legacy `orderbook.yes` / `.no` accepted as fallback.\n let useFp: boolean;\n let levelsBySide: { yes: ReadonlyArray<unknown>; no: ReadonlyArray<unknown> };\n if (payload.orderbook_fp !== undefined) {\n useFp = true;\n levelsBySide = {\n yes: payload.orderbook_fp.yes_dollars ?? [],\n no: payload.orderbook_fp.no_dollars ?? [],\n };\n } else {\n useFp = false;\n levelsBySide = {\n yes: payload.orderbook?.yes ?? [],\n no: payload.orderbook?.no ?? [],\n };\n }\n const rows: KalshiOrderbookRow[] = [];\n for (const side of [\"yes\", \"no\"] as const) {\n const levels = levelsBySide[side];\n for (const level of levels) {\n if (Array.isArray(level) && level.length >= 2) {\n rows.push({\n side,\n price: useFp ? dollarsToCents(level[0]) : maybeNumber(level[0]),\n size: useFp ? fpStringToInt(level[1]) : maybeInt(level[1]),\n source: SOURCE,\n });\n } else if (level !== null && typeof level === \"object\") {\n // Dict form — access via Record<string, unknown> to satisfy TS strict\n // narrowing without losing the runtime tolerance for `contracts` alias.\n const obj = level as Record<string, unknown>;\n rows.push({\n side,\n price: useFp ? dollarsToCents(obj.price) : maybeNumber(obj.price),\n size: useFp\n ? fpStringToInt(obj.size ?? obj.contracts)\n : maybeInt(obj.size ?? obj.contracts),\n source: SOURCE,\n });\n }\n }\n }\n const snapshotAt = new Date().toISOString();\n return Object.freeze({\n rows: Object.freeze(rows),\n source: SOURCE,\n retrievedAt: snapshotAt,\n snapshotAt,\n ticker,\n });\n}\n","// Phase 9 — Polymarket trades public surface (TRADES-04..05, TS port of\n// packages/markets/src/mostlyright/markets/polymarket_trades.py).\n//\n// Uses the existing Gamma client pattern (fetchFn injection, 0.2 s polite\n// floor). Row shapes mirror Python column-for-column.\n\nimport { fetchWithRetry } from \"@mostlyrightmd/core\";\n\nimport type { PolymarketHistoryRow, PolymarketSnapshotRow, TradesResult } from \"./types.js\";\n\nconst GAMMA_BASE = \"https://gamma-api.polymarket.com\";\n// Architect iter-1 CRITICAL: prices-history lives on the CLOB host\n// (clob.polymarket.com), NOT Gamma. The `market` query parameter is the\n// CLOB token id (ERC-1155 asset id) — NOT a Gamma market/condition/event id.\nconst CLOB_BASE = \"https://clob.polymarket.com\";\nconst DEFAULT_USER_AGENT = \"mostlyright-ts/0.2.0 (+https://github.com/helloiamvu/tradewinds)\";\nconst DEFAULT_SLEEP_BETWEEN_MS = 200;\n/** Source label for snapshot rows (Gamma-hosted). */\nconst SOURCE_SNAPSHOT = \"polymarket.gamma\" as const;\n/** Source label for history rows (CLOB-hosted; distinct from Gamma). */\nconst SOURCE_HISTORY = \"polymarket.clob\" as const;\n\nexport interface PolymarketClientOptions {\n /** Politeness sleep between requests in ms. Default 200. 0 to skip. */\n readonly sleepBetweenMs?: number;\n /** AbortSignal for the whole call. */\n readonly signal?: AbortSignal;\n /** Override fetch for tests. */\n readonly fetchFn?: typeof fetch;\n /** Per-attempt timeout. Default 30_000 ms. */\n readonly timeoutMs?: number;\n}\n\nexport interface PolymarketHistoryArgs {\n readonly from: Date;\n readonly to: Date;\n /** Bucket size in minutes (default 60). */\n readonly fidelityMinutes?: number;\n}\n\nfunction validateDate(d: Date, name: string): void {\n if (!(d instanceof Date) || Number.isNaN(d.getTime())) {\n throw new TypeError(`${name} must be a valid Date; got ${String(d)}`);\n }\n}\n\nfunction maybeNumber(v: unknown): number | null {\n if (v === null || v === undefined) return null;\n const n = typeof v === \"string\" ? Number(v) : (v as number);\n return typeof n === \"number\" && Number.isFinite(n) ? n : null;\n}\n\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n const onAbort = () => {\n cleanup();\n reject(signal?.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n function cleanup() {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n if (signal) {\n if (signal.aborted) {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", onAbort);\n }\n });\n}\n\nfunction buildUrl(\n baseUrl: string,\n path: string,\n params?: Record<string, string | number | boolean | null | undefined>,\n): string {\n const url = new URL(`${baseUrl}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n}\n\nasync function getJson(\n baseUrl: string,\n path: string,\n params: Record<string, string | number | boolean | null | undefined> | undefined,\n opts: PolymarketClientOptions,\n): Promise<unknown> {\n const url = buildUrl(baseUrl, path, params);\n const headers: Record<string, string> = {\n \"User-Agent\": DEFAULT_USER_AGENT,\n Accept: \"application/json\",\n };\n const timeoutMs = opts.timeoutMs ?? 30_000;\n let resp: Response;\n if (opts.fetchFn !== undefined) {\n const init: RequestInit = { method: \"GET\", headers };\n if (opts.signal) init.signal = opts.signal;\n resp = await opts.fetchFn(url, init);\n if (!resp.ok) {\n throw new Error(`polymarket GET ${url} failed: HTTP ${resp.status}`);\n }\n } else {\n const retryOpts: Parameters<typeof fetchWithRetry>[1] = {\n method: \"GET\",\n headers,\n timeoutMs,\n };\n if (opts.signal) retryOpts.signal = opts.signal;\n resp = await fetchWithRetry(url, retryOpts);\n }\n const json = await resp.json();\n const sleepMs = opts.sleepBetweenMs ?? DEFAULT_SLEEP_BETWEEN_MS;\n if (sleepMs > 0) {\n await sleep(sleepMs, opts.signal);\n }\n return json;\n}\n\ninterface RawPricePoint {\n readonly t?: number;\n readonly p?: number | string;\n readonly v?: number | string;\n readonly price?: number | string;\n readonly volume?: number | string;\n}\n\ninterface RawMarket {\n readonly id?: string | number;\n readonly outcomes?: string | ReadonlyArray<unknown>;\n readonly outcomePrices?: string | ReadonlyArray<unknown>;\n readonly volume?: number | string;\n readonly liquidity?: number | string;\n}\n\ninterface RawEvent {\n readonly id?: string;\n readonly markets?: ReadonlyArray<RawMarket>;\n}\n\nfunction coerceStringList(v: unknown): string[] {\n if (v === null || v === undefined) return [];\n if (Array.isArray(v)) return v.map((x) => String(x));\n if (typeof v === \"string\") {\n try {\n const parsed: unknown = JSON.parse(v);\n if (Array.isArray(parsed)) return parsed.map((x) => String(x));\n } catch {\n return [];\n }\n }\n return [];\n}\n\nexport async function polymarketHistory(\n /** CLOB token id (ERC-1155 asset id, one per outcome — YES or NO). NOT\n * a Gamma market/condition/event id. Architect iter-1 CRITICAL fix. */\n tokenId: string,\n args: PolymarketHistoryArgs,\n opts: PolymarketClientOptions = {},\n): Promise<TradesResult<PolymarketHistoryRow>> {\n if (typeof tokenId !== \"string\" || tokenId.length === 0) {\n throw new TypeError(`tokenId must be a non-empty string; got ${JSON.stringify(tokenId)}`);\n }\n validateDate(args.from, \"from\");\n validateDate(args.to, \"to\");\n if (args.from.getTime() >= args.to.getTime()) {\n throw new RangeError(\n `from (${args.from.toISOString()}) must be < to (${args.to.toISOString()})`,\n );\n }\n const fidelity = args.fidelityMinutes ?? 60;\n if (fidelity < 1 || !Number.isInteger(fidelity)) {\n throw new RangeError(`fidelityMinutes must be a positive integer; got ${fidelity}`);\n }\n const payload = await getJson(\n CLOB_BASE,\n \"/prices-history\",\n {\n market: tokenId,\n startTs: Math.trunc(args.from.getTime() / 1000),\n endTs: Math.trunc(args.to.getTime() / 1000),\n fidelity,\n },\n opts,\n );\n let points: ReadonlyArray<RawPricePoint>;\n if (Array.isArray(payload)) {\n points = payload as ReadonlyArray<RawPricePoint>;\n } else if (payload !== null && typeof payload === \"object\") {\n points = (payload as { history?: ReadonlyArray<RawPricePoint> }).history ?? [];\n } else {\n points = [];\n }\n const rows: PolymarketHistoryRow[] = [];\n for (const p of points) {\n if (p === null || typeof p !== \"object\") continue;\n const tsEpoch = p.t;\n const ts =\n typeof tsEpoch === \"number\" && Number.isFinite(tsEpoch)\n ? new Date(tsEpoch * 1000).toISOString()\n : null;\n rows.push({\n ts,\n price: maybeNumber(p.p ?? p.price),\n volume: maybeNumber(p.v ?? p.volume),\n source: SOURCE_HISTORY,\n });\n }\n return Object.freeze({\n rows: Object.freeze(rows),\n source: SOURCE_HISTORY,\n retrievedAt: new Date().toISOString(),\n tokenId,\n fidelityMinutes: fidelity,\n });\n}\n\nexport async function polymarketSnapshot(\n eventId: string,\n opts: PolymarketClientOptions = {},\n): Promise<TradesResult<PolymarketSnapshotRow>> {\n if (typeof eventId !== \"string\" || eventId.length === 0) {\n throw new TypeError(`eventId must be a non-empty string; got ${JSON.stringify(eventId)}`);\n }\n const payload = await getJson(\n GAMMA_BASE,\n `/events/${encodeURIComponent(eventId)}`,\n undefined,\n opts,\n );\n if (payload === null || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new Error(\n `polymarket snapshot: bad event payload for ${JSON.stringify(eventId)}; expected object`,\n );\n }\n const event = payload as RawEvent;\n const markets = event.markets ?? [];\n const rows: PolymarketSnapshotRow[] = [];\n for (const m of markets) {\n if (m === null || typeof m !== \"object\") continue;\n const outcomes = coerceStringList(m.outcomes);\n const prices = coerceStringList(m.outcomePrices);\n const volume = maybeNumber(m.volume);\n const liquidity = maybeNumber(m.liquidity);\n const marketIdStr = m.id !== undefined && m.id !== null ? String(m.id) : null;\n for (let i = 0; i < outcomes.length; i++) {\n const priceStr = i < prices.length ? prices[i] : null;\n rows.push({\n marketId: marketIdStr,\n outcome: outcomes[i] ?? \"\",\n lastPrice: maybeNumber(priceStr),\n volume,\n liquidity,\n source: SOURCE_SNAPSHOT,\n });\n }\n }\n const snapshotAt = new Date().toISOString();\n return Object.freeze({\n rows: Object.freeze(rows),\n source: SOURCE_SNAPSHOT,\n retrievedAt: snapshotAt,\n snapshotAt,\n eventId,\n });\n}\n","// Phase 9 — trades cache adapter (TRADES-06, TS counterpart to\n// packages/markets/src/mostlyright/markets/_trades_cache.py).\n//\n// Thin wrapper over the existing `@mostlyrightmd/core` CacheStore interface\n// (MemoryStore / IndexedDBStore / FsStore). Key shape mirrors the Python\n// path layout: trades/{issuer}/{ticker}/{YYYY-MM}.\n//\n// Volatile-window rules: current UTC month and future months are not\n// cacheable (write no-op + read miss) — trades may still arrive for the\n// active month.\n\nimport type { CacheStore } from \"@mostlyrightmd/core/internal/cache\";\n\nconst ISSUER_RE = /^[a-z][a-z0-9._-]{0,31}$/;\n// Iter-2 codex + python-architect HIGH: parity with Python `_trades_cache._TICKER_RE`.\n// The leading negative lookahead `(?!\\.+$)` rejects all-dot strings (`.`, `..`,\n// `...`). Without it, a `..` ticker would silently misplace the cache key at\n// the issuer-directory level on stores with path-aware semantics (matches\n// Python's silent-misplacement defense).\nconst TICKER_RE = /^(?!\\.+$)[A-Za-z0-9._-]{1,128}$/;\n\nexport interface TradesCacheKey {\n readonly issuer: string;\n readonly ticker: string;\n readonly year: number;\n readonly month: number;\n}\n\n/** Build the canonical key string for a (issuer, ticker, year, month). */\nexport function tradesCacheKey(args: TradesCacheKey): string {\n if (typeof args.issuer !== \"string\" || !ISSUER_RE.test(args.issuer)) {\n throw new RangeError(\n `invalid issuer for cache key: ${JSON.stringify(args.issuer)}; must match ${ISSUER_RE}`,\n );\n }\n if (typeof args.ticker !== \"string\" || !TICKER_RE.test(args.ticker)) {\n throw new RangeError(\n `invalid ticker for cache key: ${JSON.stringify(args.ticker)}; must match ${TICKER_RE}`,\n );\n }\n if (!Number.isInteger(args.year) || args.year < 2000 || args.year > 2100) {\n throw new RangeError(`year out of range [2000, 2100]: ${args.year}`);\n }\n if (!Number.isInteger(args.month) || args.month < 1 || args.month > 12) {\n throw new RangeError(`month out of range [1, 12]: ${args.month}`);\n }\n const mm = args.month.toString().padStart(2, \"0\");\n return `trades/${args.issuer}/${args.ticker}/${args.year}-${mm}`;\n}\n\nexport function isCurrentUtcMonth(year: number, month: number, now: Date = new Date()): boolean {\n return year === now.getUTCFullYear() && month === now.getUTCMonth() + 1;\n}\n\nexport function isFutureUtcMonth(year: number, month: number, now: Date = new Date()): boolean {\n const yNow = now.getUTCFullYear();\n const mNow = now.getUTCMonth() + 1;\n return year > yNow || (year === yNow && month > mNow);\n}\n\nexport interface TradesCacheReadOpts {\n readonly now?: Date;\n}\n\nexport interface TradesCacheWriteOpts {\n readonly now?: Date;\n}\n\n/** Read cached trades rows. Returns `null` on miss / current-or-future month. */\nexport async function readTradesCache<Row>(\n cache: CacheStore,\n args: TradesCacheKey,\n opts: TradesCacheReadOpts = {},\n): Promise<ReadonlyArray<Row> | null> {\n if (\n isCurrentUtcMonth(args.year, args.month, opts.now) ||\n isFutureUtcMonth(args.year, args.month, opts.now)\n ) {\n return null;\n }\n const key = tradesCacheKey(args);\n const value = await cache.get<ReadonlyArray<Row>>(key);\n return value ?? null;\n}\n\n/**\n * Write rows to the cache. Returns `false` (no-op) when:\n * - the (year, month) is the current UTC month (still mutable),\n * - the (year, month) is in the future, OR\n * - rows is empty.\n */\nexport async function writeTradesCache<Row>(\n cache: CacheStore,\n args: TradesCacheKey,\n rows: ReadonlyArray<Row>,\n opts: TradesCacheWriteOpts = {},\n): Promise<boolean> {\n if (\n isCurrentUtcMonth(args.year, args.month, opts.now) ||\n isFutureUtcMonth(args.year, args.month, opts.now)\n ) {\n return false;\n }\n if (rows.length === 0) return false;\n const key = tradesCacheKey(args);\n await cache.set(key, rows);\n return true;\n}\n\n/** Delete cached entry; returns true when a value existed before. */\nexport async function invalidateTradesCache(\n cache: CacheStore,\n args: TradesCacheKey,\n): Promise<boolean> {\n const key = tradesCacheKey(args);\n const before = await cache.get(key);\n if (before === null) return false;\n await cache.delete(key);\n return true;\n}\n"],"mappings":"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","names":["fetchWithRetry","DEFAULT_USER_AGENT","DEFAULT_SLEEP_BETWEEN_MS","validateDate","maybeNumber","sleep","buildUrl","getJson"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@mostlyrightmd/markets",
3
+ "version": "0.1.0-rc.7",
4
+ "description": "Prediction-market resolvers (Kalshi NHIGH/NLOW, Polymarket) for the mostlyright TypeScript SDK (placeholder scaffold; implementation lands in TS-W1+).",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./polymarket": {
17
+ "types": "./dist/polymarket/index.d.ts",
18
+ "import": "./dist/polymarket/index.mjs",
19
+ "require": "./dist/polymarket/index.cjs"
20
+ },
21
+ "./trades": {
22
+ "types": "./dist/trades/index.d.ts",
23
+ "import": "./dist/trades/index.mjs",
24
+ "require": "./dist/trades/index.cjs"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "peerDependencies": {
31
+ "@mostlyrightmd/core": "^0.1.0-rc.7"
32
+ },
33
+ "devDependencies": {
34
+ "tsup": "8.3.5",
35
+ "typescript": "5.6.3",
36
+ "vitest": "2.1.9",
37
+ "@mostlyrightmd/core": "0.1.0-rc.7"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "prebuild": "pnpm --filter @mostlyrightmd/codegen run codegen",
44
+ "build": "tsup",
45
+ "test": "vitest",
46
+ "typecheck": "tsc --noEmit",
47
+ "clean": "rm -rf dist coverage .tsbuildinfo",
48
+ "codegen": "echo \"@mostlyrightmd/markets — no codegen step at this layer\""
49
+ }
50
+ }