nautilus_indicators/python/ratio/
efficiency_ratio.rs1use nautilus_core::python::to_pyvalue_err;
17use nautilus_model::{
18 data::Bar,
19 enums::PriceType,
20 types::{Money, Price, Quantity, fixed::MAX_FLOAT_PRECISION},
21};
22use pyo3::prelude::*;
23
24use crate::{indicator::Indicator, ratio::efficiency_ratio::EfficiencyRatio};
25
26#[pymethods]
27#[pyo3_stub_gen::derive::gen_stub_pymethods]
28impl EfficiencyRatio {
29 #[new]
49 #[pyo3(signature = (period, price_type=None))]
50 fn py_new(period: usize, price_type: Option<PriceType>) -> PyResult<Self> {
51 Self::new_checked(period, price_type).map_err(to_pyvalue_err)
52 }
53
54 fn __repr__(&self) -> String {
55 format!("EfficiencyRatio({})", self.period)
56 }
57
58 #[getter]
59 #[pyo3(name = "name")]
60 fn py_name(&self) -> String {
61 self.name()
62 }
63
64 #[getter]
65 #[pyo3(name = "period")]
66 const fn py_period(&self) -> usize {
67 self.period
68 }
69
70 #[getter]
71 #[pyo3(name = "value")]
72 const fn py_value(&self) -> f64 {
73 self.value
74 }
75
76 #[getter]
77 #[pyo3(name = "initialized")]
78 const fn py_initialized(&self) -> bool {
79 self.initialized
80 }
81
82 #[getter]
83 #[pyo3(name = "has_inputs")]
84 fn py_has_inputs(&self) -> bool {
85 self.has_inputs()
86 }
87
88 #[pyo3(name = "update_raw")]
89 fn py_update_raw(
90 &mut self,
91 #[gen_stub(override_type(type_repr = "float"))] value: &Bound<'_, PyAny>,
92 ) -> PyResult<()> {
93 let value = extract_update_value(value)?;
94 self.update_raw(value);
95 Ok(())
96 }
97
98 #[pyo3(name = "handle_bar")]
99 fn py_handle_bar(&mut self, bar: &Bar) -> PyResult<()> {
100 check_float_precision(bar.close.precision)?;
101
102 self.handle_bar(bar);
103 Ok(())
104 }
105
106 #[pyo3(name = "reset")]
107 fn py_reset(&mut self) {
108 self.reset();
109 }
110}
111
112fn extract_update_value(value: &Bound<'_, PyAny>) -> PyResult<f64> {
113 if value.is_instance_of::<Price>() {
114 let price = value.extract::<Price>()?;
115 check_float_precision(price.precision)?;
116 return Ok(price.as_f64());
117 }
118
119 if value.is_instance_of::<Quantity>() {
120 let quantity = value.extract::<Quantity>()?;
121 check_float_precision(quantity.precision)?;
122 return Ok(quantity.as_f64());
123 }
124
125 if value.is_instance_of::<Money>() {
126 let money = value.extract::<Money>()?;
127 check_float_precision(money.currency.precision)?;
128 return Ok(money.as_f64());
129 }
130
131 value.extract()
132}
133
134fn check_float_precision(precision: u8) -> PyResult<()> {
135 if precision > MAX_FLOAT_PRECISION {
136 return Err(to_pyvalue_err(format!(
137 "Fixed-point precision {precision} exceeds maximum float precision {MAX_FLOAT_PRECISION}",
138 )));
139 }
140
141 Ok(())
142}