nautilus_model/ffi/data/
bar.rs

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// -------------------------------------------------------------------------------------------------
15
16use std::{
17    collections::hash_map::DefaultHasher,
18    ffi::c_char,
19    hash::{Hash, Hasher},
20    str::FromStr,
21};
22
23use nautilus_core::{
24    UnixNanos,
25    ffi::string::{cstr_as_str, str_to_cstr},
26};
27
28use crate::{
29    data::bar::{Bar, BarSpecification, BarType},
30    enums::{AggregationSource, BarAggregation, PriceType},
31    identifiers::InstrumentId,
32    types::{Price, Quantity},
33};
34
35/// # Panics
36///
37/// Panics if `aggregation` or `price_type` do not correspond to valid enum variants.
38#[unsafe(no_mangle)]
39pub extern "C" fn bar_specification_new(
40    step: usize,
41    aggregation: u8,
42    price_type: u8,
43) -> BarSpecification {
44    let aggregation =
45        BarAggregation::from_repr(aggregation as usize).expect("Error converting enum");
46    let price_type = PriceType::from_repr(price_type as usize).expect("Error converting enum");
47    BarSpecification::new(step, aggregation, price_type)
48}
49
50/// Returns a [`BarSpecification`] as a C string pointer.
51#[unsafe(no_mangle)]
52pub extern "C" fn bar_specification_to_cstr(bar_spec: &BarSpecification) -> *const c_char {
53    str_to_cstr(&bar_spec.to_string())
54}
55
56#[unsafe(no_mangle)]
57pub extern "C" fn bar_specification_hash(bar_spec: &BarSpecification) -> u64 {
58    let mut h = DefaultHasher::new();
59    bar_spec.hash(&mut h);
60    h.finish()
61}
62
63#[unsafe(no_mangle)]
64pub extern "C" fn bar_specification_eq(lhs: &BarSpecification, rhs: &BarSpecification) -> u8 {
65    u8::from(lhs == rhs)
66}
67
68#[unsafe(no_mangle)]
69pub extern "C" fn bar_specification_lt(lhs: &BarSpecification, rhs: &BarSpecification) -> u8 {
70    u8::from(lhs < rhs)
71}
72
73#[unsafe(no_mangle)]
74pub extern "C" fn bar_specification_le(lhs: &BarSpecification, rhs: &BarSpecification) -> u8 {
75    u8::from(lhs <= rhs)
76}
77
78#[unsafe(no_mangle)]
79pub extern "C" fn bar_specification_gt(lhs: &BarSpecification, rhs: &BarSpecification) -> u8 {
80    u8::from(lhs > rhs)
81}
82
83#[unsafe(no_mangle)]
84pub extern "C" fn bar_specification_ge(lhs: &BarSpecification, rhs: &BarSpecification) -> u8 {
85    u8::from(lhs >= rhs)
86}
87
88/// # Panics
89///
90/// Panics if `aggregation_source` does not correspond to a valid enum variant.
91#[unsafe(no_mangle)]
92pub extern "C" fn bar_type_new(
93    instrument_id: InstrumentId,
94    spec: BarSpecification,
95    aggregation_source: u8,
96) -> BarType {
97    let aggregation_source =
98        AggregationSource::from_repr(aggregation_source as usize).expect("Error converting enum");
99
100    BarType::Standard {
101        instrument_id,
102        spec,
103        aggregation_source,
104    }
105}
106
107#[unsafe(no_mangle)]
108pub extern "C" fn bar_type_new_composite(
109    instrument_id: InstrumentId,
110    spec: BarSpecification,
111    aggregation_source: AggregationSource,
112
113    composite_step: usize,
114    composite_aggregation: BarAggregation,
115    composite_aggregation_source: AggregationSource,
116) -> BarType {
117    BarType::new_composite(
118        instrument_id,
119        spec,
120        aggregation_source,
121        composite_step,
122        composite_aggregation,
123        composite_aggregation_source,
124    )
125}
126
127#[unsafe(no_mangle)]
128pub extern "C" fn bar_type_is_standard(bar_type: &BarType) -> u8 {
129    bar_type.is_standard() as u8
130}
131
132#[unsafe(no_mangle)]
133pub extern "C" fn bar_type_is_composite(bar_type: &BarType) -> u8 {
134    bar_type.is_composite() as u8
135}
136
137#[unsafe(no_mangle)]
138pub extern "C" fn bar_type_standard(bar_type: &BarType) -> BarType {
139    bar_type.standard()
140}
141
142#[unsafe(no_mangle)]
143pub extern "C" fn bar_type_composite(bar_type: &BarType) -> BarType {
144    bar_type.composite()
145}
146
147#[unsafe(no_mangle)]
148pub extern "C" fn bar_type_instrument_id(bar_type: &BarType) -> InstrumentId {
149    bar_type.instrument_id()
150}
151
152#[unsafe(no_mangle)]
153pub extern "C" fn bar_type_spec(bar_type: &BarType) -> BarSpecification {
154    bar_type.spec()
155}
156
157#[unsafe(no_mangle)]
158pub extern "C" fn bar_type_aggregation_source(bar_type: &BarType) -> AggregationSource {
159    bar_type.aggregation_source()
160}
161
162/// Returns any [`BarType`] parsing error from the provided C string pointer.
163///
164/// # Safety
165///
166/// Assumes `ptr` is a valid C string pointer.
167#[unsafe(no_mangle)]
168pub unsafe extern "C" fn bar_type_check_parsing(ptr: *const c_char) -> *const c_char {
169    let value = unsafe { cstr_as_str(ptr) };
170    match BarType::from_str(value) {
171        Ok(_) => str_to_cstr(""),
172        Err(e) => str_to_cstr(&e.to_string()),
173    }
174}
175
176/// Returns a [`BarType`] from a C string pointer.
177///
178/// # Safety
179///
180/// Assumes `ptr` is a valid C string pointer.
181#[unsafe(no_mangle)]
182pub unsafe extern "C" fn bar_type_from_cstr(ptr: *const c_char) -> BarType {
183    let value = unsafe { cstr_as_str(ptr) };
184    BarType::from(value)
185}
186
187#[unsafe(no_mangle)]
188pub extern "C" fn bar_type_eq(lhs: &BarType, rhs: &BarType) -> u8 {
189    u8::from(lhs == rhs)
190}
191
192#[unsafe(no_mangle)]
193pub extern "C" fn bar_type_lt(lhs: &BarType, rhs: &BarType) -> u8 {
194    u8::from(lhs < rhs)
195}
196
197#[unsafe(no_mangle)]
198pub extern "C" fn bar_type_le(lhs: &BarType, rhs: &BarType) -> u8 {
199    u8::from(lhs <= rhs)
200}
201
202#[unsafe(no_mangle)]
203pub extern "C" fn bar_type_gt(lhs: &BarType, rhs: &BarType) -> u8 {
204    u8::from(lhs > rhs)
205}
206
207#[unsafe(no_mangle)]
208pub extern "C" fn bar_type_ge(lhs: &BarType, rhs: &BarType) -> u8 {
209    u8::from(lhs >= rhs)
210}
211
212#[unsafe(no_mangle)]
213pub extern "C" fn bar_type_hash(bar_type: &BarType) -> u64 {
214    let mut h = DefaultHasher::new();
215    bar_type.hash(&mut h);
216    h.finish()
217}
218
219/// Returns a [`BarType`] as a C string pointer.
220#[unsafe(no_mangle)]
221pub extern "C" fn bar_type_to_cstr(bar_type: &BarType) -> *const c_char {
222    str_to_cstr(&bar_type.to_string())
223}
224
225#[unsafe(no_mangle)]
226#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
227pub extern "C" fn bar_new(
228    bar_type: BarType,
229    open: Price,
230    high: Price,
231    low: Price,
232    close: Price,
233    volume: Quantity,
234    ts_event: UnixNanos,
235    ts_init: UnixNanos,
236) -> Bar {
237    Bar {
238        bar_type,
239        open,
240        high,
241        low,
242        close,
243        volume,
244        ts_event,
245        ts_init,
246    }
247}
248
249#[unsafe(no_mangle)]
250pub extern "C" fn bar_eq(lhs: &Bar, rhs: &Bar) -> u8 {
251    u8::from(lhs == rhs)
252}
253
254#[unsafe(no_mangle)]
255pub extern "C" fn bar_hash(bar: &Bar) -> u64 {
256    let mut h = DefaultHasher::new();
257    bar.hash(&mut h);
258    h.finish()
259}
260
261/// Returns a [`Bar`] as a C string.
262#[unsafe(no_mangle)]
263pub extern "C" fn bar_to_cstr(bar: &Bar) -> *const c_char {
264    str_to_cstr(&bar.to_string())
265}