nautilus_interactive_brokers/python/
providers.rs1use nautilus_core::python::to_pyruntime_err;
19use nautilus_model::{identifiers::InstrumentId, python::instruments::instrument_any_to_pyobject};
20use pyo3::{prelude::*, types::PyList};
21
22use crate::{
23 config::InteractiveBrokersInstrumentProviderConfig,
24 providers::instruments::InteractiveBrokersInstrumentProvider,
25 python::conversion::{contract_details_to_pyobject, py_to_contract},
26};
27
28#[cfg(feature = "python")]
29#[pymethods]
30#[pyo3_stub_gen::derive::gen_stub_pymethods]
31impl InteractiveBrokersInstrumentProvider {
32 #[new]
33 fn py_new(config: InteractiveBrokersInstrumentProviderConfig) -> Self {
34 Self::new(config)
35 }
36
37 fn __repr__(&self) -> String {
38 format!("{self:?}")
39 }
40
41 #[pyo3(name = "find")]
43 fn py_find(&self, py: Python, instrument_id: InstrumentId) -> PyResult<Option<Py<PyAny>>> {
44 match self.find(&instrument_id) {
45 Some(instrument) => Ok(Some(instrument_any_to_pyobject(py, instrument)?)),
46 None => Ok(None),
47 }
48 }
49
50 #[pyo3(name = "find_by_contract_id")]
52 fn py_find_by_contract_id(&self, py: Python, contract_id: i32) -> PyResult<Option<Py<PyAny>>> {
53 match self.find_by_contract_id(contract_id) {
54 Some(instrument) => Ok(Some(instrument_any_to_pyobject(py, instrument)?)),
55 None => Ok(None),
56 }
57 }
58
59 #[pyo3(name = "get_all")]
61 fn py_get_all<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyList>> {
62 let instruments = self.get_all();
63 let py_instruments: PyResult<Vec<_>> = instruments
64 .into_iter()
65 .map(|inst| instrument_any_to_pyobject(py, inst))
66 .collect();
67 PyList::new(py, py_instruments?)
68 }
69
70 #[pyo3(name = "count")]
72 fn py_count(&self) -> usize {
73 self.count()
74 }
75
76 #[pyo3(name = "get_price_magnifier")]
78 fn py_get_price_magnifier(&self, instrument_id: InstrumentId) -> i32 {
79 self.get_price_magnifier(&instrument_id)
80 }
81
82 #[pyo3(name = "fetch_contract_details")]
87 fn py_fetch_contract_details(&self) {}
88
89 #[pyo3(name = "determine_venue")]
91 #[allow(clippy::needless_pass_by_value)]
92 fn py_determine_venue(&self, py: Python<'_>, contract: Py<PyAny>) -> PyResult<String> {
93 let rust_contract = py_to_contract(contract.bind(py))?;
94 Ok(self.determine_venue(&rust_contract, None).to_string())
95 }
96
97 #[pyo3(name = "instrument_id_to_ib_contract_details")]
99 fn py_instrument_id_to_ib_contract_details(
100 &self,
101 py: Python<'_>,
102 instrument_id: InstrumentId,
103 ) -> PyResult<Option<Py<PyAny>>> {
104 self.instrument_id_to_ib_contract_details(&instrument_id)
105 .as_ref()
106 .map(|details| contract_details_to_pyobject(py, details))
107 .transpose()
108 }
109
110 #[pyo3(name = "save_cache")]
116 fn py_save_cache<'py>(
117 &self,
118 py: Python<'py>,
119 cache_path: String,
120 ) -> PyResult<Bound<'py, PyAny>> {
121 let provider = self.clone();
122 pyo3_async_runtimes::tokio::future_into_py(py, async move {
123 provider
124 .save_cache(&cache_path)
125 .await
126 .map_err(to_pyruntime_err)
127 })
128 }
129
130 #[pyo3(name = "load_cache")]
140 fn py_load_cache<'py>(
141 &self,
142 py: Python<'py>,
143 cache_path: String,
144 ) -> PyResult<Bound<'py, PyAny>> {
145 let provider = self.clone();
146 pyo3_async_runtimes::tokio::future_into_py(py, async move {
147 provider
148 .load_cache(&cache_path)
149 .await
150 .map_err(to_pyruntime_err)
151 })
152 }
153}