bts/
lib.rs

1//! # BTS: BackTest Strategy for Trading Algorithms
2//!
3//! **BTS** is a high-performance Rust library for backtesting trading strategies on candlestick (OHLCV) data.
4//! It is designed for **speed, flexibility, and accuracy**, making it ideal for both **retail traders** and **algorithmic trading developers**.
5//!
6//! ## Why BTS?
7//! - **Optimized for Performance**: Uses O(1) operations on orders/positions, and parallel processing for optimization tasks.
8//! - **Technical Analysis Ready**: Seamlessly integrates with the [`ta`](https://crates.io/crates/ta) crate for 100+ indicators (EMA, MACD, RSI, etc.).
9//! - **Risk Management**: Supports stop-loss, take-profit, and trailing stops with configurable rules.
10//! - **Realistic Simulations**: Models slippage, fees, and latency for accurate backtesting.
11//! - **Extensible**: Add custom indicators, strategies, or data sources with minimal effort.
12//!
13//! ## Core Components
14//! | Component   | Description                                                                                     |
15//! |-------------|-------------------------------------------------------------------------------------------------|
16//! | **`Candle`** | Represents OHLCV (Open, High, Low, Close, Volume) data for a single time period.               |
17//! | **`Order`**  | Market, limit, or conditional orders (e.g., stop-loss, take-profit).                          |
18//! | **`Position`** | Open trades with configurable exit rules (e.g., trailing stops).                              |
19//! | **`Wallet`** | Tracks balance, locked funds, unrealized P&L, and fees.                                       |
20//! | **`Metrics`** | Calculates performance metrics: P&L, drawdown, Sharpe ratio, win rate, and more.             |
21//! | **`Optimizer`** | Calculates bests parameters *(indicators, RR, etc...)*.             |
22//! | **`Backtest`** | The engine that simulates strategy execution over historical data.                          |
23//!
24//! ## Features
25//! ### 1. **Technical Indicators**
26//! - Compatible with the [`ta`](https://crates.io/crates/ta) crate for 100+ additional indicators.
27//!
28//! ### 2. **Order Types & Exit Rules**
29//! | Order Type               | Description                                                                                     |
30//! |--------------------------|-------------------------------------------------------------------------------------------------|
31//! | **Market Order**         | Executes immediately at the current price.                                                    |
32//! | **Limit Order**          | Executes only at a specified price or better.                                                 |
33//! | **Take-Profit**          | Closes the position when a target price is reached.                                          |
34//! | **Stop-Loss**            | Closes the position to limit losses.                                                          |
35//! | **Trailing Stop**        | Dynamically adjusts the stop price based on market movements.                                |
36//! | **Take-Profit + Stop-Loss** | Combines both rules for risk management.                                                   |
37//!
38//! ### 3. **Performance Metrics**
39//! | Metric               | Description                                                                                     |
40//! |----------------------|-------------------------------------------------------------------------------------------------|
41//! | **Max Drawdown**     | Largest peak-to-trough decline in account balance (%).                                        |
42//! | **Profit Factor**    | Ratio of gross profits to gross losses.                                                       |
43//! | **Sharpe Ratio**     | Risk-adjusted return (higher = better).                                                      |
44//! | **Win Rate**         | Percentage of winning trades.                                                                 |
45//! | **Sortino Ratio**    | Like Sharpe ratio, but focuses only on downside volatility.                                  |
46//!
47//! ### 4. **Optimization Tools**
48//! - **Parallel Brute-Force**: Optimize strategy parameters (e.g., EMA periods) using multi-threading.
49//!
50//! ## Getting Started
51//! ### 1. Add BTS to your project:
52//! ```toml
53//! [dependencies]
54//! bts = "*"
55//! ta = "*"  # Optional: For technical analysis indicators
56//! ```
57//!
58//! ### 2. Run a Simple Backtest:
59//! ```rust
60//! use bts::prelude::*;
61//! use chrono::DateTime;
62//!
63//! fn main() {
64//!     let candle = CandleBuilder::builder()
65//!         .open(100.0)
66//!         .high(110.0)
67//!         .low(95.0)
68//!         .close(105.0)
69//!         .volume(1.0)
70//!         .bid(0.5)
71//!         .open_time(DateTime::default())
72//!         .close_time(DateTime::default())
73//!         .build()
74//!         .unwrap();
75//!
76//!     // Initialize backtest with \$10,000
77//!     let mut backtest = Backtest::new(vec![candle], 10_000.0, None).unwrap();
78//!
79//!     // Execute a market buy order
80//!     backtest
81//!         .run(|bt, _candle| {
82//!             let order: Order = (OrderType::Market(102.0), 1.0, OrderSide::Buy).into();
83//!             bt.place_order(order).unwrap();
84//!
85//!             // Close the position at \$104.0
86//!             if let Some(position) = bt.positions().last().cloned() {
87//!                 bt.close_position(&position, 104.0, true).unwrap();
88//!             }
89//!
90//!             Ok(())
91//!         })
92//!         .unwrap();
93//!
94//!     // Print performance metrics
95//!     #[cfg(feature = "metrics")]
96//!     {
97//!         let metrics = Metrics::from(&backtest);
98//!         println!("{}", metrics);
99//!     }
100//! }
101//! ```
102//!
103//! ### Output:
104//! ```bash
105//! === Backtest Metrics ===
106//! Initial Balance: 10000.00
107//! Final Balance: 10018.00
108//! Max Drawdown: 0.20%
109//! Profit Factor: 2.00
110//! Sharpe Ratio: 1.50
111//! Win Rate: 100.00%
112//! ```
113//!
114//! ## Use Cases
115//! - **Retail Traders**: Test manual strategies before risking real capital.
116//! - **Algo Developers**: Build and optimize automated trading systems.
117//! - **Quant Researchers**: Backtest statistical arbitrage or machine learning models.
118//! - **Educational**: Teach trading concepts with a hands-on tool.
119//!
120//! ## Integrations
121//! | Crate          | Purpose                                                                                     |
122//! |----------------|---------------------------------------------------------------------------------------------|
123//! | [`ta`](https://crates.io/crates/ta) | Technical analysis indicators (EMA, RSI, MACD, etc.).                                      |
124//! | [`rayon`](https://crates.io/crates/rayon) | Parallel processing for optimization.                                                     |
125//! | [`serde`](https://crates.io/crates/serde) | Serialize/deserialize backtest results.                                                    |
126//! | [`plotters`](https://crates.io/crates/plotters) | Visualize equity curves and indicators.                                                   |
127//!
128//! ## Error Handling
129//! BTS uses custom error types to handle:
130//! - Insufficient balance.
131//! - Invalid order types.
132//! - Missing data (e.g., candles, positions).
133//!
134//! Example:
135//! ```rust
136//! use bts::prelude::*;
137//! use chrono::DateTime;
138//!
139//! fn main() {
140//!     let candle = CandleBuilder::builder()
141//!         .open(100.0)
142//!         .high(110.0)
143//!         .low(95.0)
144//!         .close(105.0)
145//!         .volume(1.0)
146//!         .bid(0.5)
147//!         .open_time(DateTime::default())
148//!         .close_time(DateTime::default())
149//!         .build()
150//!         .unwrap();
151//!
152//!     // Initialize backtest with \$10,000
153//!     let mut backtest = Backtest::new(vec![candle], 10_000.0, None).unwrap();
154//!
155//!     // Execute a market buy order
156//!     backtest
157//!         .run(|bt, _candle| {
158//!             let order: Order = (OrderType::Market(102.0), 1.0, OrderSide::Buy).into();
159//!             match bt.place_order(order) {
160//!                Ok(_) => println!("Order in the pool!"),
161//!                Err(_) => eprintln!("Error to place an order")
162//!             }
163//!             Ok(())
164//!         })
165//!         .unwrap();
166//! }
167//! ```
168//!
169//! ## Contributing
170//! Contributions are welcome! See [`CONTRIBUTING.md`](https://github.com/raonagos/bts/blob/main/CONTRIBUTING.md).
171//!
172//! ## License
173//! MIT
174#![warn(missing_docs)]
175
176/// Core trading engine components: orders, positions, wallet, and backtest logic.
177pub mod engine;
178
179/// Error types for the library.
180pub mod errors;
181
182/// Utility functions and helpers.
183mod utils;
184
185/// Performance metrics: drawdown, Sharpe ratio, win rate, etc.
186#[cfg(feature = "metrics")]
187pub mod metrics;
188
189/// Strategy parameter optimization.
190#[cfg(feature = "optimizer")]
191pub mod optimizer;
192
193/// Re-exports of commonly used types and traits for convenience.
194pub mod prelude {
195    pub use super::*;
196    pub use crate::engine::*;
197    pub use crate::errors::*;
198
199    #[cfg(feature = "metrics")]
200    pub use crate::metrics::*;
201
202    #[cfg(feature = "optimizer")]
203    pub use crate::optimizer::*;
204}
205
206use std::ops::{Add, Div, Mul, Sub};
207
208/// Trait for performing percentage-based calculations.
209///
210/// This trait provides methods to add, subtract, and calculate percentages
211/// for numeric types, enabling common financial calculations.
212pub trait PercentCalculus<Rhs = Self> {
213    /// Adds a percentage to the value.
214    ///
215    /// ### Arguments
216    /// * `rhs` - The percentage to add (e.g., 10.0 for 10%).
217    ///
218    /// ### Returns
219    /// The value increased by the given percentage.
220    fn addpercent(self, rhs: Rhs) -> Self;
221
222    /// Subtracts a percentage from the value.
223    ///
224    /// ### Arguments
225    /// * `rhs` - The percentage to subtract (e.g., 10.0 for 10%).
226    ///
227    /// ### Returns
228    /// The value decreased by the given percentage.
229    fn subpercent(self, rhs: Rhs) -> Self;
230
231    /// Calculates the absolute value of a percentage.
232    ///
233    /// ### Arguments
234    /// * `percent` - The percentage to calculate (e.g., 10.0 for 10%).
235    ///
236    /// ### Returns
237    /// The absolute value of the given percentage.
238    fn how_many(self, percent: Self) -> Self;
239
240    /// Calculates the percentage change between two values.
241    ///
242    /// ### Arguments
243    /// * `new` - The new value to compare with.
244    ///
245    /// ### Returns
246    /// The percentage change from the original value to the new value.
247    fn change(self, new: Self) -> Self;
248}
249
250impl PercentCalculus for f64 {
251    fn addpercent(self, percent: Self) -> Self {
252        self.add(self.mul(percent.div(100.0)))
253    }
254
255    fn subpercent(self, percent: Self) -> Self {
256        self.sub(self.mul(percent.div(100.0)))
257    }
258
259    fn how_many(self, percent: Self) -> Self {
260        percent.mul(self.div(100.0))
261    }
262
263    fn change(self, new: Self) -> Self {
264        new.sub(self).div(self).mul(100.0)
265    }
266}
267
268#[cfg(test)]
269mod percent {
270    use super::*;
271
272    #[test]
273    fn add() {
274        assert_eq!(110.0, 100.0.addpercent(10.0))
275    }
276
277    #[test]
278    fn sub() {
279        assert_eq!(90.0, 100.0.subpercent(10.0))
280    }
281
282    #[test]
283    fn how_many() {
284        assert_eq!(10.0, 100.0.how_many(10.0))
285    }
286
287    #[test]
288    fn change() {
289        assert_eq!(10.0, 100.0.change(110.0))
290    }
291}