diff --git a/core/api-doc-config.generated.json b/core/api-doc-config.generated.json index 40aaff04..131c33c5 100644 --- a/core/api-doc-config.generated.json +++ b/core/api-doc-config.generated.json @@ -1,9 +1,9 @@ { - "_generated": "Auto-generated by extract-jsdoc.js on 2026-07-10T06:40:05.097Z. Do not edit manually.", + "_generated": "Auto-generated by extract-jsdoc.js on 2026-07-12T06:54:59.328Z. Do not edit manually.", "methods": { "has": { "summary": "HTTP verb for the endpoint (e.g. GET, POST). */", - "description": "method: string;\n /** URL path template, relative to the descriptor's baseUrl. */\n path: string;\n /** Whether this endpoint requires authenticated credentials. */\n isPrivate?: boolean;\n /** Identifier used to generate the implicit API method name. */\n operationId?: string;\n /**\nWhen set, requests use this base URL instead of the descriptor default\n(OpenAPI path- or operation-level `servers` override).\n/\n baseUrl?: string;\n}\n\nexport interface ApiDescriptor {\n /** Base URL that all endpoint paths are resolved against. */\n baseUrl: string;\n /** Map of endpoint key to endpoint definition used by the implicit API machinery. */\n endpoints: Record;\n}\n\nexport interface ImplicitApiMethodInfo {\n /** Generated method name exposed on the exchange instance. */\n name: string;\n /** HTTP verb for the underlying endpoint. */\n method: string;\n /** URL path template for the underlying endpoint. */\n path: string;\n /** Whether the underlying endpoint requires authenticated credentials. */\n isPrivate: boolean;\n}\n\nexport interface MarketFilterParams {\n /** Maximum number of results to return */\n limit?: number;\n /** Pagination offset — number of results to skip */\n offset?: number;\n /** Sort order for results */\n sort?: 'volume' | 'liquidity' | 'newest';\n status?: 'active' | 'inactive' | 'closed' | 'all'; // Filter by market status (default: 'active', 'inactive' and 'closed' are interchangeable)\n searchIn?: 'title' | 'description' | 'both'; // Where to search (default: 'title')\n query?: string; // For keyword search\n slug?: string; // For slug/ticker lookup\n marketId?: string; // Direct lookup by market ID\n outcomeId?: string; // Reverse lookup -- find market containing this outcome\n eventId?: string; // Find markets belonging to an event\n page?: number; // For pagination (used by Limitless)\n similarityThreshold?: number; // For semantic search (used by Limitless)\n /** Filter by source venue (e.g. 'polymarket', 'kalshi', 'myriad'). `exchange` is an alias. */\n sourceExchange?: string;\n /** Alias for `sourceExchange`. */\n exchange?: string;\n}\n\nexport interface MarketFetchParams extends MarketFilterParams {\n /** Optional client-side filter applied after fetching */\n filter?: MarketFilterCriteria;\n /** Filter by category. Each market belongs to a venue-assigned category such as \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Filter by tags. Returns markets matching ANY of the provided tags. Tags are more specific than categories -- for example a \"Sports\" market might carry tags [\"Sports\", \"FIFA World Cup\", \"2026 FIFA World Cup\"]. Common tags include \"Crypto\", \"Politics\", \"Elections\", \"Geopolitics\", \"Fed Rates\", \"Trump\". */\n tags?: string[];\n}\n\nexport interface EventFetchParams {\n query?: string; // For keyword search\n /** Maximum number of results to return */\n limit?: number;\n /** Opaque venue pagination cursor, where supported. */\n cursor?: string;\n /** Pagination offset — number of results to skip */\n offset?: number;\n /** Sort order for results */\n sort?: 'volume' | 'liquidity' | 'newest';\n status?: 'active' | 'inactive' | 'closed' | 'all'; // Filter by event status (default: 'active', 'inactive' and 'closed' are interchangeable)\n /** Where to search (default: 'title') */\n searchIn?: 'title' | 'description' | 'both';\n eventId?: string; // Direct lookup by event ID\n slug?: string; // Lookup by event slug\n /** Filter events by their parent series. Accepts the venue-native series id / ticker / slug (e.g. Kalshi `\"KXATPMATCH\"`, Polymarket `\"wta\"`). Passed through to the vendor where supported, otherwise applied to `sourceMetadata` after fetch. */\n series?: string;\n /** Optional client-side filter applied after fetching */\n filter?: EventFilterCriteria;\n /** Filter by category. Each event belongs to a venue-assigned category such as \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Filter by tags. Returns events matching ANY of the provided tags. Tags are more specific than categories -- for example a \"Politics\" event might carry tags [\"Politics\", \"Geopolitics\", \"Middle East\", \"Iran\"]. Common tags include \"Crypto\", \"Elections\", \"Fed Rates\", \"FIFA World Cup\", \"Trump\". */\n tags?: string[];\n /** Filter by source venue (e.g. 'polymarket', 'kalshi', 'myriad'). `exchange` is an alias. */\n sourceExchange?: string;\n /** Alias for `sourceExchange`. */\n exchange?: string;\n}\n\n/**\nParameters for `fetchSeries`. Venues that don't expose a series concept\nreturn an empty array regardless of the filters.\n/\nexport interface SeriesFetchParams {\n /** Direct lookup by venue-native series id (e.g. \"KXATPMATCH\" on Kalshi, \"atp\" or \"1\" on Polymarket Gamma). When set, the result is the matching series with its events populated where the venue supports it. */\n id?: string;\n /** Lookup by series slug (e.g. \"wta\", \"nfl\"). */\n slug?: string;\n /** Keyword search across series title / description. */\n query?: string;\n /** Filter by recurrence cadence ('daily', 'weekly', 'annual', ...). */\n recurrence?: string;\n /** Maximum number of results to return. */\n limit?: number;\n /** Pagination offset. */\n offset?: number;\n}\n\n/**\nDeprecated - use OHLCVParams or TradesParams instead. Resolution is optional for backward compatibility.\n/\nexport interface HistoryFilterParams {\n resolution?: CandleInterval; // Optional for backward compatibility\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return */\n limit?: number;\n}\n\nexport interface OHLCVParams {\n resolution: CandleInterval; // Required for candle aggregation\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return */\n limit?: number;\n}\n\n/**\nParameters for fetching trade history. No resolution parameter - trades are discrete events.\n/\n/** Maximum allowed value for `TradesParams.limit`. */\nexport const MAX_TRADES_LIMIT = 1000;\n\nexport interface TradesParams {\n // No resolution - trades are discrete events, not aggregated\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return (max {@link MAX_TRADES_LIMIT}) */\n limit?: number;\n}\n\nexport interface MyTradesParams {\n outcomeId?: string; // filter to specific outcome/ticker\n marketId?: string; // filter to specific market\n /** Only return records after this date */\n since?: Date;\n /** Only return records before this date */\n until?: Date;\n /** Maximum number of results to return */\n limit?: number;\n cursor?: string; // for Kalshi cursor pagination\n}\n\nexport interface FetchOrderBookParams {\n /** Outcome side: 'yes' or 'no'. Required for exchanges like Limitless\n where the API returns a single orderbook per market. */\n side?: 'yes' | 'no';\n /** Outcome alias: 'yes' or 'no', or an outcome token ID. When set,\n the first argument is treated as a market ID and this value selects\n which outcome's order book to fetch. Accepts the literal strings\n 'yes'/'no' (resolved via a market lookup) or a raw outcome token ID. */\n outcome?: string;\n /** Unix timestamp (ms) — fetch a historical snapshot at or before this\n time, or the start of a range when combined with `until` (hosted API only). */\n since?: number;\n /** Unix timestamp (ms) — end of a historical range. When combined with\n `since`, returns an array of reconstructed L2 OrderBook snapshots\n between `since` and `until` (hosted API only). */\n until?: number;\n}\n\nexport interface OrderHistoryParams {\n marketId?: string; // required for Limitless (slug)\n /** Only return records after this date */\n since?: Date;\n /** Only return records before this date */\n until?: Date;\n /** Maximum number of results to return */\n limit?: number;\n /** Opaque pagination cursor from a previous response */\n cursor?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Filtering Types\n// ----------------------------------------------------------------------------\n\nexport interface MarketFilterCriteria {\n // Text search\n text?: string;\n searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[]; // Default: ['title']\n\n // Numeric range filters\n volume24h?: { min?: number; max?: number };\n /** Filter by total (lifetime) volume range */\n volume?: { min?: number; max?: number };\n /** Filter by current liquidity range */\n liquidity?: { min?: number; max?: number };\n /** Filter by open interest range */\n openInterest?: { min?: number; max?: number };\n\n // Date filters\n resolutionDate?: {\n before?: Date;\n after?: Date;\n };\n\n // Category/tag filters\n /** Filter by category. Common values: \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Match markets that have ANY of these tags. Examples: [\"Crypto\", \"Crypto Prices\"], [\"Politics\", \"Elections\"], [\"Sports\", \"FIFA World Cup\"]. */\n tags?: string[];\n\n // Price filters (for binary markets)\n price?: {\n outcome: 'yes' | 'no' | 'up' | 'down';\n min?: number; // 0.0 to 1.0\n max?: number;\n };\n\n // Price change filters\n priceChange24h?: {\n outcome: 'yes' | 'no' | 'up' | 'down';\n min?: number; // e.g., -0.1 for 10% drop\n max?: number;\n };\n}\n\nexport type MarketFilterFunction = (market: UnifiedMarket) => boolean;\n\nexport interface EventFilterCriteria {\n // Text search\n text?: string;\n searchIn?: ('title' | 'description' | 'category' | 'tags')[]; // Default: ['title']\n\n // Category/tag filters\n /** Filter by category. Common values: \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Match events that have ANY of these tags. Examples: [\"Crypto\"], [\"Politics\", \"Geopolitics\", \"Middle East\"], [\"Sports\", \"FIFA World Cup\"]. */\n tags?: string[];\n\n // Filter by contained markets\n marketCount?: { min?: number; max?: number };\n totalVolume?: { min?: number; max?: number }; // Sum of market volumes\n}\n\nexport type EventFilterFunction = (event: UnifiedEvent) => boolean;\n\n// ----------------------------------------------------------------------------\n// Capability Map (ccxt-style exchange.has)\n// ----------------------------------------------------------------------------\n\nexport type ExchangeCapability = true | false | 'emulated';\n\nexport interface ExchangeHas {\n /** Whether this exchange supports fetching markets. */\n fetchMarkets: ExchangeCapability;\n /** Whether this exchange supports fetching events. */\n fetchEvents: ExchangeCapability;\n /** Whether this exchange exposes a recurring-series concept (Series -> Event -> Market -> Outcome). Venues without one return `false` and an empty array from `fetchSeries`. */\n fetchSeries: ExchangeCapability;\n /** Whether this exchange supports fetching OHLCV candles. */\n fetchOHLCV: ExchangeCapability;\n /** Whether this exchange supports fetching the order book. */\n fetchOrderBook: ExchangeCapability;\n /** Whether this exchange supports fetching multiple market order books. */\n fetchOrderBooks: ExchangeCapability;\n /** Whether this exchange supports fetching public trades. */\n fetchTrades: ExchangeCapability;\n /** Whether this exchange supports creating orders. */\n createOrder: ExchangeCapability;\n /** Whether this exchange supports cancelling orders. */\n cancelOrder: ExchangeCapability;\n /** Whether this exchange supports fetching a single order by id. */\n fetchOrder: ExchangeCapability;\n /** Whether this exchange supports fetching open orders. */\n fetchOpenOrders: ExchangeCapability;\n /** Whether this exchange supports fetching account positions. */\n fetchPositions: ExchangeCapability;\n /** Whether this exchange supports fetching account balances. */\n fetchBalance: ExchangeCapability;\n /** Whether this exchange supports subscribing to an on-chain address for updates. */\n watchAddress: ExchangeCapability;\n /** Whether this exchange supports unsubscribing from a watched address. */\n unwatchAddress: ExchangeCapability;\n /** Whether this exchange supports streaming order book updates. */\n watchOrderBook: ExchangeCapability;\n /** Whether this exchange supports batch-subscribing to multiple order book streams. */\n watchOrderBooks: ExchangeCapability;\n /** Whether this exchange supports unsubscribing from an order book stream. */\n unwatchOrderBook: ExchangeCapability;\n /** Whether this exchange supports streaming trade updates. */\n watchTrades: ExchangeCapability;\n /** Whether this exchange supports fetching the authenticated user's trade history. */\n fetchMyTrades: ExchangeCapability;\n /** Whether this exchange supports fetching closed orders. */\n fetchClosedOrders: ExchangeCapability;\n /** Whether this exchange supports fetching all orders (open and closed). */\n fetchAllOrders: ExchangeCapability;\n /** Whether this exchange supports building a signed order without submitting it. */\n buildOrder: ExchangeCapability;\n /** Whether this exchange supports submitting a pre-built order. */\n submitOrder: ExchangeCapability;\n /** Whether this exchange supports fetching cross-venue market matches. */\n fetchMarketMatches: ExchangeCapability;\n /** @deprecated Use {@link fetchMarketMatches} instead. */\n fetchMatches: ExchangeCapability;\n /** Whether this exchange supports fetching cross-venue event matches. */\n fetchEventMatches: ExchangeCapability;\n /** Whether this exchange supports comparing prices across venues. */\n compareMarketPrices: ExchangeCapability;\n /** Whether this exchange supports finding related markets across venues. */\n fetchRelatedMarkets: ExchangeCapability;\n /** Whether this exchange supports fetching matched markets across venues. */\n fetchMatchedMarkets: ExchangeCapability;\n /** @deprecated Use {@link fetchMatchedMarkets} instead. */\n fetchMatchedPrices: ExchangeCapability;\n /** @deprecated Use {@link fetchRelatedMarkets} instead. */\n fetchHedges: ExchangeCapability;\n /** @deprecated Use {@link fetchMatchedMarkets} instead. */\n fetchArbitrage: ExchangeCapability;\n}\n\n/**\nOptional authentication credentials for exchange operations.\n/\nexport interface ExchangeCredentials {\n // Standard API authentication (Kalshi, etc.)\n apiKey?: string;\n /** Standard API secret for HMAC-authenticated exchanges */\n apiSecret?: string;\n /** Standard API passphrase for HMAC-authenticated exchanges */\n passphrase?: string;\n /** Metaculus: `Authorization: Token ` for higher rate limits */\n apiToken?: string;\n\n // Blockchain-based authentication (Polymarket)\n privateKey?: string; // Required for Polymarket L1 auth\n\n // Polymarket-specific L2 fields\n signatureType?: number | string; // 0 = EOA, 1 = Poly Proxy, 2 = Gnosis Safe (Can also use 'eoa', 'polyproxy', 'gnosis_safe')\n funderAddress?: string; // The address funding the trades (defaults to signer address)\n\n // Limitless: wallet address for delegated signing profile lookup\n walletAddress?: string;\n\n // Optional base URL override for venue API (e.g., proxy for geo-restricted venues)\n baseUrl?: string;\n}\n\nexport interface ExchangeOptions {\n /**\nHow long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid\nbefore being discarded and re-fetched from the API on the next call.\nDefaults to 0 (no TTL — the snapshot is re-fetched on every initial call).\n/\n snapshotTTL?: number;\n}\n\n/** Shape returned by fetchMarketsPaginated */\nexport interface PaginatedMarketsResult {\n /** The page of unified markets */\n data: UnifiedMarket[];\n /** Total number of markets in the snapshot */\n total: number;\n /** Cursor to pass to the next call, or undefined if this is the last page */\n nextCursor?: string;\n}\n\n/** Shape returned by fetchEventsPaginated */\nexport interface PaginatedEventsResult {\n /** The page of unified events */\n data: UnifiedEvent[];\n /** Total number of events in the snapshot */\n total: number;\n /** Cursor to pass to the next call, or undefined if this is the last page */\n nextCursor?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Base Exchange Class\n// ----------------------------------------------------------------------------\n\nexport abstract class PredictionMarketExchange {\n [key: string]: any; // Allow dynamic method assignment for implicit API\n\n public verbose: boolean = false;\n public http: AxiosInstance;\n public enableRateLimit: boolean = true;\n // Market Cache\n public markets: Record = {};\n public marketsBySlug: Record = {};\n public loadedMarkets: boolean = false;\n /**\nCapability map derived automatically from method overrides at runtime.\nExchanges do NOT need to declare this manually -- if a subclass overrides\na method (and the override does not throw \"not supported\"), it is `true`.\nTo mark a capability as `'emulated'`, add its key to `emulatedCapabilities`.", + "description": "method: string;\n /** URL path template, relative to the descriptor's baseUrl. */\n path: string;\n /** Whether this endpoint requires authenticated credentials. */\n isPrivate?: boolean;\n /** Identifier used to generate the implicit API method name. */\n operationId?: string;\n /**\nWhen set, requests use this base URL instead of the descriptor default\n(OpenAPI path- or operation-level `servers` override).\n/\n baseUrl?: string;\n}\n\nexport interface ApiDescriptor {\n /** Base URL that all endpoint paths are resolved against. */\n baseUrl: string;\n /** Map of endpoint key to endpoint definition used by the implicit API machinery. */\n endpoints: Record;\n}\n\nexport interface ImplicitApiMethodInfo {\n /** Generated method name exposed on the exchange instance. */\n name: string;\n /** HTTP verb for the underlying endpoint. */\n method: string;\n /** URL path template for the underlying endpoint. */\n path: string;\n /** Whether the underlying endpoint requires authenticated credentials. */\n isPrivate: boolean;\n}\n\nexport interface MarketFilterParams {\n /** Maximum number of results to return */\n limit?: number;\n /** Pagination offset — number of results to skip */\n offset?: number;\n /** Sort order for results */\n sort?: 'volume' | 'liquidity' | 'newest';\n status?: 'active' | 'inactive' | 'closed' | 'all'; // Filter by market status (default: 'active', 'inactive' and 'closed' are interchangeable)\n searchIn?: 'title' | 'description' | 'both'; // Where to search (default: 'title')\n query?: string; // For keyword search\n slug?: string; // For slug/ticker lookup\n marketId?: string; // Direct lookup by market ID\n outcomeId?: string; // Reverse lookup -- find market containing this outcome\n eventId?: string; // Find markets belonging to an event\n page?: number; // For pagination (used by Limitless)\n similarityThreshold?: number; // For semantic search (used by Limitless)\n}\n\nexport interface MarketFetchParams extends MarketFilterParams {\n /** Optional client-side filter applied after fetching */\n filter?: MarketFilterCriteria;\n /** Filter by category. Each market belongs to a venue-assigned category such as \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Filter by tags. Returns markets matching ANY of the provided tags. Tags are more specific than categories -- for example a \"Sports\" market might carry tags [\"Sports\", \"FIFA World Cup\", \"2026 FIFA World Cup\"]. Common tags include \"Crypto\", \"Politics\", \"Elections\", \"Geopolitics\", \"Fed Rates\", \"Trump\". */\n tags?: string[];\n}\n\nexport interface EventFetchParams {\n query?: string; // For keyword search\n /** Maximum number of results to return */\n limit?: number;\n /** Opaque venue pagination cursor, where supported. */\n cursor?: string;\n /** Pagination offset — number of results to skip */\n offset?: number;\n /** Sort order for results */\n sort?: 'volume' | 'liquidity' | 'newest';\n status?: 'active' | 'inactive' | 'closed' | 'all'; // Filter by event status (default: 'active', 'inactive' and 'closed' are interchangeable)\n /** Where to search (default: 'title') */\n searchIn?: 'title' | 'description' | 'both';\n eventId?: string; // Direct lookup by event ID\n slug?: string; // Lookup by event slug\n /** Filter events by their parent series. Accepts the venue-native series id / ticker / slug (e.g. Kalshi `\"KXATPMATCH\"`, Polymarket `\"wta\"`). Passed through to the vendor where supported, otherwise applied to `sourceMetadata` after fetch. */\n series?: string;\n /** Optional client-side filter applied after fetching */\n filter?: EventFilterCriteria;\n /** Filter by category. Each event belongs to a venue-assigned category such as \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Filter by tags. Returns events matching ANY of the provided tags. Tags are more specific than categories -- for example a \"Politics\" event might carry tags [\"Politics\", \"Geopolitics\", \"Middle East\", \"Iran\"]. Common tags include \"Crypto\", \"Elections\", \"Fed Rates\", \"FIFA World Cup\", \"Trump\". */\n tags?: string[];\n}\n\n/**\nParameters for `fetchSeries`. Venues that don't expose a series concept\nreturn an empty array regardless of the filters.\n/\nexport interface SeriesFetchParams {\n /** Direct lookup by venue-native series id (e.g. \"KXATPMATCH\" on Kalshi, \"atp\" or \"1\" on Polymarket Gamma). When set, the result is the matching series with its events populated where the venue supports it. */\n id?: string;\n /** Lookup by series slug (e.g. \"wta\", \"nfl\"). */\n slug?: string;\n /** Keyword search across series title / description. */\n query?: string;\n /** Filter by recurrence cadence ('daily', 'weekly', 'annual', ...). */\n recurrence?: string;\n /** Maximum number of results to return. */\n limit?: number;\n /** Pagination offset. */\n offset?: number;\n}\n\n/**\nDeprecated - use OHLCVParams or TradesParams instead. Resolution is optional for backward compatibility.\n/\nexport interface HistoryFilterParams {\n resolution?: CandleInterval; // Optional for backward compatibility\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return */\n limit?: number;\n}\n\nexport interface OHLCVParams {\n resolution: CandleInterval; // Required for candle aggregation\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return */\n limit?: number;\n}\n\n/**\nParameters for fetching trade history. No resolution parameter - trades are discrete events.\n/\n/** Maximum allowed value for `TradesParams.limit`. */\nexport const MAX_TRADES_LIMIT = 1000;\n\nexport interface TradesParams {\n // No resolution - trades are discrete events, not aggregated\n /** Start of the time range */\n start?: Date;\n /** End of the time range */\n end?: Date;\n /** Maximum number of results to return (max {@link MAX_TRADES_LIMIT}) */\n limit?: number;\n}\n\nexport interface MyTradesParams {\n outcomeId?: string; // filter to specific outcome/ticker\n marketId?: string; // filter to specific market\n /** Only return records after this date */\n since?: Date;\n /** Only return records before this date */\n until?: Date;\n /** Maximum number of results to return */\n limit?: number;\n cursor?: string; // for Kalshi cursor pagination\n}\n\nexport interface FetchOrderBookParams {\n /** Outcome side: 'yes' or 'no'. Required for exchanges like Limitless\n where the API returns a single orderbook per market. */\n side?: 'yes' | 'no';\n /** Outcome alias: 'yes' or 'no', or an outcome token ID. When set,\n the first argument is treated as a market ID and this value selects\n which outcome's order book to fetch. Accepts the literal strings\n 'yes'/'no' (resolved via a market lookup) or a raw outcome token ID. */\n outcome?: string;\n /** Unix timestamp (ms) — fetch a historical snapshot at or before this\n time, or the start of a range when combined with `until` (hosted API only). */\n since?: number;\n /** Unix timestamp (ms) — end of a historical range. When combined with\n `since`, returns an array of reconstructed L2 OrderBook snapshots\n between `since` and `until` (hosted API only). */\n until?: number;\n}\n\nexport interface OrderHistoryParams {\n marketId?: string; // required for Limitless (slug)\n /** Only return records after this date */\n since?: Date;\n /** Only return records before this date */\n until?: Date;\n /** Maximum number of results to return */\n limit?: number;\n /** Opaque pagination cursor from a previous response */\n cursor?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Filtering Types\n// ----------------------------------------------------------------------------\n\nexport interface MarketFilterCriteria {\n // Text search\n text?: string;\n searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[]; // Default: ['title']\n\n // Numeric range filters\n volume24h?: { min?: number; max?: number };\n /** Filter by total (lifetime) volume range */\n volume?: { min?: number; max?: number };\n /** Filter by current liquidity range */\n liquidity?: { min?: number; max?: number };\n /** Filter by open interest range */\n openInterest?: { min?: number; max?: number };\n\n // Date filters\n resolutionDate?: {\n before?: Date;\n after?: Date;\n };\n\n // Category/tag filters\n /** Filter by category. Common values: \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Match markets that have ANY of these tags. Examples: [\"Crypto\", \"Crypto Prices\"], [\"Politics\", \"Elections\"], [\"Sports\", \"FIFA World Cup\"]. */\n tags?: string[];\n\n // Price filters (for binary markets)\n price?: {\n outcome: 'yes' | 'no' | 'up' | 'down';\n min?: number; // 0.0 to 1.0\n max?: number;\n };\n\n // Price change filters\n priceChange24h?: {\n outcome: 'yes' | 'no' | 'up' | 'down';\n min?: number; // e.g., -0.1 for 10% drop\n max?: number;\n };\n}\n\nexport type MarketFilterFunction = (market: UnifiedMarket) => boolean;\n\nexport interface EventFilterCriteria {\n // Text search\n text?: string;\n searchIn?: ('title' | 'description' | 'category' | 'tags')[]; // Default: ['title']\n\n // Category/tag filters\n /** Filter by category. Common values: \"Sports\", \"Politics\", \"Crypto\", \"Bitcoin\", \"Soccer\", \"Economic Policy\" (Polymarket) or \"Sports\", \"Mentions\" (Kalshi). */\n category?: string;\n /** Match events that have ANY of these tags. Examples: [\"Crypto\"], [\"Politics\", \"Geopolitics\", \"Middle East\"], [\"Sports\", \"FIFA World Cup\"]. */\n tags?: string[];\n\n // Filter by contained markets\n marketCount?: { min?: number; max?: number };\n totalVolume?: { min?: number; max?: number }; // Sum of market volumes\n}\n\nexport type EventFilterFunction = (event: UnifiedEvent) => boolean;\n\n// ----------------------------------------------------------------------------\n// Capability Map (ccxt-style exchange.has)\n// ----------------------------------------------------------------------------\n\nexport type ExchangeCapability = true | false | 'emulated';\n\nexport interface ExchangeHas {\n /** Whether this exchange supports fetching markets. */\n fetchMarkets: ExchangeCapability;\n /** Whether this exchange supports fetching events. */\n fetchEvents: ExchangeCapability;\n /** Whether this exchange exposes a recurring-series concept (Series -> Event -> Market -> Outcome). Venues without one return `false` and an empty array from `fetchSeries`. */\n fetchSeries: ExchangeCapability;\n /** Whether this exchange supports fetching OHLCV candles. */\n fetchOHLCV: ExchangeCapability;\n /** Whether this exchange supports fetching the order book. */\n fetchOrderBook: ExchangeCapability;\n /** Whether this exchange supports fetching multiple market order books. */\n fetchOrderBooks: ExchangeCapability;\n /** Whether this exchange supports fetching public trades. */\n fetchTrades: ExchangeCapability;\n /** Whether this exchange supports creating orders. */\n createOrder: ExchangeCapability;\n /** Whether this exchange supports cancelling orders. */\n cancelOrder: ExchangeCapability;\n /** Whether this exchange supports fetching a single order by id. */\n fetchOrder: ExchangeCapability;\n /** Whether this exchange supports fetching open orders. */\n fetchOpenOrders: ExchangeCapability;\n /** Whether this exchange supports fetching account positions. */\n fetchPositions: ExchangeCapability;\n /** Whether this exchange supports fetching account balances. */\n fetchBalance: ExchangeCapability;\n /** Whether this exchange supports subscribing to an on-chain address for updates. */\n watchAddress: ExchangeCapability;\n /** Whether this exchange supports unsubscribing from a watched address. */\n unwatchAddress: ExchangeCapability;\n /** Whether this exchange supports streaming order book updates. */\n watchOrderBook: ExchangeCapability;\n /** Whether this exchange supports batch-subscribing to multiple order book streams. */\n watchOrderBooks: ExchangeCapability;\n /** Whether this exchange supports unsubscribing from an order book stream. */\n unwatchOrderBook: ExchangeCapability;\n /** Whether this exchange supports streaming trade updates. */\n watchTrades: ExchangeCapability;\n /** Whether this exchange supports fetching the authenticated user's trade history. */\n fetchMyTrades: ExchangeCapability;\n /** Whether this exchange supports fetching closed orders. */\n fetchClosedOrders: ExchangeCapability;\n /** Whether this exchange supports fetching all orders (open and closed). */\n fetchAllOrders: ExchangeCapability;\n /** Whether this exchange supports building a signed order without submitting it. */\n buildOrder: ExchangeCapability;\n /** Whether this exchange supports submitting a pre-built order. */\n submitOrder: ExchangeCapability;\n /** Whether this exchange supports fetching cross-venue market matches. */\n fetchMarketMatches: ExchangeCapability;\n /** @deprecated Use {@link fetchMarketMatches} instead. */\n fetchMatches: ExchangeCapability;\n /** Whether this exchange supports fetching cross-venue event matches. */\n fetchEventMatches: ExchangeCapability;\n /** Whether this exchange supports comparing prices across venues. */\n compareMarketPrices: ExchangeCapability;\n /** Whether this exchange supports finding related markets across venues. */\n fetchRelatedMarkets: ExchangeCapability;\n /** Whether this exchange supports fetching matched markets across venues. */\n fetchMatchedMarkets: ExchangeCapability;\n /** @deprecated Use {@link fetchMatchedMarkets} instead. */\n fetchMatchedPrices: ExchangeCapability;\n /** @deprecated Use {@link fetchRelatedMarkets} instead. */\n fetchHedges: ExchangeCapability;\n /** @deprecated Use {@link fetchMatchedMarkets} instead. */\n fetchArbitrage: ExchangeCapability;\n}\n\n/**\nOptional authentication credentials for exchange operations.\n/\nexport interface ExchangeCredentials {\n // Standard API authentication (Kalshi, etc.)\n apiKey?: string;\n /** Standard API secret for HMAC-authenticated exchanges */\n apiSecret?: string;\n /** Standard API passphrase for HMAC-authenticated exchanges */\n passphrase?: string;\n /** Metaculus: `Authorization: Token ` for higher rate limits */\n apiToken?: string;\n\n // Blockchain-based authentication (Polymarket)\n privateKey?: string; // Required for Polymarket L1 auth\n\n // Polymarket-specific L2 fields\n signatureType?: number | string; // 0 = EOA, 1 = Poly Proxy, 2 = Gnosis Safe (Can also use 'eoa', 'polyproxy', 'gnosis_safe')\n funderAddress?: string; // The address funding the trades (defaults to signer address)\n\n // Limitless: wallet address for delegated signing profile lookup\n walletAddress?: string;\n\n // Optional base URL override for venue API (e.g., proxy for geo-restricted venues)\n baseUrl?: string;\n}\n\nexport interface ExchangeOptions {\n /**\nHow long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid\nbefore being discarded and re-fetched from the API on the next call.\nDefaults to 0 (no TTL — the snapshot is re-fetched on every initial call).\n/\n snapshotTTL?: number;\n}\n\n/** Shape returned by fetchMarketsPaginated */\nexport interface PaginatedMarketsResult {\n /** The page of unified markets */\n data: UnifiedMarket[];\n /** Total number of markets in the snapshot */\n total: number;\n /** Cursor to pass to the next call, or undefined if this is the last page */\n nextCursor?: string;\n}\n\n/** Shape returned by fetchEventsPaginated */\nexport interface PaginatedEventsResult {\n /** The page of unified events */\n data: UnifiedEvent[];\n /** Total number of events in the snapshot */\n total: number;\n /** Cursor to pass to the next call, or undefined if this is the last page */\n nextCursor?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Base Exchange Class\n// ----------------------------------------------------------------------------\n\nexport abstract class PredictionMarketExchange {\n [key: string]: any; // Allow dynamic method assignment for implicit API\n\n public verbose: boolean = false;\n public http: AxiosInstance;\n public enableRateLimit: boolean = true;\n // Market Cache\n public markets: Record = {};\n public marketsBySlug: Record = {};\n public loadedMarkets: boolean = false;\n /**\nCapability map derived automatically from method overrides at runtime.\nExchanges do NOT need to declare this manually -- if a subclass overrides\na method (and the override does not throw \"not supported\"), it is `true`.\nTo mark a capability as `'emulated'`, add its key to `emulatedCapabilities`.", "params": [], "returns": { "type": "ExchangeHas", @@ -19,7 +19,7 @@ "type": "ImplicitApiMethodInfo[]", "description": "Result" }, - "source": "BaseExchange.ts:459" + "source": "BaseExchange.ts:451" }, "loadMarkets": { "summary": "Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.", @@ -36,7 +36,7 @@ "type": "Record", "description": "Dictionary of markets indexed by marketId" }, - "source": "BaseExchange.ts:572" + "source": "BaseExchange.ts:564" }, "fetchMarkets": { "summary": "Fetch markets with optional filtering, search, or slug lookup.", @@ -83,7 +83,7 @@ "ordering — exchanges may reorder or add markets between requests. For stable iteration\nacross pages, use `loadMarkets()` and paginate over `Object.values(exchange.markets)`.", "Some exchanges (like Limitless) may only support status 'active' for search results." ], - "source": "BaseExchange.ts:609" + "source": "BaseExchange.ts:601" }, "fetchMarketsPaginated": { "summary": "Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.", @@ -110,7 +110,7 @@ "type": "PaginatedMarketsResult", "description": "PaginatedMarketsResult with data, total, and optional nextCursor" }, - "source": "BaseExchange.ts:664" + "source": "BaseExchange.ts:650" }, "fetchEventsPaginated": { "summary": "Paginated variant of {@link fetchEvents}.", @@ -137,7 +137,7 @@ "type": "PaginatedEventsResult", "description": "PaginatedEventsResult with data, total, and optional nextCursor" }, - "source": "BaseExchange.ts:733" + "source": "BaseExchange.ts:719" }, "fetchEvents": { "summary": "Fetch events with optional keyword search.", @@ -175,7 +175,7 @@ "notes": [ "Some exchanges (like Limitless) may only support status 'active' for search results." ], - "source": "BaseExchange.ts:802" + "source": "BaseExchange.ts:788" }, "fetchSeries": { "summary": "Fetch the recurring series (fourth tier above Event -> Market -> Outcome)", @@ -192,7 +192,7 @@ "type": "UnifiedSeries[]", "description": "Array of unified series. Always an array, including the singular-lookup case." }, - "source": "BaseExchange.ts:841" + "source": "BaseExchange.ts:823" }, "fetchMarket": { "summary": "Fetch a single market by lookup parameters.", @@ -209,7 +209,7 @@ "type": "UnifiedMarket", "description": "A single unified market" }, - "source": "BaseExchange.ts:859" + "source": "BaseExchange.ts:841" }, "fetchEvent": { "summary": "Fetch a single event by lookup parameters.", @@ -226,24 +226,7 @@ "type": "UnifiedEvent", "description": "A single unified event" }, - "source": "BaseExchange.ts:959" - }, - "fetchEventMetadata": { - "summary": "Fetch venue-native metadata for a specific event when the exchange", - "description": "exposes a dedicated metadata endpoint.\n\nKalshi implements this for `GET /events/{event_ticker}/metadata`.", - "params": [ - { - "name": "eventTicker", - "type": "string", - "optional": false, - "description": "eventTicker" - } - ], - "returns": { - "type": "Record", - "description": "Result" - }, - "source": "BaseExchange.ts:976" + "source": "BaseExchange.ts:941" }, "fetchOHLCV": { "summary": "Fetch historical OHLCV (candlestick) price data for a specific market outcome.", @@ -271,7 +254,7 @@ "Polymarket: outcomeId is the CLOB Token ID. Kalshi: outcomeId is the Market Ticker.", "Common resolutions: '1m' | '5m' | '15m' | '1h' | '6h' | '1d'. Arbitrary intervals (e.g. '30s', '120s', '3h') accepted by venues that support them." ], - "source": "BaseExchange.ts:987" + "source": "BaseExchange.ts:958" }, "fetchOrderBook": { "summary": "Fetch the order book (bids/asks) for a specific outcome.", @@ -300,7 +283,7 @@ "type": "OrderBook", "description": "Order book with bids and asks. Returns OrderBook[] when" }, - "source": "BaseExchange.ts:1002" + "source": "BaseExchange.ts:973" }, "fetchOrderBooks": { "summary": "Batch variant of {@link fetchOrderBook}. Fetches order books for", @@ -317,7 +300,7 @@ "type": "Record", "description": "A map keyed by the input id (preserving the caller's exact" }, - "source": "BaseExchange.ts:1030" + "source": "BaseExchange.ts:1001" }, "fetchTrades": { "summary": "Fetch raw trade history for a specific outcome.", @@ -343,7 +326,7 @@ "notes": [ "Polymarket requires an API key for trade history. Use fetchOHLCV for public historical data." ], - "source": "BaseExchange.ts:1043" + "source": "BaseExchange.ts:1014" }, "createOrder": { "summary": "Place a new order on the exchange.", @@ -360,7 +343,7 @@ "type": "Order", "description": "The created order" }, - "source": "BaseExchange.ts:1060" + "source": "BaseExchange.ts:1031" }, "buildOrder": { "summary": "Build an order payload without submitting it to the exchange.", @@ -377,7 +360,7 @@ "type": "BuiltOrder", "description": "A BuiltOrder containing the exchange-native payload" }, - "source": "BaseExchange.ts:1074" + "source": "BaseExchange.ts:1045" }, "submitOrder": { "summary": "Submit a pre-built order returned by buildOrder().", @@ -394,7 +377,7 @@ "type": "Order", "description": "The submitted order" }, - "source": "BaseExchange.ts:1086" + "source": "BaseExchange.ts:1057" }, "cancelOrder": { "summary": "Cancel an existing open order.", @@ -411,7 +394,7 @@ "type": "Order", "description": "The cancelled order" }, - "source": "BaseExchange.ts:1096" + "source": "BaseExchange.ts:1067" }, "fetchOrder": { "summary": "Fetch a specific order by ID.", @@ -428,7 +411,7 @@ "type": "Order", "description": "The order details" }, - "source": "BaseExchange.ts:1106" + "source": "BaseExchange.ts:1077" }, "fetchOpenOrders": { "summary": "Fetch all open orders, optionally filtered by market.", @@ -445,128 +428,7 @@ "type": "Order[]", "description": "Array of open orders" }, - "source": "BaseExchange.ts:1116" - }, - "fetchMyTrades": { - "summary": "Fetch authenticated user trade history.", - "description": "Fetch authenticated user trade history.", - "params": [ - { - "name": "params", - "type": "MyTradesParams", - "optional": true, - "description": "Optional trade history filters" - } - ], - "subParams": [ - { - "name": "params.outcomeId", - "description": "Filter by outcome token ID" - }, - { - "name": "params.marketId", - "description": "Filter by market ID or ticker" - }, - { - "name": "params.since", - "description": "Start timestamp or ISO date" - }, - { - "name": "params.until", - "description": "End timestamp or ISO date" - }, - { - "name": "params.limit", - "description": "Maximum number of trades" - }, - { - "name": "params.cursor", - "description": "Pagination cursor" - } - ], - "returns": { - "type": "UserTrade[]", - "description": "Array of user trades" - }, - "source": "BaseExchange.ts:1126" - }, - "fetchClosedOrders": { - "summary": "Fetch authenticated closed orders.", - "description": "Fetch authenticated closed orders.", - "params": [ - { - "name": "params", - "type": "OrderHistoryParams", - "optional": true, - "description": "Optional order history filters" - } - ], - "subParams": [ - { - "name": "params.marketId", - "description": "Filter by market ID or ticker" - }, - { - "name": "params.since", - "description": "Start timestamp or ISO date" - }, - { - "name": "params.until", - "description": "End timestamp or ISO date" - }, - { - "name": "params.limit", - "description": "Maximum number of orders" - }, - { - "name": "params.cursor", - "description": "Pagination cursor" - } - ], - "returns": { - "type": "Order[]", - "description": "Array of closed orders" - }, - "source": "BaseExchange.ts:1142" - }, - "fetchAllOrders": { - "summary": "Fetch authenticated order history across open and closed orders.", - "description": "Fetch authenticated order history across open and closed orders.", - "params": [ - { - "name": "params", - "type": "OrderHistoryParams", - "optional": true, - "description": "Optional order history filters" - } - ], - "subParams": [ - { - "name": "params.marketId", - "description": "Filter by market ID or ticker" - }, - { - "name": "params.since", - "description": "Start timestamp or ISO date" - }, - { - "name": "params.until", - "description": "End timestamp or ISO date" - }, - { - "name": "params.limit", - "description": "Maximum number of orders" - }, - { - "name": "params.cursor", - "description": "Pagination cursor" - } - ], - "returns": { - "type": "Order[]", - "description": "Array of orders" - }, - "source": "BaseExchange.ts:1157" + "source": "BaseExchange.ts:1087" }, "fetchPositions": { "summary": "Fetch current user positions across all markets.", @@ -583,7 +445,7 @@ "type": "Position[]", "description": "Array of user positions" }, - "source": "BaseExchange.ts:1172" + "source": "BaseExchange.ts:1109" }, "fetchBalance": { "summary": "Fetch account balances.", @@ -600,7 +462,7 @@ "type": "Balance[]", "description": "Array of account balances" }, - "source": "BaseExchange.ts:1182" + "source": "BaseExchange.ts:1119" }, "getExecutionPrice": { "summary": "Calculate the volume-weighted average execution price for a given order size.", @@ -629,7 +491,7 @@ "type": "number", "description": "Average execution price, or 0 if insufficient liquidity" }, - "source": "BaseExchange.ts:1192" + "source": "BaseExchange.ts:1129" }, "getExecutionPriceDetailed": { "summary": "Calculate detailed execution price information including partial fill data.", @@ -658,7 +520,7 @@ "type": "ExecutionPriceResult", "description": "Detailed execution result with price, filled amount, and fill status" }, - "source": "BaseExchange.ts:1205" + "source": "BaseExchange.ts:1142" }, "filterMarkets": { "summary": "Filter a list of markets by criteria.", @@ -681,7 +543,7 @@ "type": "UnifiedMarket[]", "description": "Filtered array of markets" }, - "source": "BaseExchange.ts:1221" + "source": "BaseExchange.ts:1158" }, "filterEvents": { "summary": "Filter a list of events by criteria.", @@ -704,7 +566,7 @@ "type": "UnifiedEvent[]", "description": "Filtered array of events" }, - "source": "BaseExchange.ts:1381" + "source": "BaseExchange.ts:1318" }, "watchOrderBook": { "summary": "Watch order book updates in real-time via WebSocket.", @@ -733,7 +595,7 @@ "type": "OrderBook", "description": "Promise that resolves with the current orderbook state" }, - "source": "BaseExchange.ts:1477" + "source": "BaseExchange.ts:1414" }, "watchOrderBooks": { "summary": "Watch multiple order books simultaneously via WebSocket.", @@ -762,7 +624,7 @@ "type": "Record", "description": "Promise that resolves with order books keyed by ID" }, - "source": "BaseExchange.ts:1490" + "source": "BaseExchange.ts:1427" }, "unwatchOrderBook": { "summary": "Unsubscribe from a previously watched order book stream.", @@ -779,7 +641,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1518" + "source": "BaseExchange.ts:1455" }, "watchTrades": { "summary": "Watch trade executions in real-time via WebSocket.", @@ -814,7 +676,7 @@ "type": "Trade[]", "description": "Promise that resolves with recent trades" }, - "source": "BaseExchange.ts:1531" + "source": "BaseExchange.ts:1468" }, "watchAddress": { "summary": "Stream activity for a public wallet address", @@ -837,7 +699,7 @@ "type": "SubscribedAddressSnapshot", "description": "Promise that resolves with the latest SubscribedAddressSnapshot snapshot" }, - "source": "BaseExchange.ts:1545" + "source": "BaseExchange.ts:1482" }, "unwatchAddress": { "summary": "Stop watching a previously registered wallet address and release its resource updates.", @@ -854,7 +716,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1558" + "source": "BaseExchange.ts:1495" }, "close": { "summary": "Close all WebSocket connections and clean up resources.", @@ -864,7 +726,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1567" + "source": "BaseExchange.ts:1504" }, "fetchMarketMatches": { "summary": "Find the same or related market on other venues. Two modes:", @@ -881,7 +743,7 @@ "type": "MatchResult[]", "description": "Array of matched markets with relation and confidence" }, - "source": "BaseExchange.ts:1581" + "source": "BaseExchange.ts:1518" }, "fetchMatches": { "summary": "fetchMatches", @@ -898,7 +760,7 @@ "type": "MatchResult[]", "description": "Result" }, - "source": "BaseExchange.ts:1597" + "source": "BaseExchange.ts:1534" }, "fetchEventMatches": { "summary": "Find the same or related event on other venues. Two modes:", @@ -915,7 +777,7 @@ "type": "EventMatchResult[]", "description": "Array of matched events with market-level match details" }, - "source": "BaseExchange.ts:1605" + "source": "BaseExchange.ts:1542" }, "compareMarketPrices": { "summary": "Compare live prices for the same market across venues. Finds identity matches and returns side-by-side best bid/ask prices so you can spot price differences at a glance.", @@ -932,7 +794,7 @@ "type": "PriceComparison[]", "description": "Array of price comparisons across venues" }, - "source": "BaseExchange.ts:1621" + "source": "BaseExchange.ts:1558" }, "fetchRelatedMarkets": { "summary": "Find related markets across venues. Discovers subset/superset market relationships", @@ -949,7 +811,7 @@ "type": "PriceComparison[]", "description": "Array of subset/superset matches with live prices" }, - "source": "BaseExchange.ts:1631" + "source": "BaseExchange.ts:1568" }, "fetchMatchedMarkets": { "summary": "fetchMatchedMarkets", @@ -966,7 +828,7 @@ "type": "MatchedMarketPair[]", "description": "Result" }, - "source": "BaseExchange.ts:1642" + "source": "BaseExchange.ts:1579" }, "fetchMatchedPrices": { "summary": "fetchMatchedPrices", @@ -983,7 +845,7 @@ "type": "MatchedPricePair[]", "description": "Array of matched market pairs with prices from each venue" }, - "source": "BaseExchange.ts:1650" + "source": "BaseExchange.ts:1587" }, "fetchHedges": { "summary": "fetchHedges", @@ -1000,7 +862,7 @@ "type": "PriceComparison[]", "description": "Array of subset/superset matches with live prices" }, - "source": "BaseExchange.ts:1661" + "source": "BaseExchange.ts:1598" }, "fetchArbitrage": { "summary": "fetchArbitrage", @@ -1017,7 +879,7 @@ "type": "ArbitrageOpportunity[]", "description": "Array of arbitrage opportunities sorted by spread" }, - "source": "BaseExchange.ts:1671" + "source": "BaseExchange.ts:1608" }, "watchPrices": { "summary": "Watch AMM price updates for a market address (Limitless only).", @@ -1041,7 +903,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:492" + "source": "index.ts:488" }, "watchUserPositions": { "summary": "Watch user positions in real-time (Limitless only).", @@ -1059,7 +921,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:504" + "source": "index.ts:500" }, "watchUserTransactions": { "summary": "Watch user transactions in real-time (Limitless only).", @@ -1077,7 +939,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:516" + "source": "index.ts:512" }, "initAuth": { "summary": "Initialize L2 API credentials for implicit API signing.", @@ -1124,7 +986,7 @@ "description": "The UnifiedEvent, or null if not found" }, "exchangeOnly": "probable", - "source": "index.ts:152" + "source": "index.ts:151" }, "getEventBySlug": { "summary": "Fetch a single event by its URL slug (Probable only).", @@ -1142,45 +1004,11 @@ "description": "The UnifiedEvent, or null if not found" }, "exchangeOnly": "probable", - "source": "index.ts:171" - }, - "watchAllOrderBooks": { - "summary": "Stream all orderbook updates across venues via the hosted WebSocket API.", - "description": "Returns a promise that resolves with the next book event.\nCall repeatedly in a loop to stream updates (CCXT Pro pattern).\nRequires hosted mode (`pmxtApiKey` set).", - "params": [ - { - "name": "venues", - "type": "string[]", - "optional": true, - "description": "Optional venue filter. Defaults to this exchange's venue" - } - ], - "returns": { - "type": "FirehoseEvent", - "description": "Next event with source, symbol, and orderbook" - }, - "source": "client.ts:2057" - }, - "firehose": { - "summary": "Stream all orderbook updates across venues.", - "description": "Stream all orderbook updates across venues.", - "params": [ - { - "name": "venues", - "type": "string[]", - "optional": true, - "description": "Optional venue filter" - } - ], - "returns": { - "type": "FirehoseEvent", - "description": "Next event with source, symbol, and orderbook" - }, - "source": "client.ts:2098" + "source": "index.ts:170" } }, "workflowExample": { "python": "import pmxt\nimport os\n\nexchange = pmxt.Polymarket(\n private_key=os.getenv('POLYMARKET_PRIVATE_KEY')\n)\n\n# 1. Check balance\nbalances = exchange.fetch_balance()\nif balances:\n balance = balances[0]\n print(f'Available: ${balance.available}')\n\n# 2. Search for a market\nmarkets = exchange.fetch_markets(query='Trump')\nmarket = markets[0]\noutcome = market.yes\n\nprint(f'{market.title}')\nprint(f'Price: {outcome.price * 100:.1f}%')\n\n# 3. Place a limit order\norder = exchange.create_order(\n market_id=market.market_id,\n outcome_id=outcome.outcome_id,\n side='buy',\n type='limit',\n amount=10,\n price=0.50\n)\n\nprint(f'Order placed: {order.id}')\n\n# 4. Check order status\nupdated_order = exchange.fetch_order(order.id)\nprint(f'Status: {updated_order.status}')\nprint(f'Filled: {updated_order.filled}/{updated_order.amount}')\n\n# 5. Cancel if needed\nif updated_order.status == 'open':\n exchange.cancel_order(order.id)\n print('Order cancelled')\n\n# 6. Check positions\npositions = exchange.fetch_positions()\nfor pos in positions:\n pnl_sign = '+' if pos.unrealized_pnl > 0 else ''\n print(f'{pos.outcome_label}: {pnl_sign}${pos.unrealized_pnl:.2f}')", - "typescript": "import pmxt from 'pmxtjs';\n\nconst exchange = new pmxt.Polymarket({\n privateKey: process.env.POLYMARKET_PRIVATE_KEY\n});\n\n// 1. Check balance\nconst [balance] = await exchange.fetchBalance();\nconsole.log(`Available: $${balance.available}`);\n\n// 2. Search for a market\nconst markets = await exchange.fetchMarkets({ query: 'Trump' });\nconst market = markets[0];\nconst outcome = market.yes;\nif (!outcome) {\n throw new Error('Market has no YES outcome');\n}\n\nconsole.log(market.title);\nconsole.log(`Price: ${(outcome.price * 100).toFixed(1)}%`);\n\n// 3. Place a limit order\nconst order = await exchange.createOrder({\n outcome,\n side: 'buy',\n type: 'limit',\n amount: 10,\n price: 0.50\n});\n\nconsole.log(`Order placed: ${order.id}`);\n\n// 4. Check order status\nconst updatedOrder = await exchange.fetchOrder(order.id);\nconsole.log(`Status: ${updatedOrder.status}`);\nconsole.log(`Filled: ${updatedOrder.filled}/${updatedOrder.amount}`);\n\n// 5. Cancel if needed\nif (updatedOrder.status === 'open') {\n await exchange.cancelOrder(order.id);\n console.log('Order cancelled');\n}\n\n// 6. Check positions\nconst positions = await exchange.fetchPositions();\npositions.forEach(pos => {\n console.log(`${pos.outcomeLabel}: ${pos.unrealizedPnL > 0 ? '+' : ''}$${pos.unrealizedPnL.toFixed(2)}`);\n});" + "typescript": "import pmxt from 'pmxtjs';\n\nconst exchange = new pmxt.Polymarket({\n privateKey: process.env.POLYMARKET_PRIVATE_KEY\n});\n\n// 1. Check balance\nconst [balance] = await exchange.fetchBalance();\nconsole.log(`Available: $${balance.available}`);\n\n// 2. Search for a market\nconst markets = await exchange.fetchMarkets({ query: 'Trump' });\nconst market = markets[0];\nconst outcome = market.yes;\n\nconsole.log(market.title);\nconsole.log(`Price: ${(outcome.price * 100).toFixed(1)}%`);\n\n// 3. Place a limit order\nconst order = await exchange.createOrder({\n marketId: market.marketId,\n outcomeId: outcome.outcomeId,\n side: 'buy',\n type: 'limit',\n amount: 10,\n price: 0.50\n});\n\nconsole.log(`Order placed: ${order.id}`);\n\n// 4. Check order status\nconst updatedOrder = await exchange.fetchOrder(order.id);\nconsole.log(`Status: ${updatedOrder.status}`);\nconsole.log(`Filled: ${updatedOrder.filled}/${updatedOrder.amount}`);\n\n// 5. Cancel if needed\nif (updatedOrder.status === 'open') {\n await exchange.cancelOrder(order.id);\n console.log('Order cancelled');\n}\n\n// 6. Check positions\nconst positions = await exchange.fetchPositions();\npositions.forEach(pos => {\n console.log(`${pos.outcomeLabel}: ${pos.unrealizedPnL > 0 ? '+' : ''}$${pos.unrealizedPnL.toFixed(2)}`);\n});" } } \ No newline at end of file diff --git a/core/src/exchanges/baozi/errors.ts b/core/src/exchanges/baozi/errors.ts index 15b1bc09..106c411a 100644 --- a/core/src/exchanges/baozi/errors.ts +++ b/core/src/exchanges/baozi/errors.ts @@ -12,11 +12,11 @@ import { const PROGRAM_ERRORS: Record = { 6000: { type: 'bad_request', message: 'Unauthorized' }, 6001: { type: 'bad_request', message: 'Market not found' }, + 6013: { type: 'bad_request', message: 'Betting is closed' }, // Changed from 6018 + 6014: { type: 'bad_request', message: 'Betting is frozen' }, // Changed from 6040 6015: { type: 'bad_request', message: 'Market is not open for betting' }, - 6018: { type: 'bad_request', message: 'Betting is closed' }, - 6020: { type: 'invalid_order', message: 'Bet amount too small' }, - 6040: { type: 'bad_request', message: 'Betting is frozen' }, - 6041: { type: 'invalid_order', message: 'Bet amount too large' }, + 6023: { type: 'invalid_order', message: 'Bet amount too small' }, // Changed from 6020 + 6024: { type: 'invalid_order', message: 'Bet amount too large' }, // Changed from 6041 }; /** diff --git a/sdks/python/pmxt/client.py b/sdks/python/pmxt/client.py index dcf32247..b810c031 100644 --- a/sdks/python/pmxt/client.py +++ b/sdks/python/pmxt/client.py @@ -843,11 +843,7 @@ def _hosted_cancel_validation_routes(self) -> Tuple[str, Optional[str]]: return "cancel_polymarket", None if self.exchange_name == "opinion": return "cancel_opinion_polygon", "cancel_opinion_bsc_pull" - if self.exchange_name == "limitless": - return "cancel_limitless_polygon", "cancel_limitless_base_pull" - raise NotSupported( - "Hosted trading is only supported for Polymarket, Opinion, and Limitless." - ) + raise NotSupported("Hosted trading is only supported for Polymarket and Opinion.") @staticmethod def _hosted_typed_data(payload: Dict[str, Any], key: str) -> Dict[str, Any]: @@ -1193,7 +1189,7 @@ def has(self) -> Dict[str, Any]: # Low-Level API Access - def _call_method(self, method_name: str, params: Any = None) -> Any: + def _call_method(self, method_name: str, params: Optional[Dict[str, Any]] = None) -> Any: """Call any exchange method on the server by name.""" try: url = f"{self._resolve_sidecar_host()}/api/{self.exchange_name}/{method_name}" @@ -1423,11 +1419,9 @@ def fetch_series(self, params: Optional[dict] = None, **kwargs) -> List[UnifiedS except ApiException as e: raise self._parse_api_exception(e) from None - def fetch_market(self, params: Optional[Union[dict, str]] = None, **kwargs) -> UnifiedMarket: + def fetch_market(self, params: Optional[dict] = None, **kwargs) -> UnifiedMarket: try: args = [] - if isinstance(params, str): - params = {"market_id": params} if kwargs: params = {**(params or {}), **kwargs} if params is not None: @@ -1491,7 +1485,7 @@ def fetch_event_metadata(self, event_ticker: str) -> Dict[str, Any]: except ApiException as e: raise self._parse_api_exception(e) from None - def fetch_order_book(self, outcome_id: Union[str, "MarketOutcome"] = _UNSET, limit: Optional[float] = None, params: Optional[FetchOrderBookParams] = None, **kwargs) -> Union[OrderBook, List[OrderBook]]: + def fetch_order_book(self, outcome_id: Union[str, "MarketOutcome"] = _UNSET, limit: Optional[float] = None, params: Optional[dict] = None, **kwargs) -> Union[OrderBook, List[OrderBook]]: try: args = [] if kwargs: @@ -1543,8 +1537,6 @@ def fetch_order_books(self, outcome_ids: List[Union[str, "MarketOutcome"]]) -> D raise self._parse_api_exception(e) from None def cancel_order(self, order_id: str) -> Order: - if self.is_hosted: - return self._hosted_cancel_order(order_id) try: args = [] args.append(order_id) @@ -1565,12 +1557,6 @@ def cancel_order(self, order_id: str) -> Order: raise self._parse_api_exception(e) from None def fetch_order(self, order_id: str) -> Order: - if self.is_hosted: - response = self._hosted_request( - "fetch_order", - path_params={"order_id": order_id}, - ) - return self._hosted_single(response, "order", order_from_v0) try: args = [] args.append(order_id) @@ -1591,16 +1577,6 @@ def fetch_order(self, order_id: str) -> Order: raise self._parse_api_exception(e) from None def fetch_open_orders(self, market_id: Optional[str] = None) -> List[Order]: - if self.is_hosted: - resolved_address = resolve_wallet_address(self, None) - params: Dict[str, Any] = {"address": resolved_address} - if market_id is not None: - params["market_id"] = market_id - response = self._hosted_request( - "fetch_open_orders", - params=params, - ) - return self._hosted_collection(response, "orders", order_from_v0) try: args = [] if market_id is not None: @@ -1622,13 +1598,6 @@ def fetch_open_orders(self, market_id: Optional[str] = None) -> List[Order]: raise self._parse_api_exception(e) from None def fetch_my_trades(self, params: Optional[dict] = None, **kwargs) -> List[UserTrade]: - if self.is_hosted: - resolved_address = resolve_wallet_address(self, None) - response = self._hosted_request( - "fetch_my_trades", - path_params={"address": resolved_address}, - ) - return self._hosted_collection(response, "trades", user_trade_from_v0) try: args = [] if kwargs: @@ -1652,12 +1621,6 @@ def fetch_my_trades(self, params: Optional[dict] = None, **kwargs) -> List[UserT raise self._parse_api_exception(e) from None def fetch_closed_orders(self, params: Optional[dict] = None, **kwargs) -> List[Order]: - if self.is_hosted: - from pmxt.errors import NotSupported - raise NotSupported( - "fetch_closed_orders is not supported in hosted mode; " - "use fetch_my_trades to see executed fills instead.", - ) try: args = [] if kwargs: @@ -1681,12 +1644,6 @@ def fetch_closed_orders(self, params: Optional[dict] = None, **kwargs) -> List[O raise self._parse_api_exception(e) from None def fetch_all_orders(self, params: Optional[dict] = None, **kwargs) -> List[Order]: - if self.is_hosted: - from pmxt.errors import NotSupported - raise NotSupported( - "fetch_all_orders is not supported in hosted mode; " - "use fetch_open_orders + fetch_my_trades to reconstruct order history.", - ) try: args = [] if kwargs: @@ -1710,13 +1667,6 @@ def fetch_all_orders(self, params: Optional[dict] = None, **kwargs) -> List[Orde raise self._parse_api_exception(e) from None def fetch_positions(self, address: Optional[str] = None) -> List[Position]: - if self.is_hosted: - resolved_address = resolve_wallet_address(self, address) - response = self._hosted_request( - "fetch_positions", - path_params={"address": resolved_address}, - ) - return self._hosted_collection(response, "positions", position_from_v0) try: args = [] if address is not None: @@ -1738,13 +1688,6 @@ def fetch_positions(self, address: Optional[str] = None) -> List[Position]: raise self._parse_api_exception(e) from None def fetch_balance(self, address: Optional[str] = None) -> List[Balance]: - if self.is_hosted: - resolved_address = resolve_wallet_address(self, address) - response = self._hosted_request( - "fetch_balance", - path_params={"address": resolved_address}, - ) - return self._hosted_collection(response, "balances", balance_from_v0) try: args = [] if address is not None: @@ -1767,8 +1710,10 @@ def fetch_balance(self, address: Optional[str] = None) -> List[Balance]: def unwatch_order_book(self, outcome_id: Union[str, "MarketOutcome"] = _UNSET, **_compat_kwargs) -> None: try: + args = [] outcome_id = _compat_id(outcome_id, _compat_kwargs) - body: dict = {"args": [_resolve_outcome_id(outcome_id)]} + args.append(_resolve_outcome_id(outcome_id)) + body: dict = {"args": args} creds = self._get_credentials_dict() if creds: body["credentials"] = creds @@ -2296,7 +2241,7 @@ def fetch_ohlcv( params_dict[key] = value args = [outcome_id, params_dict] - query = {"outcomeId": outcome_id, **params_dict} + query = {"id": outcome_id, **params_dict} data = self._handle_response( self._sidecar_read_request("fetchOHLCV", query, args) ) @@ -2356,7 +2301,7 @@ def fetch_trades( params_dict[key] = value args = [outcome_id, params_dict] - query = {"outcomeId": outcome_id, **params_dict} + query = {"id": outcome_id, **params_dict} data = self._handle_response( self._sidecar_read_request("fetchTrades", query, args) ) @@ -2905,45 +2850,6 @@ def watch_user_transactions(self, callback: Optional[Callable[[Dict[str, Any]], except ApiException as e: raise self._parse_api_exception(e) from None - def pre_warm_market(self, outcome_id: str) -> None: - """ - Pre-warm the SDK's internal caches for a market outcome. - - Args: - outcome_id: The CLOB Token ID for the outcome - - Returns: - None - """ - self._call_method("preWarmMarket", outcome_id) - return None - - def get_event_by_id(self, id: str) -> Optional[UnifiedEvent]: - """ - Fetch a single Probable event by its numeric ID. - - Args: - id: The numeric event ID - - Returns: - The event, or None if not found - """ - data = self._call_method("getEventById", id) - return _convert_event(data) if data is not None else None - - def get_event_by_slug(self, slug: str) -> Optional[UnifiedEvent]: - """ - Fetch a single Probable event by its URL slug. - - Args: - slug: The event slug - - Returns: - The event, or None if not found - """ - data = self._call_method("getEventBySlug", slug) - return _convert_event(data) if data is not None else None - # Trading Methods (require authentication) def _discover_hosted_account(self) -> dict: @@ -3426,31 +3332,38 @@ def get_execution_price_detailed( Returns: Detailed execution result """ - if amount <= 0: - raise ValueError("Amount must be greater than 0") + try: + # Convert order_book to dict for API call + bids = [{"price": b.price, "size": b.size} for b in order_book.bids] + asks = [{"price": a.price, "size": a.size} for a in order_book.asks] + ob_dict = {"bids": bids, "asks": asks, "timestamp": order_book.timestamp} - levels = [level for level in (order_book.asks if side == "buy" else order_book.bids) if level.size > 0] - levels.sort(key=lambda level: level.price, reverse=(side == "sell")) + body = { + "args": [ob_dict, side, amount] + } - if not levels: - return ExecutionPriceResult(price=0, filled_amount=0, fully_filled=False) + creds = self._get_credentials_dict() + if creds: + body["credentials"] = creds - remaining_amount = amount - total_cost = 0.0 - filled_amount = 0.0 - epsilon = 0.00000001 + url = f"{self._resolve_sidecar_host()}/api/{self.exchange_name}/getExecutionPriceDetailed" - for level in levels: - if remaining_amount <= epsilon: - break + headers = {"Content-Type": "application/json", "Accept": "application/json"} + headers.update(self._get_auth_headers()) + + response = self._fetch_with_retry( + lambda: self._api_client.call_api( + method="POST", + url=url, + body=body, + header_params=headers + ) + ) - fill_size = min(remaining_amount, level.size) - total_cost += fill_size * level.price - filled_amount += fill_size - remaining_amount -= fill_size + response.read() + data_json = json.loads(response.data) - return ExecutionPriceResult( - price=total_cost / filled_amount if filled_amount > epsilon else 0, - filled_amount=filled_amount, - fully_filled=remaining_amount <= epsilon, - ) + data = self._handle_response(data_json) + return _convert_execution_result(data) + except Exception as e: + raise self._parse_api_exception(e) from None diff --git a/sdks/typescript/pmxt/client.ts b/sdks/typescript/pmxt/client.ts index b6e8e806..f67e6ae5 100644 --- a/sdks/typescript/pmxt/client.ts +++ b/sdks/typescript/pmxt/client.ts @@ -1747,7 +1747,7 @@ export abstract class Exchange { } } - async fetchMatchedMarkets(params?: FetchMatchedMarketClustersParams): Promise { + async fetchMatchedMarkets(params?: any): Promise { await this.initPromise; try { const args: any[] = [];