Skip to main content

nautilus_deribit/
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 Deribit clients and components.
17
18use std::{any::Any, 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, TraderId},
30};
31
32use crate::{
33    common::consts::{DERIBIT, DERIBIT_VENUE},
34    config::{DeribitDataClientConfig, DeribitExecutionClientConfig},
35    data::DeribitDataClient,
36    execution::DeribitExecutionClient,
37};
38
39impl ClientConfig for DeribitDataClientConfig {
40    fn as_any(&self) -> &dyn Any {
41        self
42    }
43}
44
45/// Factory for creating Deribit data clients.
46#[derive(Debug, Clone)]
47#[cfg_attr(
48    feature = "python",
49    pyo3::pyclass(module = "nautilus_trader.adapters.deribit", from_py_object)
50)]
51#[cfg_attr(
52    feature = "python",
53    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.deribit")
54)]
55pub struct DeribitDataClientFactory;
56
57impl DeribitDataClientFactory {
58    /// Creates a new [`DeribitDataClientFactory`] instance.
59    #[must_use]
60    pub const fn new() -> Self {
61        Self
62    }
63}
64
65impl Default for DeribitDataClientFactory {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl DataClientFactory for DeribitDataClientFactory {
72    fn create(
73        &self,
74        name: &str,
75        config: &dyn ClientConfig,
76        _cache: CacheView,
77        _clock: Rc<RefCell<dyn Clock>>,
78    ) -> anyhow::Result<Box<dyn DataClient>> {
79        let deribit_config = config
80            .as_any()
81            .downcast_ref::<DeribitDataClientConfig>()
82            .ok_or_else(|| {
83                anyhow::anyhow!(
84                    "Invalid config type for DeribitDataClientFactory. Expected DeribitDataClientConfig, was {config:?}",
85                )
86            })?
87            .clone();
88
89        let client_id = ClientId::from(name);
90        let client = DeribitDataClient::new(client_id, deribit_config)?;
91        Ok(Box::new(client))
92    }
93
94    fn name(&self) -> &'static str {
95        DERIBIT
96    }
97
98    fn config_type(&self) -> &'static str {
99        "DeribitDataClientConfig"
100    }
101}
102
103impl ClientConfig for DeribitExecutionClientConfig {
104    fn as_any(&self) -> &dyn Any {
105        self
106    }
107}
108
109/// Factory for creating Deribit execution clients.
110#[derive(Debug, Clone)]
111#[cfg_attr(
112    feature = "python",
113    pyo3::pyclass(module = "nautilus_trader.adapters.deribit", from_py_object)
114)]
115#[cfg_attr(
116    feature = "python",
117    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.deribit")
118)]
119pub struct DeribitExecutionClientFactory;
120
121impl DeribitExecutionClientFactory {
122    /// Creates a new [`DeribitExecutionClientFactory`] instance.
123    #[must_use]
124    pub const fn new() -> Self {
125        Self
126    }
127}
128
129impl Default for DeribitExecutionClientFactory {
130    fn default() -> Self {
131        Self::new()
132    }
133}
134
135impl ExecutionClientFactory for DeribitExecutionClientFactory {
136    fn create(
137        &self,
138        trader_id: TraderId,
139        name: &str,
140        config: &dyn ClientConfig,
141        cache: CacheView,
142        _clock: Rc<RefCell<dyn Clock>>,
143    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
144        let deribit_config = config
145            .as_any()
146            .downcast_ref::<DeribitExecutionClientConfig>()
147            .ok_or_else(|| {
148                anyhow::anyhow!(
149                    "Invalid config type for DeribitExecutionClientFactory. Expected DeribitExecutionClientConfig, was {config:?}",
150                )
151            })?
152            .clone();
153
154        // Deribit uses netting (derivatives only, no hedging)
155        let oms_type = OmsType::Netting;
156        let account_type = AccountType::Margin;
157
158        let client_id = ClientId::from(name);
159        let core = ExecutionClientCore::new(
160            trader_id,
161            client_id,
162            *DERIBIT_VENUE,
163            oms_type,
164            deribit_config.account_id,
165            account_type,
166            None, // base_currency
167            cache,
168        );
169
170        let client = DeribitExecutionClient::new(core, deribit_config)?;
171        Ok(Box::new(client))
172    }
173
174    fn name(&self) -> &'static str {
175        DERIBIT
176    }
177
178    fn config_type(&self) -> &'static str {
179        "DeribitExecutionClientConfig"
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use std::{cell::RefCell, rc::Rc};
186
187    use nautilus_common::{
188        cache::Cache,
189        clock::VirtualClock,
190        factories::{ClientConfig, DataClientFactory},
191        live::runner::set_data_event_sender,
192        messages::DataEvent,
193    };
194    use rstest::rstest;
195
196    use super::*;
197    use crate::http::models::DeribitProductType;
198
199    fn setup_test_env() {
200        // Initialize data event sender for tests
201        let (sender, _receiver) = tokio::sync::mpsc::unbounded_channel::<DataEvent>();
202        set_data_event_sender(sender);
203    }
204
205    #[rstest]
206    fn test_deribit_data_client_factory_creation() {
207        let factory = DeribitDataClientFactory::new();
208        assert_eq!(factory.name(), DERIBIT);
209        assert_eq!(factory.config_type(), "DeribitDataClientConfig");
210    }
211
212    #[rstest]
213    fn test_deribit_data_client_factory_default() {
214        let factory = DeribitDataClientFactory::new();
215        assert_eq!(factory.name(), DERIBIT);
216    }
217
218    #[rstest]
219    fn test_deribit_data_client_config_implements_client_config() {
220        let config = DeribitDataClientConfig {
221            product_types: vec![DeribitProductType::Future],
222            ..Default::default()
223        };
224
225        let boxed_config: Box<dyn ClientConfig> = Box::new(config);
226        let downcasted = boxed_config
227            .as_any()
228            .downcast_ref::<DeribitDataClientConfig>();
229
230        assert!(downcasted.is_some());
231    }
232
233    #[rstest]
234    fn test_deribit_data_client_factory_creates_client() {
235        setup_test_env();
236
237        let factory = DeribitDataClientFactory::new();
238        let config = DeribitDataClientConfig {
239            product_types: vec![DeribitProductType::Future],
240            environment: crate::common::enums::DeribitEnvironment::Testnet,
241            ..Default::default()
242        };
243
244        let cache = Rc::new(RefCell::new(Cache::default()));
245        let clock = Rc::new(RefCell::new(VirtualClock::new()));
246
247        let result = factory.create("DERIBIT-TEST", &config, cache.into(), clock);
248        assert!(result.is_ok());
249
250        let client = result.unwrap();
251        assert_eq!(client.client_id(), ClientId::from("DERIBIT-TEST"));
252    }
253}