@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.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/index.cjs +477 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.global.js +467 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.mjs +442 -0
- package/dist/index.mjs.map +1 -0
- package/dist/polymarket/index.cjs +893 -0
- package/dist/polymarket/index.cjs.map +1 -0
- package/dist/polymarket/index.d.cts +317 -0
- package/dist/polymarket/index.d.ts +317 -0
- package/dist/polymarket/index.mjs +842 -0
- package/dist/polymarket/index.mjs.map +1 -0
- package/dist/trades/index.cjs +644 -0
- package/dist/trades/index.cjs.map +1 -0
- package/dist/trades/index.d.cts +210 -0
- package/dist/trades/index.d.ts +210 -0
- package/dist/trades/index.mjs +602 -0
- package/dist/trades/index.mjs.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { TradewindsError } from '@mostlyrightmd/core';
|
|
2
|
+
import { InternationalRow } from '@mostlyrightmd/core/discovery';
|
|
3
|
+
|
|
4
|
+
/** Raw Gamma event payload — narrow shape we depend on. */
|
|
5
|
+
interface PolymarketEventRaw {
|
|
6
|
+
id?: string;
|
|
7
|
+
slug?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
endDate?: string;
|
|
11
|
+
active?: boolean;
|
|
12
|
+
closed?: boolean;
|
|
13
|
+
archived?: boolean;
|
|
14
|
+
tags?: Array<string | {
|
|
15
|
+
label?: string;
|
|
16
|
+
slug?: string;
|
|
17
|
+
}>;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
interface FetchEventsOptions {
|
|
21
|
+
/** Politeness sleep between requests, in ms. Default 200 (0.2 s). Pass 0 to skip. */
|
|
22
|
+
readonly sleepBetweenMs?: number;
|
|
23
|
+
/** AbortSignal for the whole paginator. */
|
|
24
|
+
readonly signal?: AbortSignal;
|
|
25
|
+
/** Override fetch (for tests). Defaults to global fetch. */
|
|
26
|
+
readonly fetchFn?: typeof fetch;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fetch every active weather event from Gamma, paginated by `offset` in
|
|
30
|
+
* `PAGE_SIZE` increments until either an empty page is returned or
|
|
31
|
+
* `MAX_EVENTS` is reached. Dedup by slug to defend against the rare case
|
|
32
|
+
* where pagination overlaps under concurrent edits on Gamma's side.
|
|
33
|
+
*/
|
|
34
|
+
declare function fetchEvents(opts?: FetchEventsOptions): Promise<PolymarketEventRaw[]>;
|
|
35
|
+
/** Fetch a single event by id. Useful for the settle() flow when only an id is known. */
|
|
36
|
+
declare function fetchEventById(eventId: string, opts?: FetchEventsOptions): Promise<PolymarketEventRaw | null>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resolution-source netlocs we trust. Anything else throws
|
|
40
|
+
* PolymarketEventError. Mirrors Python `RESOLUTION_SOURCE_ALLOWLIST`.
|
|
41
|
+
*/
|
|
42
|
+
declare const RESOLUTION_SOURCE_ALLOWLIST: ReadonlySet<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Per-netloc → enum value for the `resolutionSourceType` field on settlement
|
|
45
|
+
* records. `hko` / `cwa` are predeclared for v0.2 (HKO/CWA clients).
|
|
46
|
+
*/
|
|
47
|
+
declare const NETLOC_TO_RESOLUTION_TYPE: Readonly<Record<string, string>>;
|
|
48
|
+
/** Enum values for the `resolutionSourceType` column. */
|
|
49
|
+
declare const POLYMARKET_RESOLUTION_SOURCE_TYPES: readonly ["wunderground", "noaa_wrh", "hko", "cwa", "other"];
|
|
50
|
+
type PolymarketResolutionSourceType = (typeof POLYMARKET_RESOLUTION_SOURCE_TYPES)[number];
|
|
51
|
+
/**
|
|
52
|
+
* Event id pattern. Python widened this in codex iter-2 P1: real Gamma IDs
|
|
53
|
+
* are numeric strings (`"12345"`), but condition-tag UUIDs + slugs also
|
|
54
|
+
* appear in the wild. Wide enough to accept real Gamma payloads but narrow
|
|
55
|
+
* enough to defend against URL-path injection.
|
|
56
|
+
*
|
|
57
|
+
* The plan called this "UUID4 regex" but follows Python's actual behavior:
|
|
58
|
+
* the strict UUID4 form rejected every real Gamma event, breaking the
|
|
59
|
+
* discover → settle round-trip.
|
|
60
|
+
*/
|
|
61
|
+
declare const EVENT_ID_RE: RegExp;
|
|
62
|
+
/**
|
|
63
|
+
* Max bytes of a Polymarket event description we'll parse. Polymarket
|
|
64
|
+
* descriptions are concise; oversized payloads indicate hostile input
|
|
65
|
+
* (ReDoS defense).
|
|
66
|
+
*/
|
|
67
|
+
declare const MAX_DESCRIPTION_BYTES: number;
|
|
68
|
+
/**
|
|
69
|
+
* Per-resolution-source publication delay. Settlement refuses to settle
|
|
70
|
+
* until `now - settlementDate >= delay` to avoid settling on values the
|
|
71
|
+
* issuer hasn't published yet.
|
|
72
|
+
*
|
|
73
|
+
* Wunderground typically posts daily extremes ~6h after local midnight;
|
|
74
|
+
* NOAA WRH ~4h. "other" gets a conservative 24h fallback.
|
|
75
|
+
*/
|
|
76
|
+
declare const SETTLE_DELAY_HOURS: Readonly<Record<string, number>>;
|
|
77
|
+
/**
|
|
78
|
+
* Slug date extractor. Polymarket weather slugs embed the resolution date
|
|
79
|
+
* (e.g. `will-nyc-be-above-80f-on-2026-05-23`). Used by `polymarketSettle`
|
|
80
|
+
* to derive the resolution date from the slug instead of `event.endDate`.
|
|
81
|
+
*/
|
|
82
|
+
declare const SLUG_DATE_RE: RegExp;
|
|
83
|
+
/** Markets routed to v0.2 sources (CWA/HKO clients). */
|
|
84
|
+
declare const DEFERRED_STATIONS: ReadonlySet<string>;
|
|
85
|
+
/** Discovery row shape — one per active weather event. */
|
|
86
|
+
interface PolymarketDiscoveryRow {
|
|
87
|
+
readonly eventId: string | null;
|
|
88
|
+
readonly slug: string | null;
|
|
89
|
+
readonly title: string | null;
|
|
90
|
+
readonly city: string | null;
|
|
91
|
+
readonly icao: string | null;
|
|
92
|
+
readonly measure: "high" | "low" | "default" | null;
|
|
93
|
+
readonly endTime: string | null;
|
|
94
|
+
readonly resolutionSourceType: PolymarketResolutionSourceType | null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Native unit of the market's published settlement value. Codex iter-3 P2:
|
|
98
|
+
* international Polymarket markets publish in whole-°C, US in °F. The
|
|
99
|
+
* settle engine returns the resolved value in BOTH units so the caller's
|
|
100
|
+
* comparison against Polymarket's published value uses the matching unit.
|
|
101
|
+
*/
|
|
102
|
+
type SettlementUnit = "fahrenheit" | "celsius";
|
|
103
|
+
/** Settlement result shape. */
|
|
104
|
+
interface PolymarketSettlementResult {
|
|
105
|
+
readonly eventId: string;
|
|
106
|
+
readonly settlementDate: string;
|
|
107
|
+
readonly icao: string;
|
|
108
|
+
readonly measure: "high" | "low" | "default";
|
|
109
|
+
/**
|
|
110
|
+
* Resolved temperature in the unit the caller asked for (the `unit`
|
|
111
|
+
* option; defaults to the station's native unit — F for US-registry
|
|
112
|
+
* stations, C for international). Convenience pointer to `resolvedValueF`
|
|
113
|
+
* or `resolvedValueC`.
|
|
114
|
+
*/
|
|
115
|
+
readonly resolvedValue: number;
|
|
116
|
+
readonly resolvedValueC: number;
|
|
117
|
+
readonly resolvedValueF: number;
|
|
118
|
+
/** Which unit `resolvedValue` carries. */
|
|
119
|
+
readonly unit: SettlementUnit;
|
|
120
|
+
readonly resolutionSourceType: PolymarketResolutionSourceType;
|
|
121
|
+
readonly dataQualityAlert: string | null;
|
|
122
|
+
}
|
|
123
|
+
/** Settlement options. */
|
|
124
|
+
interface PolymarketSettleOptions {
|
|
125
|
+
/** Optional description override (live discovery normally supplies this). */
|
|
126
|
+
readonly description?: string;
|
|
127
|
+
/** Reference "now" for the finalization-delay check. Defaults to `new Date()`. */
|
|
128
|
+
readonly now?: Date;
|
|
129
|
+
/**
|
|
130
|
+
* Polymarket's published settlement value, if known. The comparison
|
|
131
|
+
* uses whichever unit `unit` is set to. ±1°F (or ±0.6°C) diff emits an
|
|
132
|
+
* alert; values outside that band don't throw.
|
|
133
|
+
*/
|
|
134
|
+
readonly polymarketPublishedValue?: number;
|
|
135
|
+
/**
|
|
136
|
+
* Resolved-value unit. Defaults to the station's native unit:
|
|
137
|
+
* °F for the 20 US Kalshi cities; °C for international stations
|
|
138
|
+
* (matches Polymarket's published-bucket convention per
|
|
139
|
+
* .planning/research/INGEST-PLANNER-RESEARCH.md). Codex iter-3 P2.
|
|
140
|
+
*/
|
|
141
|
+
readonly unit?: SettlementUnit;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Apply the 16 KB cap + netloc allowlist to a description string.
|
|
146
|
+
*
|
|
147
|
+
* @throws PayloadTooLargeError when the UTF-8 byte length exceeds 16 KB.
|
|
148
|
+
* @throws PolymarketEventError when any URL has a netloc outside the allowlist.
|
|
149
|
+
*/
|
|
150
|
+
declare function validateDescription(description: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Classify a description's resolution source by the first allowlisted netloc
|
|
153
|
+
* found. Returns `"other"` when no allowlisted URL appears (the settlement
|
|
154
|
+
* engine falls back to the 24-hour delay for "other").
|
|
155
|
+
*/
|
|
156
|
+
declare function extractResolutionSourceType(description: string): PolymarketResolutionSourceType;
|
|
157
|
+
|
|
158
|
+
/** Event payload is malformed (bad event id, oversized description, bad URL). */
|
|
159
|
+
declare class PolymarketEventError extends TradewindsError {
|
|
160
|
+
constructor(message: string);
|
|
161
|
+
static readonly defaultErrorCode = "POLYMARKET_EVENT_INVALID";
|
|
162
|
+
}
|
|
163
|
+
/** Settlement engine couldn't resolve an event to a value. */
|
|
164
|
+
declare class PolymarketSettlementError extends TradewindsError {
|
|
165
|
+
constructor(message: string);
|
|
166
|
+
static readonly defaultErrorCode = "POLYMARKET_SETTLEMENT_FAILED";
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Settlement attempted before the resolution source's publication delay
|
|
170
|
+
* has elapsed. Carries `waitHours` so the caller can schedule a retry.
|
|
171
|
+
*
|
|
172
|
+
* Codex iter-1 P2: overrides `payload()` so `toDict()` (and any MCP
|
|
173
|
+
* serializer downstream) includes the structured retry metadata. The
|
|
174
|
+
* fields are otherwise only readable via the live JS error object.
|
|
175
|
+
*/
|
|
176
|
+
declare class TooEarlyToSettleError extends TradewindsError {
|
|
177
|
+
readonly waitHours: number;
|
|
178
|
+
readonly resolutionSourceType: string;
|
|
179
|
+
constructor(message: string, opts: {
|
|
180
|
+
waitHours: number;
|
|
181
|
+
resolutionSourceType: string;
|
|
182
|
+
});
|
|
183
|
+
static readonly defaultErrorCode = "POLYMARKET_TOO_EARLY";
|
|
184
|
+
protected payload(): Record<string, unknown>;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Description exceeded the 16 KB cap. Direct subclass of TradewindsError
|
|
188
|
+
* (rather than PolymarketEventError) because TS prevents narrowing a
|
|
189
|
+
* `static readonly` literal type in a subclass.
|
|
190
|
+
*/
|
|
191
|
+
declare class PayloadTooLargeError extends TradewindsError {
|
|
192
|
+
constructor(message: string);
|
|
193
|
+
static readonly defaultErrorCode = "POLYMARKET_PAYLOAD_TOO_LARGE";
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface PolymarketDiscoverOptions extends FetchEventsOptions {
|
|
197
|
+
/**
|
|
198
|
+
* Sink for dropped events. Tests pass a recorder; production can pass
|
|
199
|
+
* console.info or omit. Receives `{slug, reason}` per skipped event.
|
|
200
|
+
*/
|
|
201
|
+
onSkip?: (info: {
|
|
202
|
+
slug: string | null;
|
|
203
|
+
reason: string;
|
|
204
|
+
}) => void;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Discover active Polymarket weather events.
|
|
208
|
+
*
|
|
209
|
+
* Returns one row per resolvable event. Events the resolver can't match
|
|
210
|
+
* are dropped silently (with optional `onSkip` callback). Events that
|
|
211
|
+
* route to a deferred station (Taipei, HK-low) appear in the result with
|
|
212
|
+
* `icao: null` and `measure: null` so callers can SEE them.
|
|
213
|
+
*/
|
|
214
|
+
declare function polymarketDiscover(opts?: PolymarketDiscoverOptions): Promise<PolymarketDiscoveryRow[]>;
|
|
215
|
+
|
|
216
|
+
declare const POLYMARKET_KNOWN_WRONG_STATIONS: Readonly<Record<string, ReadonlySet<string>>>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Detect whether the market resolves on the daily HIGH or LOW from
|
|
220
|
+
* keywords in the event title/slug/name. Distinct from the station-level
|
|
221
|
+
* measure: many cities have one airport for both, but the market still
|
|
222
|
+
* resolves on tmax XOR tmin.
|
|
223
|
+
*/
|
|
224
|
+
declare function detectMarketMeasure(event: PolymarketEventRaw): "high" | "low" | "default";
|
|
225
|
+
/**
|
|
226
|
+
* Derive a city key from slug + title + tags. Lowercase substring match
|
|
227
|
+
* against the catalog; longest-first so multi-token cities outrank prefixes.
|
|
228
|
+
* Returns null when no match — caller decides whether to drop or surface.
|
|
229
|
+
*/
|
|
230
|
+
declare function deriveCity(event: PolymarketEventRaw): string | null;
|
|
231
|
+
/**
|
|
232
|
+
* Extract the canonical Wunderground PWS / airport ICAO from `text`.
|
|
233
|
+
*
|
|
234
|
+
* Tier 1.5 of the resolver chain — runs between explicit `event.city`
|
|
235
|
+
* and slug-derive. When a Polymarket event embeds a Wunderground PWS
|
|
236
|
+
* URL, the URL IS the source of truth; no catalog lookup needed.
|
|
237
|
+
*
|
|
238
|
+
* Multi-URL disambiguation: when multiple canonical Wunderground URLs
|
|
239
|
+
* appear, ALL extracted ICAOs MUST agree. Disagreement returns null so
|
|
240
|
+
* the resolver falls through to Tier 2 city-derive (prevents an
|
|
241
|
+
* issuer-side citation URL from silently swapping the settlement station).
|
|
242
|
+
*
|
|
243
|
+
* Returns uppercase ICAO (4 chars, leading K) when a canonical URL is
|
|
244
|
+
* found AND any additional canonical URLs agree. Null otherwise —
|
|
245
|
+
* including the disagreement case.
|
|
246
|
+
*/
|
|
247
|
+
declare function extractIcaoFromResolutionSource(text: string | null | undefined): string | null;
|
|
248
|
+
/**
|
|
249
|
+
* Resolve an event to `{icao, stationMeasure}` using the city catalog.
|
|
250
|
+
*
|
|
251
|
+
* Returns null when no city matches (caller drops the event).
|
|
252
|
+
* Raises DeferredMarketError when the resolution would route to a v0.2
|
|
253
|
+
* source (Taipei RCTP, Hong Kong VHHH for the low-extreme market).
|
|
254
|
+
*/
|
|
255
|
+
declare function resolveStationForEvent(event: PolymarketEventRaw, marketMeasure: "high" | "low" | "default"): {
|
|
256
|
+
city: string;
|
|
257
|
+
icao: string;
|
|
258
|
+
stationMeasure: "high" | "low" | "default";
|
|
259
|
+
} | null;
|
|
260
|
+
/**
|
|
261
|
+
* Parse the resolution date from a Polymarket weather slug. The LAST
|
|
262
|
+
* YYYY-MM-DD match wins because slugs may carry both a creation date and
|
|
263
|
+
* a resolution date (`created-2026-01-01-resolves-2026-05-23`) — the
|
|
264
|
+
* resolution date is typically rightmost in Polymarket's convention.
|
|
265
|
+
*
|
|
266
|
+
* Mirrors Python `_settlement_date_from_slug` architect iter-1 HIGH-4.
|
|
267
|
+
*/
|
|
268
|
+
declare function settlementDateFromSlug(slug: string): string;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Loader contract for the resolution-source observation rows. Defaults to
|
|
272
|
+
* a no-op stub so the security/validation gates can be unit-tested without
|
|
273
|
+
* pulling live cache data; production callers wire the cache reader here.
|
|
274
|
+
*
|
|
275
|
+
* Returning an empty array signals "no rows available for this date" and
|
|
276
|
+
* surfaces as PolymarketSettlementError downstream.
|
|
277
|
+
*/
|
|
278
|
+
type ObservationLoader = (args: {
|
|
279
|
+
icao: string;
|
|
280
|
+
fromDate: string;
|
|
281
|
+
toDate: string;
|
|
282
|
+
}) => Promise<ReadonlyArray<InternationalRow>>;
|
|
283
|
+
interface PolymarketSettleArgs extends PolymarketSettleOptions {
|
|
284
|
+
/**
|
|
285
|
+
* The raw Gamma event payload. Required because the settle engine reads
|
|
286
|
+
* `slug` (for the resolution date), `description` (for the resolution
|
|
287
|
+
* source), and `title/slug/name` (for the measure). Callers can fetch
|
|
288
|
+
* via `fetchEventById` if they only have an id.
|
|
289
|
+
*/
|
|
290
|
+
readonly event: PolymarketEventRaw;
|
|
291
|
+
/**
|
|
292
|
+
* Loader that returns observation rows for `[fromDate, toDate]`. Defaults
|
|
293
|
+
* to an in-memory empty loader so callers MUST wire this for production.
|
|
294
|
+
*/
|
|
295
|
+
readonly loader?: ObservationLoader;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Settle a single Polymarket event.
|
|
299
|
+
*
|
|
300
|
+
* Validates the event id, description (16 KB cap, netloc allowlist),
|
|
301
|
+
* resolves the station via the city catalog, parses the resolution date
|
|
302
|
+
* from the slug, enforces the per-source publication-delay window, and
|
|
303
|
+
* pulls the daily extreme via `internationalDailyExtremes`.
|
|
304
|
+
*
|
|
305
|
+
* @throws PolymarketEventError on bad id / bad description / unsupported station.
|
|
306
|
+
* @throws PolymarketSettlementError when no rows resolve for the station/date.
|
|
307
|
+
* @throws TooEarlyToSettleError when the publication delay hasn't elapsed.
|
|
308
|
+
*/
|
|
309
|
+
declare function polymarketSettle(args: PolymarketSettleArgs): Promise<PolymarketSettlementResult>;
|
|
310
|
+
/**
|
|
311
|
+
* Settle by event id alone. Fetches the event from Gamma first, then
|
|
312
|
+
* delegates to `polymarketSettle`. Useful when a caller only has the id
|
|
313
|
+
* (e.g. from a Kalshi-side cross-reference).
|
|
314
|
+
*/
|
|
315
|
+
declare function polymarketSettleById(eventId: string, args: Omit<PolymarketSettleArgs, "event">): Promise<PolymarketSettlementResult>;
|
|
316
|
+
|
|
317
|
+
export { DEFERRED_STATIONS, EVENT_ID_RE, type FetchEventsOptions, MAX_DESCRIPTION_BYTES, NETLOC_TO_RESOLUTION_TYPE, type ObservationLoader, POLYMARKET_KNOWN_WRONG_STATIONS, POLYMARKET_RESOLUTION_SOURCE_TYPES, PayloadTooLargeError, type PolymarketDiscoverOptions, type PolymarketDiscoveryRow, PolymarketEventError, type PolymarketEventRaw, type PolymarketResolutionSourceType, type PolymarketSettleArgs, type PolymarketSettleOptions, PolymarketSettlementError, type PolymarketSettlementResult, RESOLUTION_SOURCE_ALLOWLIST, SETTLE_DELAY_HOURS, SLUG_DATE_RE, type SettlementUnit, TooEarlyToSettleError, deriveCity, detectMarketMeasure, extractIcaoFromResolutionSource, extractResolutionSourceType, fetchEventById, fetchEvents, polymarketDiscover, polymarketSettle, polymarketSettleById, resolveStationForEvent, settlementDateFromSlug, validateDescription };
|