Skip to main content

nautilus_indicators/python/momentum/
stochastics.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
16use nautilus_model::data::Bar;
17use pyo3::prelude::*;
18
19use crate::{
20    average::MovingAverageType,
21    indicator::Indicator,
22    momentum::stochastics::{Stochastics, StochasticsDMethod},
23};
24
25#[pymethods]
26#[pyo3_stub_gen::derive::gen_stub_pymethods]
27impl Stochastics {
28    /// Creates a new `Stochastics` instance with default parameters.
29    ///
30    /// This is the backward-compatible constructor that produces identical output
31    /// to the original Nautilus implementation, setting the following to:
32    /// - `slowing = 1` (no slowing applied to %K)
33    /// - `ma_type = Exponential` (unused when slowing = 1 or with Ratio method)
34    /// - `d_method = Ratio` (Nautilus native %D calculation)
35    #[new]
36    #[pyo3(signature = (period_k, period_d, slowing=None, ma_type=None, d_method=None))]
37    #[must_use]
38    pub fn py_new(
39        period_k: usize,
40        period_d: usize,
41        slowing: Option<usize>,
42        ma_type: Option<MovingAverageType>,
43        d_method: Option<StochasticsDMethod>,
44    ) -> Self {
45        Self::new_with_params(
46            period_k,
47            period_d,
48            slowing.unwrap_or(1),
49            ma_type.unwrap_or(MovingAverageType::Exponential),
50            d_method.unwrap_or(StochasticsDMethod::Ratio),
51        )
52    }
53
54    fn __repr__(&self) -> String {
55        format!(
56            "Stochastics({},{},{},{:?},{:?})",
57            self.period_k, self.period_d, self.slowing, self.ma_type, self.d_method
58        )
59    }
60
61    #[getter]
62    #[pyo3(name = "name")]
63    fn py_name(&self) -> String {
64        self.name()
65    }
66
67    #[getter]
68    #[pyo3(name = "period_k")]
69    const fn py_period_k(&self) -> usize {
70        self.period_k
71    }
72
73    #[getter]
74    #[pyo3(name = "period_d")]
75    const fn py_period_d(&self) -> usize {
76        self.period_d
77    }
78
79    #[getter]
80    #[pyo3(name = "slowing")]
81    const fn py_slowing(&self) -> usize {
82        self.slowing
83    }
84
85    #[getter]
86    #[pyo3(name = "ma_type")]
87    const fn py_ma_type(&self) -> MovingAverageType {
88        self.ma_type
89    }
90
91    #[getter]
92    #[pyo3(name = "d_method")]
93    const fn py_d_method(&self) -> StochasticsDMethod {
94        self.d_method
95    }
96
97    #[getter]
98    #[pyo3(name = "has_inputs")]
99    fn py_has_inputs(&self) -> bool {
100        self.has_inputs()
101    }
102
103    #[getter]
104    #[pyo3(name = "value_k")]
105    const fn py_value_k(&self) -> f64 {
106        self.value_k
107    }
108
109    #[getter]
110    #[pyo3(name = "value_d")]
111    const fn py_value_d(&self) -> f64 {
112        self.value_d
113    }
114
115    #[getter]
116    #[pyo3(name = "initialized")]
117    const fn py_initialized(&self) -> bool {
118        self.initialized
119    }
120
121    /// Updates the indicator with raw price values.
122    ///
123    /// # Parameters
124    ///
125    /// - `high`: The high price for the period.
126    /// - `low`: The low price for the period.
127    /// - `close`: The close price for the period.
128    #[pyo3(name = "update_raw")]
129    fn py_update_raw(&mut self, high: f64, low: f64, close: f64) {
130        self.update_raw(high, low, close);
131    }
132
133    #[pyo3(name = "handle_bar")]
134    fn py_handle_bar(&mut self, bar: &Bar) {
135        self.handle_bar(bar);
136    }
137
138    #[pyo3(name = "reset")]
139    fn py_reset(&mut self) {
140        self.reset();
141    }
142}