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
use ;
use async_trait;
use FutureExt;
use crate::;
use ;
/// Marker trait for signal types that can be used with the signal framework.
///
/// This trait bundles the common constraints required for signal types:
/// - `Send + Sync`: Safe to share across threads
/// - `Clone`: Can be duplicated for broadcasting
/// - `Display`: Can be formatted for logging
/// - `'static`: No borrowed references
///
/// A blanket implementation is provided for all types meeting these constraints, so this trait
/// doesn't need to be implemented manually.
///
/// # Example
///
/// ```
/// # use std::fmt;
/// # use chrono::{DateTime, Utc};
/// #[derive(Debug, Clone)]
/// pub struct MySignal {
/// pub time: DateTime<Utc>,
/// // ...
/// }
///
/// impl fmt::Display for MySignal {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "{}", self.time)
/// }
/// }
///
/// // MySignal: Signal is satisfied automatically
/// ```
/// Trait for implementing custom signal evaluation logic.
///
/// Signal evaluators analyze candlestick data to produce trading signals of type `S`. Evaluators
/// are designed to be reusable building blocks that can be composed into different operators.
///
/// # Type Parameter
///
/// * `S` - The signal type this evaluator produces. For reusable evaluators, this is typically
/// constrained with `where YourSignal: Into<S>` to allow conversion to any target type.
///
/// # Example
///
/// ```
/// # use std::fmt;
/// # use chrono::{DateTime, Utc};
/// use quantoxide::{
/// error::Result,
/// models::{
/// Lookback, MinIterationInterval, OhlcCandleRow, OhlcResolution
/// },
/// signal::{Signal, SignalEvaluator},
/// };
///
/// // Define the evaluator's native signal type
/// #[derive(Debug, Clone)]
/// pub struct MaCrossSignal {
/// pub time: DateTime<Utc>,
/// pub fast_ma: f64,
/// pub slow_ma: f64,
/// }
///
/// impl fmt::Display for MaCrossSignal {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "MaCross at {}: fast={:.2}, slow={:.2}", self.time, self.fast_ma, self.slow_ma)
/// }
/// }
///
/// // Evaluator struct is not generic, only the trait impl is
/// pub struct MaCrossEvaluator {
/// fast_period: usize,
/// slow_period: usize,
/// }
///
/// impl MaCrossEvaluator {
/// pub fn new(fast_period: usize, slow_period: usize) -> Box<Self> {
/// Box::new(Self { fast_period, slow_period })
/// }
/// }
///
/// #[async_trait::async_trait]
/// impl<S: Signal> SignalEvaluator<S> for MaCrossEvaluator
/// where
/// MaCrossSignal: Into<S>,
/// {
/// fn lookback(&self) -> Option<Lookback> {
/// Some(Lookback::new(OhlcResolution::FifteenMinutes, self.slow_period as u64)
/// .expect("valid lookback"))
/// }
///
/// fn min_iteration_interval(&self) -> MinIterationInterval {
/// MinIterationInterval::MIN
/// }
///
/// async fn evaluate(&self, candles: &[OhlcCandleRow]) -> Result<S> {
/// let signal = MaCrossSignal {
/// time: Utc::now(),
/// fast_ma: 20.0, // Calculate actual MA
/// slow_ma: 100.0,
/// };
///
/// Ok(signal.into()) // Convert to target type
/// }
/// }
/// ```
/// Internal wrapper that provides panic protection for signal evaluators.
pub ;