use std::{any::Any, cell::RefCell, rc::Rc};
use nautilus_common::{
cache::Cache,
clients::{DataClient, ExecutionClient},
clock::Clock,
};
use nautilus_live::ExecutionClientCore;
use nautilus_model::{
enums::{AccountType, OmsType},
identifiers::{AccountId, ClientId, TraderId},
};
use nautilus_system::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
use crate::{
common::consts::BITMEX_VENUE,
config::{BitmexDataClientConfig, BitmexExecClientConfig},
data::BitmexDataClient,
execution::BitmexExecutionClient,
};
impl ClientConfig for BitmexDataClientConfig {
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
)]
pub struct BitmexExecFactoryConfig {
pub trader_id: TraderId,
pub account_id: AccountId,
pub config: BitmexExecClientConfig,
}
impl BitmexExecFactoryConfig {
#[must_use]
pub fn new(trader_id: TraderId, config: BitmexExecClientConfig) -> Self {
Self {
trader_id,
account_id: AccountId::from("BITMEX-001"),
config,
}
}
}
impl ClientConfig for BitmexExecFactoryConfig {
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
)]
pub struct BitmexDataClientFactory;
impl BitmexDataClientFactory {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Default for BitmexDataClientFactory {
fn default() -> Self {
Self::new()
}
}
impl DataClientFactory for BitmexDataClientFactory {
fn create(
&self,
name: &str,
config: &dyn ClientConfig,
_cache: Rc<RefCell<Cache>>,
_clock: Rc<RefCell<dyn Clock>>,
) -> anyhow::Result<Box<dyn DataClient>> {
let bitmex_config = config
.as_any()
.downcast_ref::<BitmexDataClientConfig>()
.ok_or_else(|| {
anyhow::anyhow!(
"Invalid config type for BitmexDataClientFactory. Expected BitmexDataClientConfig, was {config:?}",
)
})?
.clone();
let client_id = ClientId::from(name);
let client = BitmexDataClient::new(client_id, bitmex_config)?;
Ok(Box::new(client))
}
fn name(&self) -> &'static str {
"BITMEX"
}
fn config_type(&self) -> &'static str {
"BitmexDataClientConfig"
}
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.bitmex", from_py_object)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.bitmex")
)]
pub struct BitmexExecutionClientFactory;
impl BitmexExecutionClientFactory {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Default for BitmexExecutionClientFactory {
fn default() -> Self {
Self::new()
}
}
impl ExecutionClientFactory for BitmexExecutionClientFactory {
fn create(
&self,
name: &str,
config: &dyn ClientConfig,
cache: Rc<RefCell<Cache>>,
) -> anyhow::Result<Box<dyn ExecutionClient>> {
let factory_config = config
.as_any()
.downcast_ref::<BitmexExecFactoryConfig>()
.ok_or_else(|| {
anyhow::anyhow!(
"Invalid config type for BitmexExecutionClientFactory. Expected BitmexExecFactoryConfig, was {config:?}",
)
})?
.clone();
let mut bitmex_config = factory_config.config;
bitmex_config.account_id = Some(factory_config.account_id);
let core = ExecutionClientCore::new(
factory_config.trader_id,
ClientId::from(name),
*BITMEX_VENUE,
OmsType::Netting,
factory_config.account_id,
AccountType::Margin,
None, cache,
);
let client = BitmexExecutionClient::new(core, bitmex_config)?;
Ok(Box::new(client))
}
fn name(&self) -> &'static str {
"BITMEX"
}
fn config_type(&self) -> &'static str {
"BitmexExecFactoryConfig"
}
}