nautilus_binance/
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 Binance clients and components.
17
18use std::{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::ClientId,
29};
30use nautilus_system::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
31
32use crate::{
33    common::consts::{BINANCE, BINANCE_VENUE},
34    config::{BinanceDataClientConfig, BinanceExecClientConfig},
35    data::BinanceSpotDataClient,
36    execution::BinanceSpotExecutionClient,
37};
38
39/// Factory for creating Binance data clients.
40#[derive(Debug)]
41pub struct BinanceDataClientFactory;
42
43impl BinanceDataClientFactory {
44    /// Creates a new [`BinanceDataClientFactory`] instance.
45    #[must_use]
46    pub const fn new() -> Self {
47        Self
48    }
49}
50
51impl Default for BinanceDataClientFactory {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl DataClientFactory for BinanceDataClientFactory {
58    fn create(
59        &self,
60        name: &str,
61        config: &dyn ClientConfig,
62        _cache: Rc<RefCell<Cache>>,
63        _clock: Rc<RefCell<dyn Clock>>,
64    ) -> anyhow::Result<Box<dyn DataClient>> {
65        let binance_config = config
66            .as_any()
67            .downcast_ref::<BinanceDataClientConfig>()
68            .ok_or_else(|| {
69                anyhow::anyhow!(
70                    "Invalid config type for BinanceDataClientFactory. Expected BinanceDataClientConfig, was {config:?}",
71                )
72            })?
73            .clone();
74
75        let client_id = ClientId::from(name);
76        let client = BinanceSpotDataClient::new(client_id, binance_config)?;
77        Ok(Box::new(client))
78    }
79
80    fn name(&self) -> &'static str {
81        BINANCE
82    }
83
84    fn config_type(&self) -> &'static str {
85        stringify!(BinanceDataClientConfig)
86    }
87}
88
89/// Factory for creating Binance Spot execution clients.
90#[derive(Debug)]
91pub struct BinanceExecutionClientFactory;
92
93impl BinanceExecutionClientFactory {
94    /// Creates a new [`BinanceExecutionClientFactory`] instance.
95    #[must_use]
96    pub const fn new() -> Self {
97        Self
98    }
99}
100
101impl Default for BinanceExecutionClientFactory {
102    fn default() -> Self {
103        Self::new()
104    }
105}
106
107impl ExecutionClientFactory for BinanceExecutionClientFactory {
108    fn create(
109        &self,
110        name: &str,
111        config: &dyn ClientConfig,
112        cache: Rc<RefCell<Cache>>,
113        clock: Rc<RefCell<dyn Clock>>,
114    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
115        let binance_config = config
116            .as_any()
117            .downcast_ref::<BinanceExecClientConfig>()
118            .ok_or_else(|| {
119                anyhow::anyhow!(
120                    "Invalid config type for BinanceExecutionClientFactory. Expected BinanceExecClientConfig, was {config:?}",
121                )
122            })?
123            .clone();
124
125        // Spot uses cash account type and hedging OMS
126        let account_type = AccountType::Cash;
127        let oms_type = OmsType::Hedging;
128
129        let core = ExecutionClientCore::new(
130            binance_config.trader_id,
131            ClientId::from(name),
132            *BINANCE_VENUE,
133            oms_type,
134            binance_config.account_id,
135            account_type,
136            None, // base_currency
137            clock,
138            cache,
139        );
140
141        let client = BinanceSpotExecutionClient::new(core, binance_config)?;
142
143        Ok(Box::new(client))
144    }
145
146    fn name(&self) -> &'static str {
147        BINANCE
148    }
149
150    fn config_type(&self) -> &'static str {
151        stringify!(BinanceExecClientConfig)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use nautilus_system::factories::DataClientFactory;
158    use rstest::rstest;
159
160    use super::*;
161
162    #[rstest]
163    fn test_binance_data_client_factory_creation() {
164        let factory = BinanceDataClientFactory::new();
165        assert_eq!(factory.name(), "BINANCE");
166        assert_eq!(factory.config_type(), "BinanceDataClientConfig");
167    }
168
169    #[rstest]
170    fn test_binance_data_client_factory_default() {
171        let factory = BinanceDataClientFactory;
172        assert_eq!(factory.name(), "BINANCE");
173    }
174}