optionstratlib_core/utils/mod.rs
1//! # Utils Module
2//!
3//! Cross-cutting helpers whose defining owner is the `core` layer: they
4//! depend on nothing above `core` and every layer may call them. This
5//! module is deliberately *not* a catch-all. Each file below names one
6//! concern and one owner, and the ownership is machine-checked by
7//! `scripts/check_module_boundaries.py` (`UTILS_FILE_LAYER`), so a helper
8//! that grows a dependency on a higher layer fails the graph check instead
9//! of quietly turning this module back into a shared dumping ground
10//! (ADR-0001 D2, roadmap M1-09).
11//!
12//! | File | Owner | Contents |
13//! |------|-------|----------|
14//! | `json_format.rs` | core | `write_json`, `write_json_pretty` and the `impl_json_display!` / `impl_json_debug!` / `impl_json_debug_pretty!` macros |
15//! | `numeric.rs` | core | `approx_equal`, `calculate_log_returns` |
16//! | `rng.rs` | core | `deterministic_rng`, `get_random_element`, `random_decimal`, `DETERMINISTIC_RNG_DEFAULT_SEED` |
17//! | `time.rs` | core | `TimeFrame`, `units_per_year`, `convert_time_frame`, date formatting |
18//! | `traits.rs` | core | `Len` |
19//!
20//! Helpers that used to live here and now sit with their owner:
21//!
22//! - `prepare_file_path` is `visualization::prepare_file_path`: preparing a
23//! path on disk exists to write a rendered chart, and nothing below
24//! `visualization` calls it.
25//! - CSV and OHLCV parsing belong to `market` (`chains`), re-homed in M1-08.
26//! - `setup_logger` / `setup_logger_with_level` are **removed**. Installing a
27//! global `tracing` subscriber is an application decision, not a library
28//! one (`rules/global_rules.md`, "Logging & Observability"), so the library
29//! no longer depends on `tracing-subscriber` at all. Install one from your
30//! binary:
31//!
32//! ```rust,ignore
33//! tracing_subscriber::fmt()
34//! .with_max_level(tracing::Level::INFO)
35//! .init();
36//! ```
37//!
38//! The example binaries take theirs from the unpublished `osl-example-support`
39//! workspace member, which is where application-side wiring belongs.
40//!
41//! Every other module keeps its own `utils.rs` (`greeks::utils`,
42//! `chains::utils`, `strategies::utils`, ...). Those are owned by their
43//! parent module by construction and are checked as part of it; nothing is
44//! promoted here just because more than one caller wants it.
45//!
46//! ## Time frames
47//!
48//! ```rust
49//! use positive::pos_or_panic;
50//! use optionstratlib_core::utils::time::TimeFrame;
51//!
52//! let daily = TimeFrame::Day;
53//! let trading_days_per_year = daily.periods_per_year(); // Returns 252.0
54//!
55//! let custom = TimeFrame::Custom(pos_or_panic!(365.0));
56//! let periods = custom.periods_per_year(); // Returns 365.0
57//! ```
58//!
59//! Time-frame conversions are constant-time; they read the predefined
60//! period constants in `crate::constants`.
61//!
62//! ## Numeric comparison
63//!
64//! ```rust
65//! use optionstratlib_core::utils::numeric::approx_equal;
66//!
67//! assert!(approx_equal(1.0, 1.000_000_01));
68//! assert!(!approx_equal(1.0, 1.1));
69//! ```
70//!
71//! ## Randomness
72//!
73//! Every Monte-Carlo or simulation test seeds deterministically, so an
74//! upstream precision shift cannot flip an assertion by luck:
75//!
76//! ```rust
77//! use optionstratlib_core::utils::deterministic_rng;
78//! use rand::RngExt;
79//!
80//! let mut rng = deterministic_rng(42);
81//! let _: u64 = rng.random();
82//! ```
83//!
84//! Random element selection is O(n) in the size of the set.
85
86/// JSON-backed `Debug` and `Display` writers and the macros that wire a
87/// type to them.
88pub mod json_format;
89/// Tolerance-based `f64` comparison and the logarithmic-return transform.
90pub mod numeric;
91/// Deterministic seeding and generic random-sampling helpers.
92pub mod rng;
93/// Time frames, period conversions and date formatting.
94pub mod time;
95/// Traits shared across the library.
96mod traits;
97
98pub use numeric::{approx_equal, calculate_log_returns};
99pub use rng::{
100 DETERMINISTIC_RNG_DEFAULT_SEED, deterministic_rng, get_random_element, get_random_element_with,
101 random_decimal,
102};
103pub use time::TimeFrame;
104pub use traits::Len;