ta_lib_in_rust/lib.rs
1//! # Technical Indicators
2//!
3//! A comprehensive Rust library for calculating financial technical indicators
4//! using the [Polars](https://pola.rs/) DataFrame library.
5//!
6//! This crate provides functions to calculate various technical indicators
7//! from OHLCV (Open, High, Low, Close, Volume) data stored in Polars DataFrames.
8//!
9//! ## Categories
10//!
11//! The indicators are organized into the following categories:
12//!
13//! - **Moving Averages**: Trend-following indicators that smooth price data
14//! - **Oscillators**: Indicators that fluctuate within a bounded range
15//! - **Volatility**: Indicators that measure the rate of price movement
16//! - **Volume**: Indicators based on trading volume
17//! - **Trend**: Indicators designed to identify market direction
18//! - **Momentum**: Indicators that measure the rate of price change
19//! - **Strategy**: Trading strategies combining multiple indicators
20//!
21//! ## Usage Examples
22//!
23//! ### Basic Indicator Calculation
24//!
25//! ```rust
26//! use polars::prelude::*;
27//! use ta_lib_in_rust::indicators::moving_averages::calculate_sma;
28//!
29//! fn main() -> PolarsResult<()> {
30//! let close_prices = Series::new(
31//! "close".into(),
32//! &[
33//! 100.0, 101.0, 102.0, 103.0, 105.0, 104.0, 106.0, 107.0, 109.0, 108.0,
34//! 107.0, 109.0, 111.0, 114.0, 113.0, 116.0, 119.0, 120.0, 119.0, 117.0,
35//! 118.0, 120.0, 123.0, 122.0, 120.0, 118.0, 119.0, 121.0, 124.0, 125.0,
36//! ],
37//! );
38//! // Create a sample DataFrame with price data
39//! let mut df = DataFrame::new(vec![close_prices.clone().into()])?;
40//!
41//! // Calculate a Simple Moving Average
42//! let sma_10 = calculate_sma(&df, "close", 10)?;
43//! df.with_column(sma_10)?;
44//!
45//! println!("{}", df);
46//! Ok(())
47//! }
48//! ```
49//!
50//! ### Combining Multiple Indicators
51//!
52//! ```rust
53//! use polars::prelude::*;
54//! use ta_lib_in_rust::indicators::{
55//! moving_averages::{calculate_sma, calculate_ema},
56//! oscillators::calculate_rsi,
57//! volatility::calculate_bollinger_bands,
58//! };
59//!
60//! fn main() -> PolarsResult<()> {
61//! // Create a DataFrame with price data
62//! let close = Series::new("close", &[100.0, 102.0, 104.0, 103.0, 105.0, 107.0, 108.0,
63//! 107.0, 106.0, 105.0, 107.0, 108.0, 109.0, 110.0]);
64//! let high = Series::new("high", &[101.0, 103.0, 104.5, 103.5, 106.0, 107.5, 108.5,
65//! 107.2, 106.5, 105.5, 107.5, 108.5, 109.5, 111.0]);
66//! let low = Series::new("low", &[99.0, 101.5, 103.0, 102.0, 104.0, 106.0, 107.0,
67//! 106.0, 105.0, 104.0, 106.0, 107.5, 108.5, 109.0]);
68//! let mut df = DataFrame::new(vec![close.clone(), high.clone(), low.clone()])?;
69//!
70//! // Calculate multiple indicators
71//! let sma_5 = calculate_sma(&df, "close", 5)?;
72//! let ema_8 = calculate_ema(&df, "close", 8)?;
73//! let rsi_7 = calculate_rsi(&df, 7, "close")?;
74//! let (bb_middle, bb_upper, bb_lower) = calculate_bollinger_bands(&df, 10, 2.0, "close")?;
75//!
76//! // Add all indicators to the DataFrame
77//! df = df.with_columns([
78//! sma_5, ema_8, rsi_7, bb_middle, bb_upper, bb_lower
79//! ])?;
80//!
81//! // Create custom trading signals
82//! let bullish_signal = df.clone()
83//! .lazy()
84//! .with_columns([
85//! (col("close").gt(col("sma_5"))
86//! & col("close").gt(col("bb_middle"))
87//! & col("rsi_7").gt(lit(50.0)))
88//! .alias("bullish")
89//! ])
90//! .collect()?;
91//!
92//! println!("DataFrame with indicators and signals:");
93//! println!("{}", bullish_signal);
94//!
95//! Ok(())
96//! }
97//! ```
98//!
99//! ### Running a Trading Strategy Backtest
100//!
101//! ```rust
102//! use polars::prelude::*;
103//! use ta_lib_in_rust::strategy::daily::multi_indicator_daily_1::{
104//! run_strategy, calculate_performance, StrategyParams
105//! };
106//!
107//! fn main() -> PolarsResult<()> {
108//! // Load data from CSV
109//! let df = CsvReadOptions::default()
110//! .with_has_header(true)
111//! .try_into_reader_with_file_path(Some("path/to/ohlcv_data.csv".into()))?
112//! .finish()?;
113//!
114//! // Set strategy parameters
115//! let params = StrategyParams {
116//! sma_short_period: 20,
117//! sma_long_period: 50,
118//! rsi_period: 14,
119//! rsi_overbought: 70.0,
120//! rsi_oversold: 30.0,
121//! bb_period: 20,
122//! bb_std_dev: 2.0,
123//! macd_fast: 12,
124//! macd_slow: 26,
125//! macd_signal: 9,
126//! min_signals_for_buy: 3,
127//! min_signals_for_sell: 3,
128//! };
129//!
130//! // Run the strategy to generate buy and sell signals
131//! let signals = run_strategy(&df, ¶ms)?;
132//!
133//! // Calculate performance metrics
134//! let close_series = df.column("close")?;
135//! let (
136//! final_value, // Final portfolio value
137//! total_return, // Total return percentage
138//! num_trades, // Number of trades executed
139//! win_rate, // Percentage of winning trades
140//! max_drawdown, // Maximum drawdown percentage
141//! profit_factor, // Ratio of gross profit to gross loss
142//! ) = calculate_performance(
143//! close_series,
144//! &signals.buy_signals,
145//! &signals.sell_signals,
146//! 10000.0, // Initial capital
147//! );
148//!
149//! println!("Strategy Backtest Results:");
150//! println!("Final Portfolio Value: ${:.2}", final_value);
151//! println!("Total Return: {:.2}%", total_return);
152//! println!("Number of Trades: {}", num_trades);
153//! println!("Win Rate: {:.2}%", win_rate);
154//! println!("Maximum Drawdown: {:.2}%", max_drawdown * 100.0);
155//! println!("Profit Factor: {:.2}", profit_factor);
156//!
157//! Ok(())
158//! }
159//! ```
160//!
161//! ### Comparing Multiple Strategies
162//!
163//! ```rust
164//! use polars::prelude::*;
165//! use ta_lib_in_rust::strategy::minute::{
166//! multi_indicator_minute_1,
167//! multi_indicator_minute_2,
168//! multi_indicator_minute_3
169//! };
170//!
171//! fn main() -> PolarsResult<()> {
172//! // Load minute data from CSV
173//! let mut df = CsvReadOptions::default()
174//! .with_has_header(true)
175//! .try_into_reader_with_file_path(Some("path/to/minute_data.csv".into()))?
176//! .finish()?;
177//!
178//! // Cast volume to float if needed
179//! df = df.lazy()
180//! .with_columns([
181//! col("volume").cast(DataType::Float64),
182//! ])
183//! .collect()?;
184//!
185//! // Initialize strategies with default parameters
186//! let params1 = multi_indicator_minute_1::StrategyParams::default();
187//! let params2 = multi_indicator_minute_2::StrategyParams::default();
188//! let params3 = multi_indicator_minute_3::StrategyParams::default();
189//!
190//! // Run strategies
191//! let signals1 = multi_indicator_minute_1::run_strategy(&df, ¶ms1)?;
192//! let signals2 = multi_indicator_minute_2::run_strategy(&df, ¶ms2)?;
193//! let signals3 = multi_indicator_minute_3::run_strategy(&df, ¶ms3)?;
194//!
195//! // Calculate performance for each strategy
196//! let close_prices = df.column("close")?;
197//!
198//! let (final_value1, return1, trades1, win_rate1, drawdown1, _, _) =
199//! multi_indicator_minute_1::calculate_performance(
200//! close_prices,
201//! &signals1.buy_signals,
202//! &signals1.sell_signals,
203//! 10000.0,
204//! true
205//! );
206//!
207//! let (final_value2, return2, trades2, win_rate2, drawdown2, _, _) =
208//! multi_indicator_minute_2::calculate_performance(
209//! close_prices,
210//! &signals2.buy_signals,
211//! &signals2.sell_signals,
212//! &signals2.position_sizes,
213//! 10000.0,
214//! true,
215//! None
216//! );
217//!
218//! // Compare results
219//! println!("Strategy Comparison:");
220//! println!("Metric | Strategy 1 | Strategy 2");
221//! println!("------------------------------------");
222//! println!("Return | {:.2}% | {:.2}%", return1, return2);
223//! println!("Final Value | ${:.2} | ${:.2}", final_value1, final_value2);
224//! println!("Win Rate | {:.2}% | {:.2}%", win_rate1, win_rate2);
225//! println!("Max Drawdown| {:.2}% | {:.2}%", drawdown1*100.0, drawdown2*100.0);
226//!
227//! // Determine best performer
228//! if return1 > return2 {
229//! println!("\nStrategy 1 performed better on absolute return");
230//! } else {
231//! println!("\nStrategy 2 performed better on absolute return");
232//! }
233//!
234//! // Risk-adjusted comparison
235//! let risk_adjusted1 = return1 / (drawdown1 * 100.0);
236//! let risk_adjusted2 = return2 / (drawdown2 * 100.0);
237//!
238//! if risk_adjusted1 > risk_adjusted2 {
239//! println!("Strategy 1 performed better on risk-adjusted basis");
240//! } else {
241//! println!("Strategy 2 performed better on risk-adjusted basis");
242//! }
243//!
244//! Ok(())
245//! }
246//! ```
247//!
248//! See the documentation for each module for more detailed information and examples.
249
250pub mod indicators;
251pub mod strategy;
252pub mod util;
253
254// Re-export commonly used items
255pub use indicators::*;
256pub use strategy::*;
257
258// This is a placeholder function - should be removed before final release
259pub fn add(left: u64, right: u64) -> u64 {
260 left + right
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
268 fn it_works() {
269 let result = add(2, 2);
270 assert_eq!(result, 4);
271 }
272}