nautilus_binance/
factories.rs1use std::{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::ClientId,
30};
31
32use crate::{
33 common::{
34 consts::{BINANCE, BINANCE_VENUE},
35 enums::BinanceProductType,
36 },
37 config::{BinanceDataClientConfig, BinanceExecClientConfig},
38 futures::{data::BinanceFuturesDataClient, execution::BinanceFuturesExecutionClient},
39 spot::{data::BinanceSpotDataClient, execution::BinanceSpotExecutionClient},
40};
41
42#[derive(Debug, Clone)]
44#[cfg_attr(
45 feature = "python",
46 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", from_py_object)
47)]
48#[cfg_attr(
49 feature = "python",
50 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.binance")
51)]
52pub struct BinanceDataClientFactory;
53
54impl BinanceDataClientFactory {
55 #[must_use]
57 pub const fn new() -> Self {
58 Self
59 }
60}
61
62impl Default for BinanceDataClientFactory {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68impl DataClientFactory for BinanceDataClientFactory {
69 fn create(
70 &self,
71 name: &str,
72 config: &dyn ClientConfig,
73 _cache: Rc<RefCell<Cache>>,
74 _clock: Rc<RefCell<dyn Clock>>,
75 ) -> anyhow::Result<Box<dyn DataClient>> {
76 let binance_config = config
77 .as_any()
78 .downcast_ref::<BinanceDataClientConfig>()
79 .ok_or_else(|| {
80 anyhow::anyhow!(
81 "Invalid config type for BinanceDataClientFactory. Expected BinanceDataClientConfig, was {config:?}",
82 )
83 })?
84 .clone();
85
86 let client_id = ClientId::from(name);
87
88 let product_type = binance_config
89 .product_types
90 .first()
91 .copied()
92 .unwrap_or(BinanceProductType::Spot);
93
94 match product_type {
95 BinanceProductType::Spot => {
96 let client = BinanceSpotDataClient::new(client_id, binance_config)?;
97 Ok(Box::new(client))
98 }
99 BinanceProductType::UsdM | BinanceProductType::CoinM => {
100 let client =
101 BinanceFuturesDataClient::new(client_id, binance_config, product_type)?;
102 Ok(Box::new(client))
103 }
104 _ => {
105 anyhow::bail!("Unsupported product type for Binance data client: {product_type:?}")
106 }
107 }
108 }
109
110 fn name(&self) -> &'static str {
111 BINANCE
112 }
113
114 fn config_type(&self) -> &'static str {
115 stringify!(BinanceDataClientConfig)
116 }
117}
118
119#[derive(Debug, Clone)]
121#[cfg_attr(
122 feature = "python",
123 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", from_py_object)
124)]
125#[cfg_attr(
126 feature = "python",
127 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.binance")
128)]
129pub struct BinanceExecutionClientFactory;
130
131impl BinanceExecutionClientFactory {
132 #[must_use]
134 pub const fn new() -> Self {
135 Self
136 }
137}
138
139impl Default for BinanceExecutionClientFactory {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145impl ExecutionClientFactory for BinanceExecutionClientFactory {
146 fn create(
147 &self,
148 name: &str,
149 config: &dyn ClientConfig,
150 cache: Rc<RefCell<Cache>>,
151 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
152 let binance_config = config
153 .as_any()
154 .downcast_ref::<BinanceExecClientConfig>()
155 .ok_or_else(|| {
156 anyhow::anyhow!(
157 "Invalid config type for BinanceExecutionClientFactory. Expected BinanceExecClientConfig, was {config:?}",
158 )
159 })?
160 .clone();
161
162 let product_type = binance_config
163 .product_types
164 .first()
165 .copied()
166 .unwrap_or(BinanceProductType::Spot);
167
168 match product_type {
169 BinanceProductType::Spot => {
170 let account_type = AccountType::Cash;
172 let oms_type = OmsType::Hedging;
173
174 let core = ExecutionClientCore::new(
175 binance_config.trader_id,
176 ClientId::from(name),
177 *BINANCE_VENUE,
178 oms_type,
179 binance_config.account_id,
180 account_type,
181 None, cache,
183 );
184
185 let client = BinanceSpotExecutionClient::new(core, binance_config)?;
186 Ok(Box::new(client))
187 }
188 BinanceProductType::UsdM | BinanceProductType::CoinM => {
189 let account_type = AccountType::Margin;
191 let oms_type = OmsType::Netting;
192
193 let core = ExecutionClientCore::new(
194 binance_config.trader_id,
195 ClientId::from(name),
196 *BINANCE_VENUE,
197 oms_type,
198 binance_config.account_id,
199 account_type,
200 None, cache,
202 );
203
204 let client = BinanceFuturesExecutionClient::new(core, binance_config)?;
205 Ok(Box::new(client))
206 }
207 _ => {
208 anyhow::bail!(
209 "Unsupported product type for Binance execution client: {product_type:?}"
210 )
211 }
212 }
213 }
214
215 fn name(&self) -> &'static str {
216 BINANCE
217 }
218
219 fn config_type(&self) -> &'static str {
220 stringify!(BinanceExecClientConfig)
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use nautilus_common::factories::DataClientFactory;
227 use rstest::rstest;
228
229 use super::*;
230
231 #[rstest]
232 fn test_binance_data_client_factory_creation() {
233 let factory = BinanceDataClientFactory::new();
234 assert_eq!(factory.name(), "BINANCE");
235 assert_eq!(factory.config_type(), "BinanceDataClientConfig");
236 }
237
238 #[rstest]
239 fn test_binance_data_client_factory_default() {
240 let factory = BinanceDataClientFactory;
241 assert_eq!(factory.name(), "BINANCE");
242 }
243}