nautilus_binance/
factories.rs1use std::{cell::RefCell, rc::Rc};
19
20use nautilus_common::{
21 cache::CacheView,
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.adapters.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: CacheView,
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.product_type;
89
90 match product_type {
91 BinanceProductType::Spot => {
92 let client = BinanceSpotDataClient::new(client_id, binance_config)?;
93 Ok(Box::new(client))
94 }
95 BinanceProductType::UsdM | BinanceProductType::CoinM => {
96 let client =
97 BinanceFuturesDataClient::new(client_id, binance_config, product_type)?;
98 Ok(Box::new(client))
99 }
100 _ => {
101 anyhow::bail!("Unsupported product type for Binance data client: {product_type:?}")
102 }
103 }
104 }
105
106 fn name(&self) -> &'static str {
107 BINANCE
108 }
109
110 fn config_type(&self) -> &'static str {
111 stringify!(BinanceDataClientConfig)
112 }
113}
114
115#[derive(Debug, Clone)]
117#[cfg_attr(
118 feature = "python",
119 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", from_py_object)
120)]
121#[cfg_attr(
122 feature = "python",
123 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.binance")
124)]
125pub struct BinanceExecutionClientFactory;
126
127impl BinanceExecutionClientFactory {
128 #[must_use]
130 pub const fn new() -> Self {
131 Self
132 }
133}
134
135impl Default for BinanceExecutionClientFactory {
136 fn default() -> Self {
137 Self::new()
138 }
139}
140
141impl ExecutionClientFactory for BinanceExecutionClientFactory {
142 fn create(
143 &self,
144 name: &str,
145 config: &dyn ClientConfig,
146 cache: CacheView,
147 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
148 let binance_config = config
149 .as_any()
150 .downcast_ref::<BinanceExecClientConfig>()
151 .ok_or_else(|| {
152 anyhow::anyhow!(
153 "Invalid config type for BinanceExecutionClientFactory. Expected BinanceExecClientConfig, was {config:?}",
154 )
155 })?
156 .clone();
157
158 let product_type = binance_config.product_type;
159
160 match product_type {
161 BinanceProductType::Spot => {
162 let account_type = AccountType::Cash;
164 let oms_type = OmsType::Hedging;
165
166 let core = ExecutionClientCore::new(
167 binance_config.trader_id,
168 ClientId::from(name),
169 *BINANCE_VENUE,
170 oms_type,
171 binance_config.account_id,
172 account_type,
173 None, cache,
175 );
176
177 let client = BinanceSpotExecutionClient::new(core, binance_config)?;
178 Ok(Box::new(client))
179 }
180 BinanceProductType::UsdM | BinanceProductType::CoinM => {
181 let account_type = AccountType::Margin;
183 let oms_type = OmsType::Netting;
184
185 let core = ExecutionClientCore::new(
186 binance_config.trader_id,
187 ClientId::from(name),
188 *BINANCE_VENUE,
189 oms_type,
190 binance_config.account_id,
191 account_type,
192 None, cache,
194 );
195
196 let client = BinanceFuturesExecutionClient::new(core, binance_config)?;
197 Ok(Box::new(client))
198 }
199 _ => {
200 anyhow::bail!(
201 "Unsupported product type for Binance execution client: {product_type:?}"
202 )
203 }
204 }
205 }
206
207 fn name(&self) -> &'static str {
208 BINANCE
209 }
210
211 fn config_type(&self) -> &'static str {
212 stringify!(BinanceExecClientConfig)
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use nautilus_common::factories::DataClientFactory;
219 use rstest::rstest;
220
221 use super::*;
222
223 #[rstest]
224 fn test_binance_data_client_factory_creation() {
225 let factory = BinanceDataClientFactory::new();
226 assert_eq!(factory.name(), BINANCE);
227 assert_eq!(factory.config_type(), "BinanceDataClientConfig");
228 }
229
230 #[rstest]
231 fn test_binance_data_client_factory_default() {
232 let factory = BinanceDataClientFactory;
233 assert_eq!(factory.name(), BINANCE);
234 }
235}