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    factories::{ClientConfig, DataClientFactory, ExecutionClientFactory},
25};
26use nautilus_live::ExecutionClientCore;
27use nautilus_model::{
28    enums::{AccountType, OmsType},
29    identifiers::{AccountId, ClientId, TraderId},
30};
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)]
54#[cfg_attr(
55    feature = "python",
56    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
57)]
58pub struct BitmexExecFactoryConfig {
59    /// The trader ID for the execution client.
60    pub trader_id: TraderId,
61    /// The account ID for the execution client.
62    pub account_id: AccountId,
63    /// The underlying execution client configuration.
64    pub config: BitmexExecClientConfig,
65}
66
67impl BitmexExecFactoryConfig {
68    /// Creates a new [`BitmexExecFactoryConfig`].
69    ///
70    /// The `account_id` defaults to `BITMEX-001` and is overridden once the
71    /// real account number is detected from the API.
72    #[must_use]
73    pub fn new(trader_id: TraderId, config: BitmexExecClientConfig) -> Self {
74        Self {
75            trader_id,
76            account_id: AccountId::from("BITMEX-001"),
77            config,
78        }
79    }
80}
81
82impl ClientConfig for BitmexExecFactoryConfig {
83    fn as_any(&self) -> &dyn Any {
84        self
85    }
86}
87
88/// Factory for creating BitMEX data clients.
89#[derive(Debug, Clone)]
90#[cfg_attr(
91    feature = "python",
92    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
93)]
94#[cfg_attr(
95    feature = "python",
96    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
97)]
98pub struct BitmexDataClientFactory;
99
100impl BitmexDataClientFactory {
101    /// Creates a new [`BitmexDataClientFactory`] instance.
102    #[must_use]
103    pub const fn new() -> Self {
104        Self
105    }
106}
107
108impl Default for BitmexDataClientFactory {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114impl DataClientFactory for BitmexDataClientFactory {
115    fn create(
116        &self,
117        name: &str,
118        config: &dyn ClientConfig,
119        _cache: Rc<RefCell<Cache>>,
120        _clock: Rc<RefCell<dyn Clock>>,
121    ) -> anyhow::Result<Box<dyn DataClient>> {
122        let bitmex_config = config
123            .as_any()
124            .downcast_ref::<BitmexDataClientConfig>()
125            .ok_or_else(|| {
126                anyhow::anyhow!(
127                    "Invalid config type for BitmexDataClientFactory. Expected BitmexDataClientConfig, was {config:?}",
128                )
129            })?
130            .clone();
131
132        let client_id = ClientId::from(name);
133        let client = BitmexDataClient::new(client_id, bitmex_config)?;
134        Ok(Box::new(client))
135    }
136
137    fn name(&self) -> &'static str {
138        "BITMEX"
139    }
140
141    fn config_type(&self) -> &'static str {
142        "BitmexDataClientConfig"
143    }
144}
145
146/// Factory for creating BitMEX execution clients.
147#[derive(Debug, Clone)]
148#[cfg_attr(
149    feature = "python",
150    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
151)]
152#[cfg_attr(
153    feature = "python",
154    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
155)]
156pub struct BitmexExecutionClientFactory;
157
158impl BitmexExecutionClientFactory {
159    /// Creates a new [`BitmexExecutionClientFactory`] instance.
160    #[must_use]
161    pub const fn new() -> Self {
162        Self
163    }
164}
165
166impl Default for BitmexExecutionClientFactory {
167    fn default() -> Self {
168        Self::new()
169    }
170}
171
172impl ExecutionClientFactory for BitmexExecutionClientFactory {
173    fn create(
174        &self,
175        name: &str,
176        config: &dyn ClientConfig,
177        cache: Rc<RefCell<Cache>>,
178    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
179        let factory_config = config
180            .as_any()
181            .downcast_ref::<BitmexExecFactoryConfig>()
182            .ok_or_else(|| {
183                anyhow::anyhow!(
184                    "Invalid config type for BitmexExecutionClientFactory. Expected BitmexExecFactoryConfig, was {config:?}",
185                )
186            })?
187            .clone();
188
189        let mut bitmex_config = factory_config.config;
190        bitmex_config.account_id = Some(factory_config.account_id);
191
192        let core = ExecutionClientCore::new(
193            factory_config.trader_id,
194            ClientId::from(name),
195            *BITMEX_VENUE,
196            OmsType::Netting,
197            factory_config.account_id,
198            AccountType::Margin,
199            None, // base_currency
200            cache,
201        );
202
203        let client = BitmexExecutionClient::new(core, bitmex_config)?;
204        Ok(Box::new(client))
205    }
206
207    fn name(&self) -> &'static str {
208        "BITMEX"
209    }
210
211    fn config_type(&self) -> &'static str {
212        "BitmexExecFactoryConfig"
213    }
214}