1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5use crate::error::OpenPxError;
6use crate::models::{
7 Candlestick, Fill, Market, MarketTrade, Order, OrderSide, Orderbook, OrderbookSnapshot,
8 Position, PriceHistoryInterval,
9};
10
11use super::config::{FetchMarketsParams, FetchOrdersParams, FetchUserActivityParams};
12use super::manifest::ExchangeManifest;
13
14#[allow(async_fn_in_trait)]
15pub trait Exchange: Send + Sync {
16 fn id(&self) -> &'static str;
17 fn name(&self) -> &'static str;
18
19 async fn fetch_markets(
25 &self,
26 params: &FetchMarketsParams,
27 ) -> Result<(Vec<Market>, Option<String>), OpenPxError>;
28
29 async fn fetch_market(&self, market_id: &str) -> Result<Market, OpenPxError>;
30
31 async fn create_order(
32 &self,
33 market_id: &str,
34 outcome: &str,
35 side: OrderSide,
36 price: f64,
37 size: f64,
38 params: HashMap<String, String>,
39 ) -> Result<Order, OpenPxError>;
40
41 async fn cancel_order(
42 &self,
43 order_id: &str,
44 market_id: Option<&str>,
45 ) -> Result<Order, OpenPxError>;
46
47 async fn fetch_order(
48 &self,
49 order_id: &str,
50 market_id: Option<&str>,
51 ) -> Result<Order, OpenPxError>;
52
53 async fn fetch_open_orders(
54 &self,
55 params: Option<FetchOrdersParams>,
56 ) -> Result<Vec<Order>, OpenPxError>;
57
58 async fn fetch_positions(&self, market_id: Option<&str>) -> Result<Vec<Position>, OpenPxError>;
59
60 async fn fetch_balance(&self) -> Result<HashMap<String, f64>, OpenPxError>;
61
62 async fn refresh_balance(&self) -> Result<(), OpenPxError> {
64 Ok(())
65 }
66
67 async fn fetch_orderbook(&self, req: OrderbookRequest) -> Result<Orderbook, OpenPxError> {
70 let _ = req;
71 Err(OpenPxError::Exchange(
72 crate::error::ExchangeError::NotSupported("fetch_orderbook".into()),
73 ))
74 }
75
76 async fn fetch_price_history(
78 &self,
79 req: PriceHistoryRequest,
80 ) -> Result<Vec<Candlestick>, OpenPxError> {
81 let _ = req;
82 Err(OpenPxError::Exchange(
83 crate::error::ExchangeError::NotSupported("fetch_price_history".into()),
84 ))
85 }
86
87 async fn fetch_trades(
90 &self,
91 req: TradesRequest,
92 ) -> Result<(Vec<MarketTrade>, Option<String>), OpenPxError> {
93 let _ = req;
94 Err(OpenPxError::Exchange(
95 crate::error::ExchangeError::NotSupported("fetch_trades".into()),
96 ))
97 }
98
99 async fn fetch_orderbook_history(
102 &self,
103 req: OrderbookHistoryRequest,
104 ) -> Result<(Vec<OrderbookSnapshot>, Option<String>), OpenPxError> {
105 let _ = req;
106 Err(OpenPxError::Exchange(
107 crate::error::ExchangeError::NotSupported("fetch_orderbook_history".into()),
108 ))
109 }
110
111 async fn fetch_balance_raw(&self) -> Result<Value, OpenPxError> {
113 Err(OpenPxError::Exchange(
114 crate::error::ExchangeError::NotSupported("fetch_balance_raw".into()),
115 ))
116 }
117
118 async fn fetch_user_activity(
125 &self,
126 params: FetchUserActivityParams,
127 ) -> Result<Value, OpenPxError> {
128 let _ = params;
129 Err(OpenPxError::Exchange(
130 crate::error::ExchangeError::NotSupported("fetch_user_activity".into()),
131 ))
132 }
133
134 async fn fetch_fills(
136 &self,
137 market_id: Option<&str>,
138 limit: Option<usize>,
139 ) -> Result<Vec<Fill>, OpenPxError> {
140 let _ = (market_id, limit);
141 Err(OpenPxError::Exchange(
142 crate::error::ExchangeError::NotSupported("fetch_fills".into()),
143 ))
144 }
145
146 fn describe(&self) -> ExchangeInfo {
147 ExchangeInfo {
148 id: self.id(),
149 name: self.name(),
150 has_fetch_markets: true,
151 has_create_order: true,
152 has_cancel_order: true,
153 has_fetch_positions: true,
154 has_fetch_balance: true,
155 has_fetch_orderbook: false,
156 has_fetch_price_history: false,
157 has_fetch_trades: false,
158 has_fetch_user_activity: false,
159 has_fetch_fills: false,
160 has_approvals: false,
161 has_refresh_balance: false,
162 has_websocket: false,
163 has_fetch_orderbook_history: false,
164 }
165 }
166
167 fn manifest(&self) -> &'static ExchangeManifest;
169}
170
171#[derive(Debug, Clone, Serialize)]
172#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
173pub struct ExchangeInfo {
174 pub id: &'static str,
175 pub name: &'static str,
176 pub has_fetch_markets: bool,
177 pub has_create_order: bool,
178 pub has_cancel_order: bool,
179 pub has_fetch_positions: bool,
180 pub has_fetch_balance: bool,
181 pub has_fetch_orderbook: bool,
182 pub has_fetch_price_history: bool,
183 pub has_fetch_trades: bool,
184 pub has_fetch_user_activity: bool,
185 pub has_fetch_fills: bool,
186 pub has_approvals: bool,
187 pub has_refresh_balance: bool,
188 pub has_websocket: bool,
189 pub has_fetch_orderbook_history: bool,
190}
191
192#[derive(Debug, Clone, Default, Serialize, Deserialize)]
194#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
195pub struct OrderbookRequest {
196 pub market_id: String,
197 pub outcome: Option<String>,
198 pub token_id: Option<String>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
203#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
204pub struct PriceHistoryRequest {
205 pub market_id: String,
206 pub outcome: Option<String>,
207 pub token_id: Option<String>,
208 pub condition_id: Option<String>,
210 pub interval: PriceHistoryInterval,
211 pub start_ts: Option<i64>,
213 pub end_ts: Option<i64>,
215}
216
217#[derive(Debug, Clone, Default, Serialize, Deserialize)]
219#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
220pub struct TradesRequest {
221 pub market_id: String,
223 pub market_ref: Option<String>,
226 pub outcome: Option<String>,
227 pub token_id: Option<String>,
228 pub start_ts: Option<i64>,
230 pub end_ts: Option<i64>,
232 pub limit: Option<usize>,
234 pub cursor: Option<String>,
236}
237
238#[derive(Debug, Clone, Default, Serialize, Deserialize)]
239#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
240pub struct OrderbookHistoryRequest {
241 pub market_id: String,
242 pub token_id: Option<String>,
243 pub start_ts: Option<i64>,
244 pub end_ts: Option<i64>,
245 pub limit: Option<usize>,
246 pub cursor: Option<String>,
247}