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)]
50pub struct BitmexExecFactoryConfig {
51    /// The trader ID for the execution client.
52    pub trader_id: TraderId,
53    /// The account ID for the execution client.
54    pub account_id: AccountId,
55    /// The underlying execution client configuration.
56    pub config: BitmexExecClientConfig,
57}
58
59impl ClientConfig for BitmexExecFactoryConfig {
60    fn as_any(&self) -> &dyn Any {
61        self
62    }
63}
64
65/// Factory for creating BitMEX data clients.
66#[derive(Debug)]
67pub struct BitmexDataClientFactory;
68
69impl BitmexDataClientFactory {
70    /// Creates a new [`BitmexDataClientFactory`] instance.
71    #[must_use]
72    pub const fn new() -> Self {
73        Self
74    }
75}
76
77impl Default for BitmexDataClientFactory {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83impl DataClientFactory for BitmexDataClientFactory {
84    fn create(
85        &self,
86        name: &str,
87        config: &dyn ClientConfig,
88        _cache: Rc<RefCell<Cache>>,
89        _clock: Rc<RefCell<dyn Clock>>,
90    ) -> anyhow::Result<Box<dyn DataClient>> {
91        let bitmex_config = config
92            .as_any()
93            .downcast_ref::<BitmexDataClientConfig>()
94            .ok_or_else(|| {
95                anyhow::anyhow!(
96                    "Invalid config type for BitmexDataClientFactory. Expected BitmexDataClientConfig, was {config:?}",
97                )
98            })?
99            .clone();
100
101        let client_id = ClientId::from(name);
102        let client = BitmexDataClient::new(client_id, bitmex_config)?;
103        Ok(Box::new(client))
104    }
105
106    fn name(&self) -> &'static str {
107        "BITMEX"
108    }
109
110    fn config_type(&self) -> &'static str {
111        "BitmexDataClientConfig"
112    }
113}
114
115/// Factory for creating BitMEX execution clients.
116#[derive(Debug)]
117pub struct BitmexExecutionClientFactory;
118
119impl BitmexExecutionClientFactory {
120    /// Creates a new [`BitmexExecutionClientFactory`] instance.
121    #[must_use]
122    pub const fn new() -> Self {
123        Self
124    }
125}
126
127impl Default for BitmexExecutionClientFactory {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133impl ExecutionClientFactory for BitmexExecutionClientFactory {
134    fn create(
135        &self,
136        name: &str,
137        config: &dyn ClientConfig,
138        cache: Rc<RefCell<Cache>>,
139    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
140        let factory_config = config
141            .as_any()
142            .downcast_ref::<BitmexExecFactoryConfig>()
143            .ok_or_else(|| {
144                anyhow::anyhow!(
145                    "Invalid config type for BitmexExecutionClientFactory. Expected BitmexExecFactoryConfig, was {config:?}",
146                )
147            })?
148            .clone();
149
150        let mut bitmex_config = factory_config.config;
151        bitmex_config.account_id = Some(factory_config.account_id);
152
153        let core = ExecutionClientCore::new(
154            factory_config.trader_id,
155            ClientId::from(name),
156            *BITMEX_VENUE,
157            OmsType::Netting,
158            factory_config.account_id,
159            AccountType::Margin,
160            None, // base_currency
161            cache,
162        );
163
164        let client = BitmexExecutionClient::new(core, bitmex_config)?;
165        Ok(Box::new(client))
166    }
167
168    fn name(&self) -> &'static str {
169        "BITMEX"
170    }
171
172    fn config_type(&self) -> &'static str {
173        "BitmexExecFactoryConfig"
174    }
175}