diff --git a/sdks/python/pmxt/__init__.py b/sdks/python/pmxt/__init__.py index 24e53837..28e8495e 100644 --- a/sdks/python/pmxt/__init__.py +++ b/sdks/python/pmxt/__init__.py @@ -56,6 +56,8 @@ PaginatedEventsResult, Order, BuiltOrder, + CreateOrderParams, + TxPayload, Position, Balance, MarketFilterCriteria, @@ -78,6 +80,7 @@ PriceComparison, ArbitrageOpportunity, SubscribedAddressSnapshot, + SubscriptionOption, ExecutionPriceResult, MatchRelation, ClusterSortOption, @@ -225,6 +228,8 @@ def restart_server() -> None: "PaginatedEventsResult", "Order", "BuiltOrder", + "CreateOrderParams", + "TxPayload", "ExecutionPriceResult", "Position", "Balance", @@ -237,6 +242,7 @@ def restart_server() -> None: "PriceComparison", "ArbitrageOpportunity", "SubscribedAddressSnapshot", + "SubscriptionOption", "MatchRelation", "ClusterSortOption", "MatchedClusterSort", diff --git a/sdks/python/pmxt/client.py b/sdks/python/pmxt/client.py index 5c4219c7..5bcf9c6e 100644 --- a/sdks/python/pmxt/client.py +++ b/sdks/python/pmxt/client.py @@ -50,6 +50,7 @@ TradesParams, FetchOrderBookParams, SubscribedAddressSnapshot, + SubscriptionOption, FirehoseEvent, MatchResult, EventMatchResult, @@ -1683,6 +1684,7 @@ def fetch_trades( since: Optional[int] = None, start: Optional[Union[str, int]] = None, end: Optional[Union[str, int]] = None, + resolution: Optional[str] = None, **kwargs ) -> List[Trade]: """ @@ -1696,6 +1698,7 @@ def fetch_trades( since: Return trades since this timestamp (Unix milliseconds) start: Start of time range (ISO 8601 string or epoch seconds/ms) end: End of time range (ISO 8601 string or epoch seconds/ms) + resolution: Optional trade resolution/status filter forwarded to the venue **kwargs: Additional parameters Returns: @@ -1717,6 +1720,8 @@ def fetch_trades( params_dict["start"] = start if end is not None: params_dict["end"] = end + if resolution is not None: + params_dict["resolution"] = resolution # Add any extra keyword arguments for key, value in kwargs.items(): @@ -2078,7 +2083,7 @@ def watch_trades( def watch_address( self, address: str, - types: Optional[List[str]] = None, + types: Optional[List[SubscriptionOption]] = None, ) -> SubscribedAddressSnapshot: """ Watch real-time updates of a public wallet via WebSocket. diff --git a/sdks/python/pmxt/feed_client.py b/sdks/python/pmxt/feed_client.py index 0faba1ca..8c2fc48f 100644 --- a/sdks/python/pmxt/feed_client.py +++ b/sdks/python/pmxt/feed_client.py @@ -15,6 +15,8 @@ from dataclasses import dataclass, field from typing import List, Optional, Dict, Any, Tuple +from .errors import PmxtError + @dataclass(frozen=True) class Ticker: @@ -190,10 +192,10 @@ def _request(self, url: str, params: Optional[Dict[str, Any]] = None) -> Any: except urllib.error.HTTPError as e: body = json.loads(e.read()) if e.fp else {} msg = body.get("error", e.reason) - raise RuntimeError(f"Feed API error ({e.code}): {msg}") from e + raise PmxtError(f"Feed API error ({e.code}): {msg}") from e if not body.get("success"): - raise RuntimeError(f"Feed API error: {body.get('error', 'unknown')}") + raise PmxtError(f"Feed API error: {body.get('error', 'unknown')}") return body["data"] @staticmethod diff --git a/sdks/python/pmxt/models.py b/sdks/python/pmxt/models.py index de1cc856..4ce33e08 100644 --- a/sdks/python/pmxt/models.py +++ b/sdks/python/pmxt/models.py @@ -18,6 +18,7 @@ OrderSide = Literal["buy", "sell"] OrderType = Literal["market", "limit"] OutcomeType = Literal["yes", "no", "up", "down"] +SubscriptionOption = Literal["trades", "positions", "balances"] @dataclass @@ -471,7 +472,7 @@ class BuiltOrder: exchange: str """The exchange name this order was built for.""" - params: Dict[str, Any] + params: "CreateOrderParams" """The original params used to build this order.""" raw: Any @@ -480,10 +481,28 @@ class BuiltOrder: signed_order: Optional[Dict[str, Any]] = None """For CLOB exchanges (Polymarket): the EIP-712 signed order.""" - tx: Optional[Dict[str, Any]] = None + tx: Optional["TxPayload"] = None """For on-chain AMM exchanges: the EVM transaction payload.""" +class CreateOrderParams(TypedDict, total=False): + """Parameters used to build or create an order.""" + market_id: str + outcome_id: str + side: OrderSide + type: OrderType + amount: float + price: float + fee: int + + +class TxPayload(TypedDict): + """EVM transaction payload returned for on-chain AMM orders.""" + to: str + data: str + value: str + chainId: int + @dataclass class Position: """A current position in a market.""" @@ -701,6 +720,7 @@ class TradesParams(TypedDict, total=False): until: int limit: int cursor: str + resolution: str class FetchOrderBookParams(TypedDict, total=False): @@ -833,12 +853,12 @@ class MatchedMarketCluster: confidence: float """Cluster confidence score.""" + volume_24h: float + """Total 24-hour volume across markets in the cluster.""" + category: Optional[str] = None """Canonical category selected by the hosted API.""" - volume_24h: Optional[float] = None - """Total 24-hour volume across markets in the cluster.""" - raw_matches: Optional[List[Dict[str, Any]]] = None """Pairwise match edges used to build the cluster when requested.""" @@ -862,12 +882,12 @@ class MatchedEventCluster: confidence: float """Cluster confidence score.""" + volume_24h: float + """Total 24-hour volume across events in the cluster.""" + category: Optional[str] = None """Canonical category selected by the hosted API.""" - volume_24h: Optional[float] = None - """Total 24-hour volume across events in the cluster.""" - raw_matches: Optional[List[Dict[str, Any]]] = None """Pairwise match edges used to build the cluster when requested.""" diff --git a/sdks/typescript/pmxt/client.ts b/sdks/typescript/pmxt/client.ts index 5bde0054..8d591b9b 100644 --- a/sdks/typescript/pmxt/client.ts +++ b/sdks/typescript/pmxt/client.ts @@ -1013,6 +1013,9 @@ export abstract class Exchange { async submitOrder(built: BuiltOrder): Promise { await this.initPromise; + if (this.isHosted) { + throw new PmxtError("submitOrder is not available in hosted mode. Use createOrder instead."); + } try { const args: any[] = []; args.push(built); diff --git a/sdks/typescript/pmxt/router.ts b/sdks/typescript/pmxt/router.ts index 6e8be5d7..c0a244f8 100644 --- a/sdks/typescript/pmxt/router.ts +++ b/sdks/typescript/pmxt/router.ts @@ -224,6 +224,8 @@ export class Router extends Exchange { marketId?: string; slug?: string; url?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -234,6 +236,8 @@ export class Router extends Exchange { marketId?: string; slug?: string; url?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -246,6 +250,8 @@ export class Router extends Exchange { if (marketId) query.marketId = marketId; if (params.slug ?? params.market?.slug) query.slug = params.slug ?? params.market?.slug; if (params.url) query.url = params.url; + if (params.query) query.query = params.query; + if (params.category) query.category = params.category; if (params.relation) query.relation = params.relation; if (params.minConfidence !== undefined) query.minConfidence = params.minConfidence; if (params.limit !== undefined) query.limit = params.limit; @@ -274,6 +280,8 @@ export class Router extends Exchange { marketId?: string; slug?: string; url?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -284,6 +292,8 @@ export class Router extends Exchange { marketId?: string; slug?: string; url?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -303,6 +313,8 @@ export class Router extends Exchange { event?: UnifiedEvent; eventId?: string; slug?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -312,6 +324,8 @@ export class Router extends Exchange { event?: UnifiedEvent; eventId?: string; slug?: string; + query?: string; + category?: string; relation?: MatchRelation; minConfidence?: number; limit?: number; @@ -323,6 +337,8 @@ export class Router extends Exchange { const eventId = params.eventId ?? (!params.event?.slug ? params.event?.id : undefined); if (eventId) query.eventId = eventId; if (params.slug ?? params.event?.slug) query.slug = params.slug ?? params.event?.slug; + if (params.query) query.query = params.query; + if (params.category) query.category = params.category; if (params.relation) query.relation = params.relation; if (params.minConfidence !== undefined) query.minConfidence = params.minConfidence; if (params.limit !== undefined) query.limit = params.limit; diff --git a/sdks/typescript/scripts/generate-client-methods.js b/sdks/typescript/scripts/generate-client-methods.js index 1cebda06..064743ef 100644 --- a/sdks/typescript/scripts/generate-client-methods.js +++ b/sdks/typescript/scripts/generate-client-methods.js @@ -424,10 +424,18 @@ function generateMethod(name, params, config, sf) { const argsCode = buildArgsLines(params, sf); const returnCode = buildReturnLines(config); const { returnTs } = config; + const localOnlyGuard = name === 'submitOrder' + ? [ + ` if (this.isHosted) {`, + ` throw new PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.");`, + ` }`, + ] + : []; return [ ` async ${name}(${sig}): Promise<${returnTs}> {`, ` await this.initPromise;`, + ...localOnlyGuard, ` try {`, ` ${argsCode}`, ` const response = await this.fetchWithRetry(\`\${this.resolveBaseUrl()}/api/\${this.exchangeName}/${name}\`, {`,