1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2025 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// -------------------------------------------------------------------------------------------------
1516use std::str::FromStr;
1718use chrono::{DateTime, Utc};
19use chrono_tz::Tz;
20use nautilus_core::python::to_pyvalue_err;
21use nautilus_model::python::common::EnumIterator;
22use pyo3::{PyTypeInfo, prelude::*, types::PyType};
2324use crate::sessions::{
25 ForexSession, fx_local_from_utc, fx_next_end, fx_next_start, fx_prev_end, fx_prev_start,
26};
2728#[pymethods]
29impl ForexSession {
30#[new]
31fn py_new(py: Python<'_>, value: &Bound<'_, PyAny>) -> PyResult<Self> {
32let t = Self::type_object(py);
33Self::py_from_str(&t, value)
34 }
3536const fn __hash__(&self) -> isize {
37*self as isize
38 }
3940fn __repr__(&self) -> String {
41format!(
42"<{}.{}: '{}'>",
43stringify!(PositionSide),
44self.name(),
45self.value(),
46 )
47 }
4849fn __str__(&self) -> String {
50self.to_string()
51 }
5253#[getter]
54 #[must_use]
55pub fn name(&self) -> String {
56self.to_string()
57 }
5859#[getter]
60 #[must_use]
61pub const fn value(&self) -> u8 {
62*self as u8
63 }
6465#[classmethod]
66fn variants(_: &Bound<'_, PyType>, py: Python<'_>) -> EnumIterator {
67 EnumIterator::new::<Self>(py)
68 }
6970#[classmethod]
71 #[pyo3(name = "from_str")]
72fn py_from_str(_: &Bound<'_, PyType>, data: &Bound<'_, PyAny>) -> PyResult<Self> {
73let data_str: &str = data.extract()?;
74let tokenized = data_str.to_uppercase();
75Self::from_str(&tokenized).map_err(to_pyvalue_err)
76 }
7778#[classattr]
79 #[pyo3(name = "SYDNEY")]
80const fn py_no_position_side() -> Self {
81Self::Sydney
82 }
8384#[classattr]
85 #[pyo3(name = "TOKYO")]
86const fn py_flat() -> Self {
87Self::Tokyo
88 }
8990#[classattr]
91 #[pyo3(name = "LONDON")]
92const fn py_long() -> Self {
93Self::London
94 }
9596#[classattr]
97 #[pyo3(name = "NEW_YORK")]
98const fn py_short() -> Self {
99Self::NewYork
100 }
101}
102103/// Converts a UTC timestamp to the local time for the given Forex session.
104///
105/// The `time_now` must be timezone-aware with its tzinfo set to a built-in `datetime.timezone`
106/// (e.g. `datetime.timezone.utc`). Third-party tzinfo objects (like those from `pytz`) are not supported.
107#[pyfunction]
108#[pyo3(name = "fx_local_from_utc")]
109pub fn py_fx_local_from_utc(
110 session: ForexSession,
111 time_now: DateTime<Utc>,
112) -> PyResult<DateTime<Tz>> {
113Ok(fx_local_from_utc(session, time_now))
114}
115116/// Returns the next session start time in UTC.
117///
118/// The `time_now` must be timezone-aware with its tzinfo set to a built-in `datetime.timezone`
119/// (e.g. `datetime.timezone.utc`). Third-party tzinfo objects (like those from `pytz`) are not supported.
120#[pyfunction]
121#[pyo3(name = "fx_next_start")]
122pub fn py_fx_next_start(session: ForexSession, time_now: DateTime<Utc>) -> PyResult<DateTime<Utc>> {
123Ok(fx_next_start(session, time_now))
124}
125126/// Returns the next session end time in UTC.
127///
128/// The `time_now` must be timezone-aware with its tzinfo set to a built-in `datetime.timezone`
129/// (e.g. `datetime.timezone.utc`). Third-party tzinfo objects (like those from `pytz`) are not supported.
130#[pyfunction]
131#[pyo3(name = "fx_next_end")]
132pub fn py_fx_next_end(session: ForexSession, time_now: DateTime<Utc>) -> PyResult<DateTime<Utc>> {
133Ok(fx_next_end(session, time_now))
134}
135136/// Returns the previous session start time in UTC.
137///
138/// The `time_now` must be timezone-aware with its tzinfo set to a built-in `datetime.timezone`
139/// (e.g. `datetime.timezone.utc`). Third-party tzinfo objects (like those from `pytz`) are not supported.
140#[pyfunction]
141#[pyo3(name = "fx_prev_start")]
142pub fn py_fx_prev_start(session: ForexSession, time_now: DateTime<Utc>) -> PyResult<DateTime<Utc>> {
143Ok(fx_prev_start(session, time_now))
144}
145146/// Returns the previous session end time in UTC.
147///
148/// The `time_now` must be timezone-aware with its tzinfo set to a built-in `datetime.timezone`
149/// (e.g. `datetime.timezone.utc`). Third-party tzinfo objects (like those from `pytz`) are not supported.
150#[pyfunction]
151#[pyo3(name = "fx_prev_end")]
152pub fn py_fx_prev_end(session: ForexSession, time_now: DateTime<Utc>) -> PyResult<DateTime<Utc>> {
153Ok(fx_prev_end(session, time_now))
154}