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(
26 &self,
27 params: &FetchMarketsParams,
28 ) -> Result<(Vec<Market>, Option<String>), OpenPxError>;
29
30 async fn fetch_market(&self, market_id: &str) -> Result<Market, OpenPxError>;
31
32 async fn create_order(
33 &self,
34 market_id: &str,
35 outcome: &str,
36 side: OrderSide,
37 price: f64,
38 size: f64,
39 params: HashMap<String, String>,
40 ) -> Result<Order, OpenPxError>;
41
42 async fn cancel_order(
43 &self,
44 order_id: &str,
45 market_id: Option<&str>,
46 ) -> Result<Order, OpenPxError>;
47
48 async fn fetch_order(
49 &self,
50 order_id: &str,
51 market_id: Option<&str>,
52 ) -> Result<Order, OpenPxError>;
53
54 async fn fetch_open_orders(
55 &self,
56 params: Option<FetchOrdersParams>,
57 ) -> Result<Vec<Order>, OpenPxError>;
58
59 async fn fetch_positions(&self, market_id: Option<&str>) -> Result<Vec<Position>, OpenPxError>;
60
61 async fn fetch_balance(&self) -> Result<HashMap<String, f64>, OpenPxError>;
62
63 async fn refresh_balance(&self) -> Result<(), OpenPxError> {
65 Ok(())
66 }
67
68 async fn fetch_orderbook(&self, req: OrderbookRequest) -> Result<Orderbook, OpenPxError> {
71 let _ = req;
72 Err(OpenPxError::Exchange(
73 crate::error::ExchangeError::NotSupported("fetch_orderbook".into()),
74 ))
75 }
76
77 async fn fetch_price_history(
79 &self,
80 req: PriceHistoryRequest,
81 ) -> Result<Vec<Candlestick>, OpenPxError> {
82 let _ = req;
83 Err(OpenPxError::Exchange(
84 crate::error::ExchangeError::NotSupported("fetch_price_history".into()),
85 ))
86 }
87
88 async fn fetch_trades(
91 &self,
92 req: TradesRequest,
93 ) -> Result<(Vec<MarketTrade>, Option<String>), OpenPxError> {
94 let _ = req;
95 Err(OpenPxError::Exchange(
96 crate::error::ExchangeError::NotSupported("fetch_trades".into()),
97 ))
98 }
99
100 async fn fetch_orderbook_history(
103 &self,
104 req: OrderbookHistoryRequest,
105 ) -> Result<(Vec<OrderbookSnapshot>, Option<String>), OpenPxError> {
106 let _ = req;
107 Err(OpenPxError::Exchange(
108 crate::error::ExchangeError::NotSupported("fetch_orderbook_history".into()),
109 ))
110 }
111
112 async fn fetch_balance_raw(&self) -> Result<Value, OpenPxError> {
114 Err(OpenPxError::Exchange(
115 crate::error::ExchangeError::NotSupported("fetch_balance_raw".into()),
116 ))
117 }
118
119 async fn fetch_user_activity(
126 &self,
127 params: FetchUserActivityParams,
128 ) -> Result<Value, OpenPxError> {
129 let _ = params;
130 Err(OpenPxError::Exchange(
131 crate::error::ExchangeError::NotSupported("fetch_user_activity".into()),
132 ))
133 }
134
135 async fn fetch_fills(
137 &self,
138 market_id: Option<&str>,
139 limit: Option<usize>,
140 ) -> Result<Vec<Fill>, OpenPxError> {
141 let _ = (market_id, limit);
142 Err(OpenPxError::Exchange(
143 crate::error::ExchangeError::NotSupported("fetch_fills".into()),
144 ))
145 }
146
147 fn describe(&self) -> ExchangeInfo {
148 ExchangeInfo {
149 id: self.id(),
150 name: self.name(),
151 has_fetch_markets: true,
152 has_create_order: true,
153 has_cancel_order: true,
154 has_fetch_positions: true,
155 has_fetch_balance: true,
156 has_fetch_orderbook: false,
157 has_fetch_price_history: false,
158 has_fetch_trades: false,
159 has_fetch_user_activity: false,
160 has_fetch_fills: false,
161 has_approvals: false,
162 has_refresh_balance: false,
163 has_websocket: false,
164 has_fetch_orderbook_history: false,
165 }
166 }
167
168 fn manifest(&self) -> &'static ExchangeManifest;
170}
171
172#[derive(Debug, Clone, Serialize)]
173#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
174pub struct ExchangeInfo {
175 pub id: &'static str,
176 pub name: &'static str,
177 pub has_fetch_markets: bool,
178 pub has_create_order: bool,
179 pub has_cancel_order: bool,
180 pub has_fetch_positions: bool,
181 pub has_fetch_balance: bool,
182 pub has_fetch_orderbook: bool,
183 pub has_fetch_price_history: bool,
184 pub has_fetch_trades: bool,
185 pub has_fetch_user_activity: bool,
186 pub has_fetch_fills: bool,
187 pub has_approvals: bool,
188 pub has_refresh_balance: bool,
189 pub has_websocket: bool,
190 pub has_fetch_orderbook_history: bool,
191}
192
193#[derive(Debug, Clone, Default, Serialize, Deserialize)]
195#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
196pub struct OrderbookRequest {
197 pub market_id: String,
198 pub outcome: Option<String>,
199 pub token_id: Option<String>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
205pub struct PriceHistoryRequest {
206 pub market_id: String,
207 pub outcome: Option<String>,
208 pub token_id: Option<String>,
209 pub condition_id: Option<String>,
211 pub interval: PriceHistoryInterval,
212 pub start_ts: Option<i64>,
214 pub end_ts: Option<i64>,
216}
217
218#[derive(Debug, Clone, Default, Serialize, Deserialize)]
220#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
221pub struct TradesRequest {
222 pub market_id: String,
224 pub market_ref: Option<String>,
227 pub outcome: Option<String>,
228 pub token_id: Option<String>,
229 pub start_ts: Option<i64>,
231 pub end_ts: Option<i64>,
233 pub limit: Option<usize>,
235 pub cursor: Option<String>,
237}
238
239#[derive(Debug, Clone, Default, Serialize, Deserialize)]
240#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
241pub struct OrderbookHistoryRequest {
242 pub market_id: String,
243 pub token_id: Option<String>,
244 pub start_ts: Option<i64>,
245 pub end_ts: Option<i64>,
246 pub limit: Option<usize>,
247 pub cursor: Option<String>,
248}