fin_primitives/lib.rs
1//! # fin-primitives
2//!
3//! Validated, decimal-precise building blocks for trading and quantitative
4//! systems: price and quantity types that cannot hold invalid values, a
5//! sequence-checked level-2 order book, tick-to-OHLCV aggregation, streaming
6//! indicators with an explicit warm-up contract, a position ledger, risk rules,
7//! Black-Scholes Greeks and a walk-forward backtester. One error type,
8//! [`FinError`], covers all of it.
9//!
10//! ## A first look
11//!
12//! Build a book from sequenced deltas, read the top of book, and price a
13//! market order by walking the levels:
14//!
15//! ```
16//! use fin_primitives::orderbook::{BookDelta, DeltaAction, OrderBook};
17//! use fin_primitives::types::{Price, Quantity, Side, Symbol};
18//! use rust_decimal_macros::dec;
19//!
20//! # fn main() -> Result<(), fin_primitives::FinError> {
21//! let mut book = OrderBook::new(Symbol::new("BTC-USD")?);
22//! let levels = [
23//! (Side::Ask, dec!(64250.50), dec!(0.842)),
24//! (Side::Ask, dec!(64251.00), dec!(1.310)),
25//! (Side::Bid, dec!(64250.00), dec!(1.204)),
26//! (Side::Bid, dec!(64249.50), dec!(0.655)),
27//! ];
28//! for (seq, (side, price, qty)) in (1..).zip(levels) {
29//! book.apply_delta(BookDelta {
30//! side,
31//! price: Price::new(price)?,
32//! quantity: Quantity::new(qty)?,
33//! action: DeltaAction::Set,
34//! sequence: seq,
35//! })?;
36//! }
37//!
38//! assert_eq!(book.spread(), Some(dec!(0.50)));
39//! assert_eq!(book.mid_price(), Some(dec!(64250.25)));
40//!
41//! // Buying 1 BTC takes all 0.842 at the best ask and 0.158 at the next level.
42//! let vwap = book.vwap_for_qty(Side::Ask, Quantity::new(dec!(1))?)?;
43//! assert_eq!(vwap, dec!(64250.579));
44//!
45//! // A delta that would cross the book is rejected and rolled back.
46//! let crossing = BookDelta {
47//! side: Side::Bid,
48//! price: Price::new(dec!(64251.00))?,
49//! quantity: Quantity::new(dec!(2))?,
50//! action: DeltaAction::Set,
51//! sequence: 5,
52//! };
53//! assert!(book.apply_delta(crossing).is_err());
54//! assert_eq!(book.sequence(), 4);
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! Ticks become bars, and bars feed indicators. Indicators return
60//! [`SignalValue::Unavailable`](signals::SignalValue::Unavailable) until they
61//! have enough history, never a NaN or a zero:
62//!
63//! ```
64//! use fin_primitives::ohlcv::{OhlcvAggregator, Timeframe};
65//! use fin_primitives::signals::indicators::Sma;
66//! use fin_primitives::signals::{BarInput, Signal, SignalValue};
67//! use fin_primitives::tick::Tick;
68//! use fin_primitives::types::{NanoTimestamp, Price, Quantity, Side, Symbol};
69//! use rust_decimal_macros::dec;
70//!
71//! # fn main() -> Result<(), fin_primitives::FinError> {
72//! let sym = Symbol::new("ETH-USD")?;
73//! let mut agg = OhlcvAggregator::new(sym.clone(), Timeframe::Minutes(1))?;
74//! let mut sma = Sma::new("sma3", 3)?;
75//!
76//! let mut values = Vec::new();
77//! for (minute, close) in [(0, dec!(3180)), (1, dec!(3190)), (2, dec!(3200)), (3, dec!(3230))] {
78//! let tick = Tick::new(
79//! sym.clone(),
80//! Price::new(close)?,
81//! Quantity::new(dec!(1))?,
82//! Side::Bid,
83//! NanoTimestamp::from_secs(1_767_625_200 + minute * 60),
84//! );
85//! for bar in agg.push_tick(&tick)? {
86//! values.push(sma.update(&BarInput::from(&bar))?);
87//! }
88//! }
89//! // Three bars have closed; the fourth is still open.
90//! assert_eq!(values[0], SignalValue::Unavailable);
91//! assert_eq!(values[1], SignalValue::Unavailable);
92//! assert_eq!(values[2], SignalValue::Scalar(dec!(3190)));
93//! # Ok(())
94//! # }
95//! ```
96//!
97//! ## Runnable examples
98//!
99//! The repository ships examples that print formatted, colored output:
100//!
101//! | Command | Shows |
102//! |---------|-------|
103//! | `cargo run --example order_book` | depth ladder, spread, micro-price, VWAP fill, rejected deltas |
104//! | `cargo run --example candles` | ticks to 1-minute candles, EMA and RSI with warm-up |
105//! | `cargo run --example position_risk` | fills, mark-to-market, drawdown and equity-floor breaches |
106//! | `cargo run --example option_chain` | Black-Scholes chain with Greeks and an implied-vol round trip |
107//!
108//! ## Where things live
109//!
110//! | Module | What it provides |
111//! |--------|------------------|
112//! | [`types`] | [`Price`](types::Price), [`Quantity`](types::Quantity), [`Symbol`](types::Symbol), [`NanoTimestamp`](types::NanoTimestamp), [`Side`](types::Side) |
113//! | [`tick`] | [`Tick`](tick::Tick), `TickFilter`, `TickReplayer` |
114//! | [`orderbook`] | [`OrderBook`](orderbook::OrderBook): L2 book with sequence checks and crossed-book rollback |
115//! | [`ohlcv`] | [`OhlcvBar`](ohlcv::OhlcvBar), [`OhlcvAggregator`](ohlcv::OhlcvAggregator), `OhlcvSeries` analytics |
116//! | [`signals`] | the [`Signal`](signals::Signal) trait, `SignalPipeline`, and several hundred indicators in [`signals::indicators`] |
117//! | [`position`] | [`Fill`](position::Fill), [`Position`](position::Position), [`PositionLedger`](position::PositionLedger), Kelly sizing |
118//! | [`risk`] | `DrawdownTracker`, the [`RiskRule`](risk::RiskRule) trait, [`RiskMonitor`](risk::RiskMonitor), VaR and stress tools |
119//! | [`greeks`] | [`BlackScholes`](greeks::BlackScholes) pricing, Greeks, implied volatility, multi-leg spreads |
120//! | [`backtest`] | bar-by-bar `Backtester`, `Strategy` trait, `WalkForwardOptimizer` |
121//! | [`async_signals`] | Tokio-based `StreamingSignalPipeline` |
122//! | [`regime`] | Hurst exponent, GARCH(1,1), correlation-breakdown regime detection |
123//!
124//! Further modules cover portfolio optimization, factor models, yield curves,
125//! fixed income, credit, derivatives, execution cost, microstructure, Monte
126//! Carlo, pairs trading, tax lots and more; see the module list below.
127//!
128//! ## Design
129//!
130//! - **Validated at construction.** `Price::new` rejects zero and negative
131//! values; `Quantity::new` rejects negatives; `Symbol::new` rejects empty or
132//! whitespace strings. Code that holds one of these types can trust it.
133//! - **Decimal where money is.** Prices, quantities, P&L and order-book math
134//! use [`rust_decimal::Decimal`]. Statistical models (GARCH, optimizers,
135//! Black-Scholes internals) compute in `f64` and convert at the boundary.
136//! - **Typed errors.** Fallible operations return `Result<_, FinError>`, and
137//! the crate's Clippy config warns on `unwrap`, `expect` and `panic`.
138//! - **Traits at the seams.** [`risk::RiskRule`], [`signals::Signal`] and
139//! [`tick::TickFilter`] are traits, so your own rules and indicators plug in
140//! next to the built-in ones.
141//! - **No unsafe code.** The crate is `#![forbid(unsafe_code)]`.
142//!
143//! Sister crate: [fin-stream](https://github.com/Mattbusel/fin-stream) handles
144//! real-time market data ingestion on top of these types.
145
146#![forbid(unsafe_code)]
147#![deny(missing_docs)]
148
149pub mod async_signals;
150pub mod backtest;
151pub mod error;
152pub mod greeks;
153pub mod ohlcv;
154pub mod orderbook;
155pub mod position;
156pub mod risk;
157pub mod signals;
158pub mod tick;
159pub mod types;
160pub mod pnl;
161pub mod correlation;
162pub mod latency;
163pub mod scenario;
164pub mod microstructure;
165pub mod ml;
166pub mod regime;
167pub mod cross_asset;
168pub mod attribution;
169pub mod options;
170pub mod volatility;
171pub mod impact;
172pub mod portfolio;
173
174#[cfg(feature = "python")]
175pub mod python;
176pub mod factor;
177pub mod execution;
178pub mod montecarlo;
179pub mod yield_curve;
180pub mod events;
181pub mod crypto;
182pub mod derivatives;
183pub mod technical;
184pub mod fixed_income;
185pub mod liquidity;
186pub mod pairs_trading;
187pub mod ml_features;
188pub mod performance;
189pub mod clustering;
190pub mod tax;
191pub mod rebalancing;
192pub mod funding;
193pub mod alternative_data;
194pub mod arbitrage;
195pub mod execution_cost;
196pub mod credit;
197
198pub use error::FinError;