Skip to main content

polymarket_us/
types.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4// ---------------------------------------------------------------------------
5// String-constant modules (kept for compatibility; prefer the typed enums below)
6// ---------------------------------------------------------------------------
7
8pub mod order_action {
9    pub const BUY: &str = "ORDER_ACTION_BUY";
10    pub const SELL: &str = "ORDER_ACTION_SELL";
11}
12
13pub mod order_type {
14    pub const LIMIT: &str = "ORDER_TYPE_LIMIT";
15}
16
17pub mod tif {
18    pub const GTC: &str = "TIME_IN_FORCE_GOOD_TILL_CANCEL";
19    pub const GTD: &str = "TIME_IN_FORCE_GOOD_TILL_DATE";
20    pub const FAK: &str = "TIME_IN_FORCE_IMMEDIATE_OR_CANCEL";
21    pub const FOK: &str = "TIME_IN_FORCE_FILL_OR_KILL";
22}
23
24pub mod outcome {
25    pub const LONG: &str = "LONG";
26    pub const SHORT: &str = "SHORT";
27}
28
29// ---------------------------------------------------------------------------
30// Typed enums (preferred over the string-constant modules above)
31// ---------------------------------------------------------------------------
32
33/// Whether this order is a buy or a sell.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
35#[non_exhaustive]
36pub enum OrderAction {
37    #[serde(rename = "ORDER_ACTION_BUY")]
38    Buy,
39    #[serde(rename = "ORDER_ACTION_SELL")]
40    Sell,
41}
42
43impl fmt::Display for OrderAction {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        match self {
46            Self::Buy => f.write_str("ORDER_ACTION_BUY"),
47            Self::Sell => f.write_str("ORDER_ACTION_SELL"),
48        }
49    }
50}
51
52/// Outcome side — long (yes) or short (no).
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54#[non_exhaustive]
55pub enum OrderSide {
56    #[serde(rename = "LONG")]
57    Long,
58    #[serde(rename = "SHORT")]
59    Short,
60}
61
62impl fmt::Display for OrderSide {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Self::Long => f.write_str("LONG"),
66            Self::Short => f.write_str("SHORT"),
67        }
68    }
69}
70
71/// Order execution type.
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
73#[non_exhaustive]
74pub enum OrderType {
75    #[serde(rename = "ORDER_TYPE_LIMIT")]
76    Limit,
77}
78
79impl fmt::Display for OrderType {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        f.write_str("ORDER_TYPE_LIMIT")
82    }
83}
84
85/// Time-in-force policy for an order.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[non_exhaustive]
88pub enum TimeInForce {
89    /// Good-till-cancel — stays open until filled or explicitly cancelled.
90    #[serde(rename = "TIME_IN_FORCE_GOOD_TILL_CANCEL")]
91    GoodTillCancel,
92    /// Good-till-date — expires at a specified timestamp.
93    #[serde(rename = "TIME_IN_FORCE_GOOD_TILL_DATE")]
94    GoodTillDate,
95    /// Immediate-or-cancel (fill-and-kill) — any unfilled portion is cancelled.
96    #[serde(rename = "TIME_IN_FORCE_IMMEDIATE_OR_CANCEL")]
97    ImmediateOrCancel,
98    /// Fill-or-kill — must be filled entirely or cancelled entirely.
99    #[serde(rename = "TIME_IN_FORCE_FILL_OR_KILL")]
100    FillOrKill,
101}
102
103impl fmt::Display for TimeInForce {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        let s = match self {
106            Self::GoodTillCancel => "TIME_IN_FORCE_GOOD_TILL_CANCEL",
107            Self::GoodTillDate => "TIME_IN_FORCE_GOOD_TILL_DATE",
108            Self::ImmediateOrCancel => "TIME_IN_FORCE_IMMEDIATE_OR_CANCEL",
109            Self::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL",
110        };
111        f.write_str(s)
112    }
113}
114
115/// Known market status values.
116#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
117#[serde(rename_all = "lowercase")]
118#[non_exhaustive]
119pub enum MarketStatus {
120    Open,
121    Closed,
122    Resolved,
123    /// Catch-all for any status string not yet modelled here.
124    #[serde(other)]
125    Unknown,
126}
127
128// ---------------------------------------------------------------------------
129// REST response/request types
130// ---------------------------------------------------------------------------
131
132#[derive(Debug, Clone, Deserialize)]
133pub struct HealthResponse {
134    #[serde(default)]
135    pub status: String,
136    #[serde(default)]
137    pub timestamp: String,
138}
139
140#[derive(Debug, Clone, Deserialize)]
141pub struct MarketsResponse {
142    #[serde(default)]
143    pub markets: Vec<UsMarket>,
144}
145
146#[derive(Debug, Clone, Deserialize)]
147pub struct UsMarket {
148    #[serde(default)]
149    pub id: String,
150    #[serde(default)]
151    pub slug: String,
152    #[serde(default)]
153    pub question: String,
154    #[serde(default)]
155    pub status: String,
156    #[serde(default)]
157    pub category: String,
158    #[serde(default, rename = "startDate")]
159    pub start_date: String,
160    #[serde(default, rename = "endDate")]
161    pub end_date: String,
162    #[serde(default)]
163    pub description: String,
164    #[serde(default)]
165    pub active: bool,
166    #[serde(default)]
167    pub closed: bool,
168    #[serde(default, rename = "marketType")]
169    pub market_type: String,
170    #[serde(default, rename = "marketSides")]
171    pub market_sides: Vec<serde_json::Value>,
172    #[serde(default)]
173    pub instruments: Vec<serde_json::Value>,
174    #[serde(default)]
175    pub outcomes: Vec<serde_json::Value>,
176}
177
178#[derive(Debug, Clone, Deserialize)]
179pub struct MarketSide {
180    #[serde(default)]
181    pub id: String,
182    #[serde(default)]
183    pub identifier: String,
184    #[serde(default)]
185    pub description: String,
186    #[serde(default)]
187    pub price: String,
188    #[serde(default)]
189    pub long: bool,
190    #[serde(default, rename = "marketSideType")]
191    pub market_side_type: String,
192    #[serde(default)]
193    pub team: Option<serde_json::Value>,
194    #[serde(default)]
195    pub player: Option<serde_json::Value>,
196    #[serde(flatten)]
197    pub extra: std::collections::HashMap<String, serde_json::Value>,
198}
199
200#[derive(Debug, Clone, Serialize)]
201pub struct PlaceOrderRequest {
202    pub symbol: String,
203    pub action: OrderAction,
204    #[serde(rename = "outcomeSide")]
205    pub outcome_side: OrderSide,
206    #[serde(rename = "type")]
207    pub order_type: OrderType,
208    pub price: Money,
209    pub quantity: u64,
210    pub tif: TimeInForce,
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub client_order_id: Option<String>,
213    #[serde(skip_serializing_if = "std::ops::Not::not")]
214    pub post_only: bool,
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub expires_at: Option<u64>,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct Money {
221    pub value: String,
222    pub currency: String,
223}
224
225#[derive(Debug, Clone, Deserialize)]
226pub struct PlaceOrderResponse {
227    pub order_id: String,
228    #[serde(default)]
229    pub client_order_id: Option<String>,
230    #[serde(default)]
231    pub status: String,
232    #[serde(default)]
233    pub filled_quantity: u64,
234    #[serde(default)]
235    pub remaining_quantity: u64,
236    #[serde(default)]
237    pub created_at: String,
238}
239
240#[derive(Debug, Clone, Serialize)]
241pub struct BatchedOrderRequest {
242    pub orders: Vec<PlaceOrderRequest>,
243    pub atomic: bool,
244}
245
246#[derive(Debug, Clone, Deserialize)]
247pub struct BatchedOrderResponse {
248    #[serde(default)]
249    pub orders: Vec<PlaceOrderResponse>,
250}
251
252#[derive(Debug, Clone, Deserialize)]
253pub struct CancelOrderResponse {
254    pub order_id: String,
255    #[serde(default)]
256    pub status: String,
257    #[serde(default)]
258    pub cancelled_at: Option<String>,
259}
260
261#[derive(Debug, Clone, Deserialize)]
262pub struct PortfolioPositionsResponse {
263    #[serde(default)]
264    pub positions: std::collections::HashMap<String, UsPosition>,
265    #[serde(default)]
266    pub next_cursor: String,
267    #[serde(default)]
268    pub eof: bool,
269    #[serde(default, rename = "availablePositions")]
270    pub available_positions: Vec<UsPosition>,
271}
272
273#[derive(Debug, Clone, Deserialize)]
274pub struct UsPosition {
275    #[serde(default)]
276    pub symbol: String,
277    #[serde(default)]
278    pub quantity: i64,
279    #[serde(default, rename = "avgEntryPrice")]
280    pub avg_entry_price: String,
281    #[serde(default, rename = "unrealizedPnl")]
282    pub unrealized_pnl: Option<String>,
283}
284
285#[derive(Debug, Clone, Deserialize)]
286pub struct PortfolioActivitiesResponse {
287    #[serde(default)]
288    pub activities: Vec<serde_json::Value>,
289    #[serde(default)]
290    pub next_cursor: Option<String>,
291}
292
293#[derive(Debug, Clone, Deserialize)]
294pub struct AccountBalancesResponse {
295    #[serde(default)]
296    pub balances: Vec<UserBalance>,
297}
298
299#[derive(Debug, Clone, Deserialize)]
300pub struct UserBalance {
301    #[serde(default, rename = "currentBalance")]
302    pub current_balance: f64,
303    #[serde(default)]
304    pub currency: String,
305    #[serde(default, rename = "lastUpdated")]
306    pub last_updated: Option<String>,
307    #[serde(default, rename = "buyingPower")]
308    pub buying_power: f64,
309    #[serde(default, rename = "assetNotional")]
310    pub asset_notional: Option<f64>,
311    #[serde(default, rename = "assetAvailable")]
312    pub asset_available: Option<f64>,
313    #[serde(default, rename = "pendingCredit")]
314    pub pending_credit: Option<f64>,
315    #[serde(default, rename = "openOrders")]
316    pub open_orders: Option<f64>,
317    #[serde(default, rename = "unsettledFunds")]
318    pub unsettled_funds: Option<f64>,
319    #[serde(default, rename = "marginRequirement")]
320    pub margin_requirement: Option<f64>,
321    #[serde(default, rename = "balanceReservation")]
322    pub balance_reservation: Option<f64>,
323}
324
325#[derive(Debug, Clone, Serialize, Default)]
326pub struct CancelOrderParams {
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub quantity: Option<u64>,
329}
330
331#[derive(Debug, Clone, Serialize, Default)]
332pub struct CancelAllOrdersParams {
333    #[serde(skip_serializing_if = "Option::is_none")]
334    pub symbol: Option<String>,
335}
336
337#[derive(Debug, Clone, Deserialize)]
338pub struct CancelAllOrdersResponse {
339    #[serde(default)]
340    pub cancelled: Vec<String>,
341}
342
343#[derive(Debug, Clone, Serialize)]
344pub struct ModifyOrderRequest {
345    pub price: Money,
346    pub quantity: u64,
347}
348
349#[derive(Debug, Clone, Serialize)]
350pub struct PreviewOrderRequest {
351    pub symbol: String,
352    pub action: OrderAction,
353    #[serde(rename = "outcomeSide")]
354    pub outcome_side: OrderSide,
355    #[serde(rename = "type")]
356    pub order_type: OrderType,
357    pub price: Money,
358    pub quantity: u64,
359}
360
361#[derive(Debug, Clone, Deserialize)]
362pub struct PreviewOrderResponse {
363    #[serde(default)]
364    pub estimate: serde_json::Value,
365}
366
367#[derive(Debug, Clone, Serialize)]
368pub struct ClosePositionRequest {
369    pub symbol: String,
370    pub quantity: u64,
371}
372
373#[derive(Debug, Clone, Deserialize)]
374pub struct ClosePositionResponse {
375    #[serde(default)]
376    pub status: String,
377    #[serde(default)]
378    pub order_id: Option<String>,
379}
380
381#[derive(Debug, Clone, Deserialize)]
382pub struct GetOpenOrdersResponse {
383    #[serde(default)]
384    pub orders: Vec<PlaceOrderResponse>,
385}
386
387// Events
388#[derive(Debug, Clone, Deserialize)]
389pub struct EventsResponse {
390    #[serde(default)]
391    pub events: Vec<UsEvent>,
392}
393
394#[derive(Debug, Clone, Deserialize)]
395pub struct UsEvent {
396    #[serde(default)]
397    pub id: String,
398    #[serde(default)]
399    pub slug: String,
400    #[serde(default)]
401    pub title: String,
402    #[serde(default)]
403    pub description: Option<String>,
404    #[serde(default)]
405    pub category: String,
406    #[serde(default)]
407    pub start_date: Option<String>,
408    #[serde(default)]
409    pub end_date: Option<String>,
410    #[serde(flatten)]
411    pub extra: std::collections::HashMap<String, serde_json::Value>,
412}
413
414// Market data helpers
415#[derive(Debug, Clone, Deserialize)]
416pub struct OrderBook {
417    #[serde(default)]
418    pub bids: Vec<PriceLevel>,
419    #[serde(default)]
420    pub asks: Vec<PriceLevel>,
421}
422
423#[derive(Debug, Clone, Deserialize, Serialize)]
424pub struct PriceLevel {
425    pub price: String,
426    pub quantity: String,
427}
428
429#[derive(Debug, Clone, Deserialize)]
430pub struct BestBidOffer {
431    #[serde(default)]
432    pub bid: Option<PriceLevel>,
433    #[serde(default)]
434    pub ask: Option<PriceLevel>,
435}
436
437#[derive(Debug, Clone, Deserialize)]
438pub struct SettlementPrice {
439    #[serde(default)]
440    pub symbol: String,
441    #[serde(default)]
442    pub price: String,
443    #[serde(default)]
444    pub timestamp: String,
445}
446
447// Search
448#[derive(Debug, Clone, Deserialize)]
449pub struct SearchResults {
450    #[serde(default)]
451    pub markets: Vec<UsMarket>,
452    #[serde(default)]
453    pub events: Vec<UsEvent>,
454}
455
456// Series and Sports (placeholder for expansion)
457#[derive(Debug, Clone, Deserialize)]
458pub struct League {
459    #[serde(default)]
460    pub id: String,
461    #[serde(default)]
462    pub name: String,
463    #[serde(default)]
464    pub sport: String,
465}
466
467#[derive(Debug, Clone, Deserialize)]
468pub struct Team {
469    #[serde(default)]
470    pub id: String,
471    #[serde(default)]
472    pub name: String,
473    #[serde(default)]
474    pub league_id: Option<String>,
475}