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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! # ib-flex
//!
//! Pure Rust parser for Interactive Brokers FLEX XML statements.
//!
//! ## Features
//!
//! - 🚀 **Zero-copy parsing** with quick-xml and serde
//! - 💰 **Financial precision** with rust_decimal for all monetary values
//! - 📅 **Correct datetime handling** with chrono
//! - ✅ **Type-safe** enums for asset categories, order types, etc.
//! - 🔧 **No external dependencies** beyond XML/serde
//! - 📦 **Supports both Activity and Trade Confirmation FLEX**
//!
//! ## Quick Start
//!
//! ```rust,no_run
//! use ib_flex::parse_activity_flex;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let xml = std::fs::read_to_string("flex_statement.xml")?;
//! let statement = parse_activity_flex(&xml)?;
//!
//! println!("Account: {}", statement.account_id);
//! println!("Total trades: {}", statement.trades.items.len());
//!
//! // Calculate total commissions
//! let total_commission: rust_decimal::Decimal =
//! statement.trades.items.iter().filter_map(|t| t.commission).sum();
//! println!("Total commissions: ${}", total_commission);
//! # Ok(())
//! # }
//! ```
//!
//! ## Supported FLEX Sections
//!
//! ### Activity FLEX
//! - ✅ Trades
//! - ✅ Open Positions
//! - ✅ Cash Transactions
//! - ✅ Corporate Actions
//! - ✅ Securities Info
//! - ✅ FX Conversion Rates
//!
//! ### Trade Confirmation FLEX
//! - ✅ Trade executions with all details
//! - ✅ Commission breakdown
//!
//! ## Known Limitations
//!
//! 1. **Date formats**: Only ISO-8601 (yyyy-MM-dd) and yyyyMMdd supported
//! 2. **Schema versions**: Tested with FLEX schema version 3
// Re-export commonly used types
pub use ;
pub use ;
pub use FlexSchemaVersion;
/// Parse an Activity FLEX XML statement
///
/// Parses Interactive Brokers Activity FLEX XML into a structured
/// Rust type with all trades, positions, cash flows, and other data.
///
/// # Arguments
///
/// * `xml` - XML string from IB FLEX query (Activity type)
///
/// # Returns
///
/// * `Ok(ActivityFlexStatement)` - Successfully parsed statement
/// * `Err(ParseError)` - Parse error with detailed context
///
/// # Errors
///
/// Returns `ParseError` if:
/// - XML is malformed or invalid
/// - Required fields are missing
/// - Date/decimal formats are invalid
/// - FLEX schema version is unsupported
///
/// # Example
///
/// ```rust,no_run
/// use ib_flex::parse_activity_flex;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let xml = std::fs::read_to_string("statement.xml")?;
/// let statement = parse_activity_flex(&xml)?;
///
/// println!("Trades: {}", statement.trades.items.len());
/// # Ok(())
/// # }
/// ```
/// Parse all Activity FLEX statements from XML
///
/// FLEX queries can contain multiple statements (e.g., for different days
/// in a date range backfill). This function returns all of them.
///
/// # Arguments
///
/// * `xml` - XML string from IB Activity FLEX query
///
/// # Returns
///
/// * `Ok(Vec<ActivityFlexStatement>)` - All parsed statements
/// * `Err(ParseError)` - Parse error with context
/// Parse a Trade Confirmation FLEX XML statement
///
/// Parses Interactive Brokers Trade Confirmation FLEX XML into a structured
/// Rust type with real-time trade execution data.
///
/// # Arguments
///
/// * `xml` - XML string from IB FLEX query (Trade Confirmation type)
///
/// # Returns
///
/// * `Ok(TradeConfirmationStatement)` - Successfully parsed statement
/// * `Err(ParseError)` - Parse error with detailed context
///
/// # Errors
///
/// Returns `ParseError` if:
/// - XML is malformed or invalid
/// - Required fields are missing
/// - Date/decimal formats are invalid
///
/// # Example
///
/// ```rust,no_run
/// use ib_flex::parse_trade_confirmation;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let xml = std::fs::read_to_string("trade_conf.xml")?;
/// let statement = parse_trade_confirmation(&xml)?;
///
/// println!("Trade executions: {}", statement.trades.items.len());
/// # Ok(())
/// # }
/// ```
/// Detect FLEX statement type from XML
///
/// Examines the XML structure to determine whether it's an Activity FLEX
/// or Trade Confirmation FLEX statement.
///
/// # Arguments
///
/// * `xml` - XML string from IB FLEX query
///
/// # Returns
///
/// * `Ok(StatementType)` - Detected statement type
/// * `Err(ParseError)` - If type cannot be determined
///
/// # Example
///
/// ```rust,no_run
/// use ib_flex::{detect_statement_type, StatementType};
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let xml = std::fs::read_to_string("statement.xml")?;
///
/// match detect_statement_type(&xml)? {
/// StatementType::Activity => println!("Activity FLEX"),
/// StatementType::TradeConfirmation => println!("Trade Confirmation"),
/// }
/// # Ok(())
/// # }
/// ```
/// FLEX statement type