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
use crate::;
/// Returns the lookback period required for Average Daily Range (ADR) calculation.
///
/// # Description
/// The lookback period represents the number of data points needed before the first valid output
/// can be calculated. For ADR, this equals the specified period minus one.
///
/// # Arguments
/// * `param_period` - The time period used for ADR calculation (must be >= 2)
///
/// # Returns
/// * `Result<usize, KandError>` - The lookback period (period - 1) on success
///
/// # Errors
/// * Returns `KandError::InvalidParameter` if `param_period` is less than 2
///
/// # Example
/// ```
/// use kand::ohlcv::adr;
/// let period = 14;
/// let lookback = adr::lookback(period).unwrap();
/// assert_eq!(lookback, 13); // lookback is period - 1
/// ```
pub const
/// Calculates Average Daily Range (ADR) for an entire price series.
///
/// # Description
/// The Average Daily Range measures the average price range over a specified period,
/// helping to identify volatility levels in the market.
///
/// # Mathematical Formula
/// ```text
/// Daily Range = High - Low
/// ADR = SMA(Daily Range, period)
/// ```
///
/// # Calculation Steps
/// 1. Calculate daily range for each period: High - Low
/// 2. Apply Simple Moving Average (SMA) to the daily ranges
/// 3. First (period-1) values will be NaN as they require full period data
///
/// # Arguments
/// * `input_high` - Array of high prices
/// * `input_low` - Array of low prices
/// * `param_period` - The time period for ADR calculation (must be >= 2)
/// * `output_adr` - Array to store calculated ADR values
///
/// # Returns
/// * `Result<(), KandError>` - Ok(()) on success, Err on failure
///
/// # Errors
/// * `KandError::InvalidData` - If input arrays are empty
/// * `KandError::LengthMismatch` - If input arrays have different lengths
/// * `KandError::InvalidParameter` - If `param_period` is less than 2
///
/// # Example
/// ```
/// use kand::ohlcv::adr;
/// let input_high = vec![10.0, 12.0, 15.0, 14.0, 13.0];
/// let input_low = vec![8.0, 9.0, 11.0, 10.0, 9.0];
/// let param_period = 3;
/// let mut output_adr = vec![0.0; 5];
///
/// adr::adr(&input_high, &input_low, param_period, &mut output_adr).unwrap();
/// // First two values are NaN (period-1), followed by calculated ADR values
/// ```
/// Calculates the next Average Daily Range (ADR) value incrementally.
///
/// # Description
/// Optimizes ADR calculation by using previous ADR value and only calculating
/// the latest value, avoiding recalculation of the entire series.
///
/// # Arguments
/// * `prev_adr` - Previous ADR value
/// * `input_new_high` - Latest high price
/// * `input_new_low` - Latest low price
/// * `input_old_high` - Oldest high price to be removed from period
/// * `input_old_low` - Oldest low price to be removed from period
/// * `param_period` - The time period for ADR calculation (must be >= 2)
///
/// # Returns
/// * `Result<TAFloat, KandError>` - Latest ADR value on success, Err on failure
///
/// # Errors
/// * `KandError::NaNDetected` - If any input value is NaN
/// * `KandError::InvalidParameter` - If `param_period` is less than 2
///
/// # Example
/// ```
/// use kand::ohlcv::adr;
/// let prev_adr = 3.0;
/// let new_high = 15.0;
/// let new_low = 12.0;
/// let old_high = 10.0;
/// let old_low = 8.0;
/// let period = 14;
///
/// let next_adr = adr::adr_inc(prev_adr, new_high, new_low, old_high, old_low, period).unwrap();
/// ```