ccxt_exchanges/okx/
mod.rs1use ccxt_core::{BaseExchange, ExchangeConfig, Result};
7use std::collections::HashMap;
8
9pub mod auth;
10pub mod builder;
11pub mod error;
12pub mod exchange_impl;
13pub mod parser;
14pub mod rest;
15pub mod symbol;
16pub mod ws;
17pub mod ws_exchange_impl;
18
19pub use auth::OkxAuth;
20pub use builder::OkxBuilder;
21pub use error::{OkxErrorCode, is_error_response, parse_error};
22
23#[derive(Debug)]
25pub struct Okx {
26 base: BaseExchange,
28 options: OkxOptions,
30}
31
32#[derive(Debug, Clone)]
34pub struct OkxOptions {
35 pub account_mode: String,
37 pub demo: bool,
39}
40
41impl Default for OkxOptions {
42 fn default() -> Self {
43 Self {
44 account_mode: "cash".to_string(),
45 demo: false,
46 }
47 }
48}
49
50impl Okx {
51 pub fn builder() -> OkxBuilder {
69 OkxBuilder::new()
70 }
71
72 pub fn new(config: ExchangeConfig) -> Result<Self> {
78 let base = BaseExchange::new(config)?;
79 let options = OkxOptions::default();
80
81 Ok(Self { base, options })
82 }
83
84 pub fn new_with_options(config: ExchangeConfig, options: OkxOptions) -> Result<Self> {
93 let base = BaseExchange::new(config)?;
94 Ok(Self { base, options })
95 }
96
97 pub fn base(&self) -> &BaseExchange {
99 &self.base
100 }
101
102 pub fn base_mut(&mut self) -> &mut BaseExchange {
104 &mut self.base
105 }
106
107 pub fn options(&self) -> &OkxOptions {
109 &self.options
110 }
111
112 pub fn set_options(&mut self, options: OkxOptions) {
114 self.options = options;
115 }
116
117 pub fn id(&self) -> &str {
119 "okx"
120 }
121
122 pub fn name(&self) -> &str {
124 "OKX"
125 }
126
127 pub fn version(&self) -> &str {
129 "v5"
130 }
131
132 pub fn certified(&self) -> bool {
134 false
135 }
136
137 pub fn pro(&self) -> bool {
139 true
140 }
141
142 pub fn rate_limit(&self) -> f64 {
144 20.0
145 }
146
147 pub fn timeframes(&self) -> HashMap<String, String> {
149 let mut timeframes = HashMap::new();
150 timeframes.insert("1m".to_string(), "1m".to_string());
151 timeframes.insert("3m".to_string(), "3m".to_string());
152 timeframes.insert("5m".to_string(), "5m".to_string());
153 timeframes.insert("15m".to_string(), "15m".to_string());
154 timeframes.insert("30m".to_string(), "30m".to_string());
155 timeframes.insert("1h".to_string(), "1H".to_string());
156 timeframes.insert("2h".to_string(), "2H".to_string());
157 timeframes.insert("4h".to_string(), "4H".to_string());
158 timeframes.insert("6h".to_string(), "6Hutc".to_string());
159 timeframes.insert("12h".to_string(), "12Hutc".to_string());
160 timeframes.insert("1d".to_string(), "1Dutc".to_string());
161 timeframes.insert("1w".to_string(), "1Wutc".to_string());
162 timeframes.insert("1M".to_string(), "1Mutc".to_string());
163 timeframes
164 }
165
166 pub fn urls(&self) -> OkxUrls {
168 if self.base().config.sandbox || self.options.demo {
169 OkxUrls::demo()
170 } else {
171 OkxUrls::production()
172 }
173 }
174
175 pub fn create_ws(&self) -> ws::OkxWs {
193 let urls = self.urls();
194 ws::OkxWs::new(urls.ws_public)
195 }
196}
197
198#[derive(Debug, Clone)]
200pub struct OkxUrls {
201 pub rest: String,
203 pub ws_public: String,
205 pub ws_private: String,
207 pub ws_business: String,
209}
210
211impl OkxUrls {
212 pub fn production() -> Self {
214 Self {
215 rest: "https://www.okx.com".to_string(),
216 ws_public: "wss://ws.okx.com:8443/ws/v5/public".to_string(),
217 ws_private: "wss://ws.okx.com:8443/ws/v5/private".to_string(),
218 ws_business: "wss://ws.okx.com:8443/ws/v5/business".to_string(),
219 }
220 }
221
222 pub fn demo() -> Self {
224 Self {
225 rest: "https://www.okx.com".to_string(),
226 ws_public: "wss://wspap.okx.com:8443/ws/v5/public?brokerId=9999".to_string(),
227 ws_private: "wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999".to_string(),
228 ws_business: "wss://wspap.okx.com:8443/ws/v5/business?brokerId=9999".to_string(),
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_okx_creation() {
239 let config = ExchangeConfig {
240 id: "okx".to_string(),
241 name: "OKX".to_string(),
242 ..Default::default()
243 };
244
245 let okx = Okx::new(config);
246 assert!(okx.is_ok());
247
248 let okx = okx.unwrap();
249 assert_eq!(okx.id(), "okx");
250 assert_eq!(okx.name(), "OKX");
251 assert_eq!(okx.version(), "v5");
252 assert!(!okx.certified());
253 assert!(okx.pro());
254 }
255
256 #[test]
257 fn test_timeframes() {
258 let config = ExchangeConfig::default();
259 let okx = Okx::new(config).unwrap();
260 let timeframes = okx.timeframes();
261
262 assert!(timeframes.contains_key("1m"));
263 assert!(timeframes.contains_key("1h"));
264 assert!(timeframes.contains_key("1d"));
265 assert_eq!(timeframes.len(), 13);
266 }
267
268 #[test]
269 fn test_urls() {
270 let config = ExchangeConfig::default();
271 let okx = Okx::new(config).unwrap();
272 let urls = okx.urls();
273
274 assert!(urls.rest.contains("okx.com"));
275 assert!(urls.ws_public.contains("ws.okx.com"));
276 }
277
278 #[test]
279 fn test_sandbox_urls() {
280 let config = ExchangeConfig {
281 sandbox: true,
282 ..Default::default()
283 };
284 let okx = Okx::new(config).unwrap();
285 let urls = okx.urls();
286
287 assert!(urls.ws_public.contains("wspap.okx.com"));
288 assert!(urls.ws_public.contains("brokerId=9999"));
289 }
290
291 #[test]
292 fn test_default_options() {
293 let options = OkxOptions::default();
294 assert_eq!(options.account_mode, "cash");
295 assert!(!options.demo);
296 }
297}