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