Skip to content

Commit a114458

Browse files
committed
feat: accept MarketOutcome object in all outcome-based SDK methods
Standardize the MarketOutcome shorthand pattern (already used by createOrder/buildOrder) across fetchOrderBook, fetchOHLCV, fetchTrades, watchOrderBook, and watchTrades in both Python and TypeScript SDKs. Users can now pass market.yes directly instead of market.yes.outcomeId.
1 parent 38edd1e commit a114458

File tree

2 files changed

+42
-16
lines changed

2 files changed

+42
-16
lines changed

sdks/python/pmxt/client.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
from .server_manager import ServerManager
4949

5050

51+
def _resolve_outcome_id(value: Union[str, "MarketOutcome"]) -> str:
52+
"""Extract outcome_id string from a MarketOutcome or pass through a string."""
53+
if isinstance(value, str):
54+
return value
55+
return value.outcome_id
56+
57+
5158
def _convert_outcome(raw: Dict[str, Any]) -> MarketOutcome:
5259
"""Convert raw API response to MarketOutcome."""
5360
return MarketOutcome(
@@ -606,8 +613,9 @@ def fetch_event(self, params: Optional[dict] = None, **kwargs) -> UnifiedEvent:
606613
except Exception as e:
607614
raise self._parse_api_exception(e) from None
608615

609-
def fetch_order_book(self, id: str) -> OrderBook:
616+
def fetch_order_book(self, id: Union[str, "MarketOutcome"]) -> OrderBook:
610617
try:
618+
id = _resolve_outcome_id(id)
611619
args = []
612620
args.append(id)
613621
body: dict = {"args": args}
@@ -1012,7 +1020,7 @@ def filter_events(
10121020

10131021
def fetch_ohlcv(
10141022
self,
1015-
outcome_id: str,
1023+
outcome_id: Union[str, "MarketOutcome"],
10161024
resolution: Optional[str] = None,
10171025
limit: Optional[int] = None,
10181026
start: Optional[datetime] = None,
@@ -1027,7 +1035,7 @@ def fetch_ohlcv(
10271035
- Kalshi: outcome.outcome_id is the Market Ticker
10281036
10291037
Args:
1030-
outcome_id: Outcome ID (from market.outcomes[].outcome_id)
1038+
outcome_id: Outcome ID (from market.outcomes[].outcome_id), or a MarketOutcome object
10311039
resolution: Candle resolution (e.g., "1h", "1d")
10321040
limit: Maximum number of candles to return
10331041
start: Start datetime for historical data
@@ -1047,6 +1055,7 @@ def fetch_ohlcv(
10471055
... )
10481056
"""
10491057
try:
1058+
outcome_id = _resolve_outcome_id(outcome_id)
10501059
params_dict = {}
10511060
if resolution:
10521061
params_dict["resolution"] = resolution
@@ -1077,7 +1086,7 @@ def fetch_ohlcv(
10771086

10781087
def fetch_trades(
10791088
self,
1080-
outcome_id: str,
1089+
outcome_id: Union[str, "MarketOutcome"],
10811090
limit: Optional[int] = None,
10821091
since: Optional[int] = None,
10831092
**kwargs
@@ -1100,6 +1109,7 @@ def fetch_trades(
11001109
>>> trades = exchange.fetch_trades(outcome_id, limit=50)
11011110
"""
11021111
try:
1112+
outcome_id = _resolve_outcome_id(outcome_id)
11031113
params_dict = {}
11041114
if limit:
11051115
params_dict["limit"] = limit
@@ -1126,7 +1136,7 @@ def fetch_trades(
11261136

11271137
# WebSocket Streaming Methods
11281138

1129-
def watch_order_book(self, outcome_id: str, limit: Optional[int] = None) -> OrderBook:
1139+
def watch_order_book(self, outcome_id: Union[str, "MarketOutcome"], limit: Optional[int] = None) -> OrderBook:
11301140
"""
11311141
Watch real-time order book updates via WebSocket.
11321142
@@ -1148,6 +1158,7 @@ def watch_order_book(self, outcome_id: str, limit: Optional[int] = None) -> Orde
11481158
... print(f"Best ask: {order_book.asks[0].price}")
11491159
"""
11501160
try:
1161+
outcome_id = _resolve_outcome_id(outcome_id)
11511162
args = [outcome_id]
11521163
if limit is not None:
11531164
args.append(limit)
@@ -1173,7 +1184,7 @@ def watch_order_book(self, outcome_id: str, limit: Optional[int] = None) -> Orde
11731184

11741185
def watch_trades(
11751186
self,
1176-
outcome_id: str,
1187+
outcome_id: Union[str, "MarketOutcome"],
11771188
address: Optional[str] = None,
11781189
since: Optional[int] = None,
11791190
limit: Optional[int] = None,
@@ -1201,6 +1212,7 @@ def watch_trades(
12011212
... print(f"Trade: {trade.price} @ {trade.amount}")
12021213
"""
12031214
try:
1215+
outcome_id = _resolve_outcome_id(outcome_id)
12041216
args = [outcome_id]
12051217
if address is not None:
12061218
args.append(address)

sdks/typescript/pmxt/client.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ import { ServerManager } from "./server-manager.js";
4545
import { buildArgsWithOptionalOptions } from "./args.js";
4646
import { PmxtError, fromServerError } from "./errors.js";
4747

48+
/**
49+
* Resolve a MarketOutcome shorthand to a plain outcome ID string.
50+
* Accepts either a raw string ID or a MarketOutcome object.
51+
*/
52+
function resolveOutcomeId(input: string | MarketOutcome): string {
53+
if (typeof input === 'string') return input;
54+
return input.outcomeId;
55+
}
56+
4857
// Converter functions
4958
function convertMarket(raw: any): UnifiedMarket {
5059
const outcomes: MarketOutcome[] = (raw.outcomes || []).map((o: any) => ({
@@ -544,11 +553,12 @@ export abstract class Exchange {
544553
}
545554
}
546555

547-
async fetchOrderBook(id: string): Promise<OrderBook> {
556+
async fetchOrderBook(id: string | MarketOutcome): Promise<OrderBook> {
548557
await this.initPromise;
558+
const resolvedId = resolveOutcomeId(id);
549559
try {
550560
const args: any[] = [];
551-
args.push(id);
561+
args.push(resolvedId);
552562
const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchOrderBook`, {
553563
method: 'POST',
554564
headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
@@ -817,10 +827,11 @@ export abstract class Exchange {
817827
* ```
818828
*/
819829
async fetchOHLCV(
820-
outcomeId: string,
830+
outcomeId: string | MarketOutcome,
821831
params: any
822832
): Promise<PriceCandle[]> {
823833
await this.initPromise;
834+
const resolvedOutcomeId = resolveOutcomeId(outcomeId);
824835
try {
825836
const paramsDict: any = { resolution: params.resolution };
826837
if (params.start) {
@@ -834,7 +845,7 @@ export abstract class Exchange {
834845
}
835846

836847
const requestBody: FetchOHLCVRequest = {
837-
args: [outcomeId, paramsDict],
848+
args: [resolvedOutcomeId, paramsDict],
838849
credentials: this.getCredentials()
839850
};
840851

@@ -861,18 +872,19 @@ export abstract class Exchange {
861872
* @returns List of trades
862873
*/
863874
async fetchTrades(
864-
outcomeId: string,
875+
outcomeId: string | MarketOutcome,
865876
params: any
866877
): Promise<Trade[]> {
867878
await this.initPromise;
879+
const resolvedOutcomeId = resolveOutcomeId(outcomeId);
868880
try {
869881
const paramsDict: any = { resolution: params.resolution };
870882
if (params.limit) {
871883
paramsDict.limit = params.limit;
872884
}
873885

874886
const requestBody: FetchTradesRequest = {
875-
args: [outcomeId, paramsDict],
887+
args: [resolvedOutcomeId, paramsDict],
876888
credentials: this.getCredentials()
877889
};
878890

@@ -911,10 +923,11 @@ export abstract class Exchange {
911923
* }
912924
* ```
913925
*/
914-
async watchOrderBook(outcomeId: string, limit?: number): Promise<OrderBook> {
926+
async watchOrderBook(outcomeId: string | MarketOutcome, limit?: number): Promise<OrderBook> {
915927
await this.initPromise;
928+
const resolvedOutcomeId = resolveOutcomeId(outcomeId);
916929
try {
917-
const args: any[] = [outcomeId];
930+
const args: any[] = [resolvedOutcomeId];
918931
if (limit !== undefined) {
919932
args.push(limit);
920933
}
@@ -961,14 +974,15 @@ export abstract class Exchange {
961974
* ```
962975
*/
963976
async watchTrades(
964-
outcomeId: string,
977+
outcomeId: string | MarketOutcome,
965978
address?: string,
966979
since?: number,
967980
limit?: number
968981
): Promise<Trade[]> {
969982
await this.initPromise;
983+
const resolvedOutcomeId = resolveOutcomeId(outcomeId);
970984
try {
971-
const args: any[] = [outcomeId];
985+
const args: any[] = [resolvedOutcomeId];
972986
if (address !== undefined) {
973987
args.push(address);
974988
}

0 commit comments

Comments
 (0)