1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! # fin-primitives
//!
//! The basic parts of trading software, done once and checked: exact price and
//! size types that refuse bad values, an order book, candles built from trades,
//! indicators, option prices and risk limits.
//!
//! 
//!
//! Add it (the `dec!` macro for decimal literals needs both `rust_decimal` crates):
//!
//! ```text
//! cargo add fin-primitives rust_decimal rust_decimal_macros
//! ```
//!
//! The main types: [`Price`](types::Price), [`Quantity`](types::Quantity) and
//! [`Symbol`](types::Symbol) (validated values), [`OrderBook`](orderbook::OrderBook),
//! [`OhlcvAggregator`](ohlcv::OhlcvAggregator) (ticks to candles), the
//! [`Signal`](signals::Signal) trait and its indicators,
//! [`PositionLedger`](position::PositionLedger), [`RiskMonitor`](risk::RiskMonitor),
//! [`BlackScholes`](greeks::BlackScholes), and one error type, [`FinError`].
//!
//! ## A first look
//!
//! Build a book from sequenced deltas, read the top of book, and price a
//! market order by walking the levels:
//!
//! ```
//! use fin_primitives::orderbook::{BookDelta, DeltaAction, OrderBook};
//! use fin_primitives::types::{Price, Quantity, Side, Symbol};
//! use rust_decimal_macros::dec;
//!
//! # fn main() -> Result<(), fin_primitives::FinError> {
//! let mut book = OrderBook::new(Symbol::new("BTC-USD")?);
//! let levels = [
//! (Side::Ask, dec!(64250.50), dec!(0.842)),
//! (Side::Ask, dec!(64251.00), dec!(1.310)),
//! (Side::Bid, dec!(64250.00), dec!(1.204)),
//! (Side::Bid, dec!(64249.50), dec!(0.655)),
//! ];
//! for (seq, (side, price, qty)) in (1..).zip(levels) {
//! book.apply_delta(BookDelta {
//! side,
//! price: Price::new(price)?,
//! quantity: Quantity::new(qty)?,
//! action: DeltaAction::Set,
//! sequence: seq,
//! })?;
//! }
//!
//! assert_eq!(book.spread(), Some(dec!(0.50)));
//! assert_eq!(book.mid_price(), Some(dec!(64250.25)));
//!
//! // Buying 1 BTC takes all 0.842 at the best ask and 0.158 at the next level.
//! let vwap = book.vwap_for_qty(Side::Ask, Quantity::new(dec!(1))?)?;
//! assert_eq!(vwap, dec!(64250.579));
//!
//! // A delta that would cross the book is rejected and rolled back.
//! let crossing = BookDelta {
//! side: Side::Bid,
//! price: Price::new(dec!(64251.00))?,
//! quantity: Quantity::new(dec!(2))?,
//! action: DeltaAction::Set,
//! sequence: 5,
//! };
//! assert!(book.apply_delta(crossing).is_err());
//! assert_eq!(book.sequence(), 4);
//! # Ok(())
//! # }
//! ```
//!
//! 
//!
//! Ticks become bars, and bars feed indicators. Indicators return
//! [`SignalValue::Unavailable`](signals::SignalValue::Unavailable) until they
//! have enough history, never a NaN or a zero:
//!
//! ```
//! use fin_primitives::ohlcv::{OhlcvAggregator, Timeframe};
//! use fin_primitives::signals::indicators::Sma;
//! use fin_primitives::signals::{BarInput, Signal, SignalValue};
//! use fin_primitives::tick::Tick;
//! use fin_primitives::types::{NanoTimestamp, Price, Quantity, Side, Symbol};
//! use rust_decimal_macros::dec;
//!
//! # fn main() -> Result<(), fin_primitives::FinError> {
//! let sym = Symbol::new("ETH-USD")?;
//! let mut agg = OhlcvAggregator::new(sym.clone(), Timeframe::Minutes(1))?;
//! let mut sma = Sma::new("sma3", 3)?;
//!
//! let mut values = Vec::new();
//! for (minute, close) in [(0, dec!(3180)), (1, dec!(3190)), (2, dec!(3200)), (3, dec!(3230))] {
//! let tick = Tick::new(
//! sym.clone(),
//! Price::new(close)?,
//! Quantity::new(dec!(1))?,
//! Side::Bid,
//! NanoTimestamp::from_secs(1_767_625_200 + minute * 60),
//! );
//! for bar in agg.push_tick(&tick)? {
//! values.push(sma.update(&BarInput::from(&bar))?);
//! }
//! }
//! // Three bars have closed; the fourth is still open.
//! assert_eq!(values[0], SignalValue::Unavailable);
//! assert_eq!(values[1], SignalValue::Unavailable);
//! assert_eq!(values[2], SignalValue::Scalar(dec!(3190)));
//! # Ok(())
//! # }
//! ```
//!
//! ## Runnable examples
//!
//! The repository ships examples that print formatted, colored output:
//!
//! | Command | Shows |
//! |---------|-------|
//! | `cargo run --example order_book` | depth ladder, spread, micro-price, VWAP fill, rejected deltas |
//! | `cargo run --example candles` | ticks to 1-minute candles, EMA and RSI with warm-up |
//! | `cargo run --example position_risk` | fills, mark-to-market, drawdown and equity-floor breaches |
//! | `cargo run --example option_chain` | Black-Scholes chain with Greeks and an implied-vol round trip |
//!
//! ## Where things live
//!
//! | Module | What it provides |
//! |--------|------------------|
//! | [`types`] | [`Price`](types::Price), [`Quantity`](types::Quantity), [`Symbol`](types::Symbol), [`NanoTimestamp`](types::NanoTimestamp), [`Side`](types::Side) |
//! | [`tick`] | [`Tick`](tick::Tick), `TickFilter`, `TickReplayer` |
//! | [`orderbook`] | [`OrderBook`](orderbook::OrderBook): L2 book with sequence checks and crossed-book rollback |
//! | [`ohlcv`] | [`OhlcvBar`](ohlcv::OhlcvBar), [`OhlcvAggregator`](ohlcv::OhlcvAggregator), `OhlcvSeries` analytics |
//! | [`signals`] | the [`Signal`](signals::Signal) trait, `SignalPipeline`, and several hundred indicators in [`signals::indicators`] |
//! | [`position`] | [`Fill`](position::Fill), [`Position`](position::Position), [`PositionLedger`](position::PositionLedger), Kelly sizing |
//! | [`risk`] | `DrawdownTracker`, the [`RiskRule`](risk::RiskRule) trait, [`RiskMonitor`](risk::RiskMonitor), VaR and stress tools |
//! | [`greeks`] | [`BlackScholes`](greeks::BlackScholes) pricing, Greeks, implied volatility, multi-leg spreads |
//! | [`backtest`] | bar-by-bar `Backtester`, `Strategy` trait, `WalkForwardOptimizer` |
//! | [`async_signals`] | Tokio-based `StreamingSignalPipeline` |
//! | [`regime`] | Hurst exponent, GARCH(1,1), correlation-breakdown regime detection |
//!
//! Further modules cover portfolio optimization, factor models, yield curves,
//! fixed income, credit, derivatives, execution cost, microstructure, Monte
//! Carlo, pairs trading, tax lots and more; see the module list below.
//!
//! ## Feature flags
//!
//! | feature | default | adds |
//! |---|---|---|
//! | `serde` | yes | `Serialize`/`Deserialize` on the data types; deserializing re-runs validation |
//! | `async` | yes | `async_signals`: a Tokio task that runs a signal pipeline over a channel |
//! | `ta`, `yata`, `wickra` | no | [`interop`] with those crates: their indicators read fin-primitives bars, their bars convert to [`BarInput`](signals::BarInput) |
//! | `arrow` | no | `arrow`: bars to and from Apache Arrow with exact `Decimal128` columns |
//! | `python` | no | PyO3 bindings, built with maturin from the repository's `python/` folder |
//!
//! [`normal`] has the standard normal CDF, PDF and inverse used by every pricer and
//! VaR model here (accurate to about 1e-15 relative, including the tails).
//!
//! ## Design
//!
//! - **Validated at construction.** `Price::new` rejects zero and negative
//! values; `Quantity::new` rejects negatives; `Symbol::new` rejects empty or
//! whitespace strings. Code that holds one of these types can trust it.
//! - **Decimal where money is.** Prices, quantities, P&L and order-book math
//! use [`rust_decimal::Decimal`]. Statistical models (GARCH, optimizers,
//! Black-Scholes internals) compute in `f64` and convert at the boundary.
//! - **Typed errors.** Fallible operations return `Result<_, FinError>`, and
//! the crate's Clippy config warns on `unwrap`, `expect` and `panic`.
//! - **Traits at the seams.** [`risk::RiskRule`], [`signals::Signal`] and
//! [`tick::TickFilter`] are traits, so your own rules and indicators plug in
//! next to the built-in ones.
//! - **No unsafe code.** The crate is `#![forbid(unsafe_code)]`.
//!
//! Sister crate: [fin-stream](https://gitlab.com/mattbusel/fin-stream) handles
//! real-time market data ingestion on top of these types.
pub use FinError;
/// Compiles and runs the Rust code blocks in README.md as doc tests, so the README
/// cannot drift from the API.
;