Skip to main content

nautilus_bitmex/
factories.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Factory functions for creating BitMEX clients and components.
17
18use std::{any::Any, cell::RefCell, rc::Rc};
19
20use nautilus_common::{
21    cache::Cache,
22    clients::{DataClient, ExecutionClient},
23    clock::Clock,
24};
25use nautilus_live::ExecutionClientCore;
26use nautilus_model::{
27    enums::{AccountType, OmsType},
28    identifiers::{AccountId, ClientId, TraderId},
29};
30use nautilus_system::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
31
32use crate::{
33    common::consts::BITMEX_VENUE,
34    config::{BitmexDataClientConfig, BitmexExecClientConfig},
35    data::BitmexDataClient,
36    execution::BitmexExecutionClient,
37};
38
39impl ClientConfig for BitmexDataClientConfig {
40    fn as_any(&self) -> &dyn Any {
41        self
42    }
43}
44
45/// Configuration for creating BitMEX execution clients via factory.
46///
47/// This wraps [`BitmexExecClientConfig`] with the additional trader and account
48/// identifiers required by the [`ExecutionClientCore`].
49#[derive(Clone, Debug)]
50#[cfg_attr(
51    feature = "python",
52    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
53)]
54pub struct BitmexExecFactoryConfig {
55    /// The trader ID for the execution client.
56    pub trader_id: TraderId,
57    /// The account ID for the execution client.
58    pub account_id: AccountId,
59    /// The underlying execution client configuration.
60    pub config: BitmexExecClientConfig,
61}
62
63impl BitmexExecFactoryConfig {
64    /// Creates a new [`BitmexExecFactoryConfig`].
65    ///
66    /// The `account_id` defaults to `BITMEX-001` and is overridden once the
67    /// real account number is detected from the API.
68    #[must_use]
69    pub fn new(trader_id: TraderId, config: BitmexExecClientConfig) -> Self {
70        Self {
71            trader_id,
72            account_id: AccountId::from("BITMEX-001"),
73            config,
74        }
75    }
76}
77
78impl ClientConfig for BitmexExecFactoryConfig {
79    fn as_any(&self) -> &dyn Any {
80        self
81    }
82}
83
84/// Factory for creating BitMEX data clients.
85#[derive(Debug, Clone)]
86#[cfg_attr(
87    feature = "python",
88    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
89)]
90pub struct BitmexDataClientFactory;
91
92impl BitmexDataClientFactory {
93    /// Creates a new [`BitmexDataClientFactory`] instance.
94    #[must_use]
95    pub const fn new() -> Self {
96        Self
97    }
98}
99
100impl Default for BitmexDataClientFactory {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106impl DataClientFactory for BitmexDataClientFactory {
107    fn create(
108        &self,
109        name: &str,
110        config: &dyn ClientConfig,
111        _cache: Rc<RefCell<Cache>>,
112        _clock: Rc<RefCell<dyn Clock>>,
113    ) -> anyhow::Result<Box<dyn DataClient>> {
114        let bitmex_config = config
115            .as_any()
116            .downcast_ref::<BitmexDataClientConfig>()
117            .ok_or_else(|| {
118                anyhow::anyhow!(
119                    "Invalid config type for BitmexDataClientFactory. Expected BitmexDataClientConfig, was {config:?}",
120                )
121            })?
122            .clone();
123
124        let client_id = ClientId::from(name);
125        let client = BitmexDataClient::new(client_id, bitmex_config)?;
126        Ok(Box::new(client))
127    }
128
129    fn name(&self) -> &'static str {
130        "BITMEX"
131    }
132
133    fn config_type(&self) -> &'static str {
134        "BitmexDataClientConfig"
135    }
136}
137
138/// Factory for creating BitMEX execution clients.
139#[derive(Debug, Clone)]
140#[cfg_attr(
141    feature = "python",
142    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
143)]
144pub struct BitmexExecutionClientFactory;
145
146impl BitmexExecutionClientFactory {
147    /// Creates a new [`BitmexExecutionClientFactory`] instance.
148    #[must_use]
149    pub const fn new() -> Self {
150        Self
151    }
152}
153
154impl Default for BitmexExecutionClientFactory {
155    fn default() -> Self {
156        Self::new()
157    }
158}
159
160impl ExecutionClientFactory for BitmexExecutionClientFactory {
161    fn create(
162        &self,
163        name: &str,
164        config: &dyn ClientConfig,
165        cache: Rc<RefCell<Cache>>,
166    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
167        let factory_config = config
168            .as_any()
169            .downcast_ref::<BitmexExecFactoryConfig>()
170            .ok_or_else(|| {
171                anyhow::anyhow!(
172                    "Invalid config type for BitmexExecutionClientFactory. Expected BitmexExecFactoryConfig, was {config:?}",
173                )
174            })?
175            .clone();
176
177        let mut bitmex_config = factory_config.config;
178        bitmex_config.account_id = Some(factory_config.account_id);
179
180        let core = ExecutionClientCore::new(
181            factory_config.trader_id,
182            ClientId::from(name),
183            *BITMEX_VENUE,
184            OmsType::Netting,
185            factory_config.account_id,
186            AccountType::Margin,
187            None, // base_currency
188            cache,
189        );
190
191        let client = BitmexExecutionClient::new(core, bitmex_config)?;
192        Ok(Box::new(client))
193    }
194
195    fn name(&self) -> &'static str {
196        "BITMEX"
197    }
198
199    fn config_type(&self) -> &'static str {
200        "BitmexExecFactoryConfig"
201    }
202}