1use thiserror::Error;
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Candle {
10 pub timestamp: i64, pub open: f64,
12 pub high: f64,
13 pub low: f64,
14 pub close: f64,
15 pub volume: f64,
16}
17
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum PriceSource {
22 Open,
23 High,
24 Low,
25 Close,
26 HLC3,
27 OHLC4,
28 HL2,
29}
30
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Side {
35 Long,
36 Short,
37}
38
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41#[derive(Debug, Clone, PartialEq)]
42pub enum Signal {
43 Entry(Side),
44 Exit(ExitReason),
45 Hold,
46}
47
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50#[derive(Debug, Clone, PartialEq)]
51pub enum ExitReason {
52 RuleTriggered,
53 StopLoss,
54 TakeProfit,
55 TrailingStop,
56 DailyLossLimit,
57 DrawdownBreaker,
58}
59
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub enum Timeframe {
64 M1,
65 M5,
66 M15,
67 M30,
68 H1,
69 H4,
70 D1,
71 W1,
72 MN1,
73}
74
75#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
77#[derive(Debug, Clone, Copy, PartialEq)]
78pub struct MacdOutput {
79 pub macd_line: f64,
80 pub signal_line: f64,
81 pub histogram: f64,
82}
83
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
86#[derive(Debug, Clone, Copy, PartialEq)]
87pub struct BollingerOutput {
88 pub upper: f64,
89 pub middle: f64,
90 pub lower: f64,
91}
92
93#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
95#[derive(Debug, Clone, Copy, PartialEq)]
96pub struct KeltnerOutput {
97 pub upper: f64,
98 pub middle: f64,
99 pub lower: f64,
100}
101
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104#[derive(Debug, Clone, Copy, PartialEq)]
105pub struct DonchianOutput {
106 pub upper: f64,
107 pub middle: f64,
108 pub lower: f64,
109}
110
111#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113#[derive(Debug, Clone, Copy, PartialEq)]
114pub struct StochasticOutput {
115 pub k: f64,
116 pub d: f64,
117}
118
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121#[derive(Debug, Clone, Copy, PartialEq)]
122pub struct AdxOutput {
123 pub plus_di: f64,
124 pub minus_di: f64,
125 pub adx: f64,
126}
127
128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
130#[derive(Debug, Clone, Copy, PartialEq)]
131pub struct IchimokuOutput {
132 pub tenkan_sen: f64,
133 pub kijun_sen: f64,
134 pub senkou_span_a: f64,
135 pub senkou_span_b: f64,
136 pub chikou_span: f64,
137}
138
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
141#[derive(Debug, Clone, Copy, PartialEq)]
142pub struct PivotOutput {
143 pub pp: f64,
144 pub r1: f64,
145 pub r2: f64,
146 pub r3: f64,
147 pub s1: f64,
148 pub s2: f64,
149 pub s3: f64,
150}
151
152#[derive(Error, Debug)]
154pub enum MantisError {
155 #[error("Invalid parameter: {param} = {value} ({reason})")]
156 InvalidParameter {
157 param: &'static str,
158 value: String,
159 reason: &'static str,
160 },
161
162 #[error("Insufficient data: need {required} candles, got {provided}")]
163 InsufficientData { required: usize, provided: usize },
164
165 #[error("Strategy validation failed: {0}")]
166 StrategyValidation(String),
167
168 #[error("Backtest error: {0}")]
169 BacktestError(String),
170}
171
172pub type Result<T> = std::result::Result<T, MantisError>;