ib_flex/
lib.rs

1//! # ib-flex
2//!
3//! Pure Rust parser for Interactive Brokers FLEX XML statements.
4//!
5//! ## Features
6//!
7//! - 🚀 **Zero-copy parsing** with quick-xml and serde
8//! - 💰 **Financial precision** with rust_decimal for all monetary values
9//! - 📅 **Correct datetime handling** with chrono
10//! - ✅ **Type-safe** enums for asset categories, order types, etc.
11//! - 🔧 **No external dependencies** beyond XML/serde
12//! - 📦 **Supports both Activity and Trade Confirmation FLEX**
13//!
14//! ## Quick Start
15//!
16//! ```rust,no_run
17//! use ib_flex::parse_activity_flex;
18//!
19//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
20//! let xml = std::fs::read_to_string("flex_statement.xml")?;
21//! let statement = parse_activity_flex(&xml)?;
22//!
23//! println!("Account: {}", statement.account_id);
24//! println!("Total trades: {}", statement.trades.items.len());
25//!
26//! // Calculate total commissions
27//! let total_commission: rust_decimal::Decimal =
28//!     statement.trades.items.iter().map(|t| t.commission).sum();
29//! println!("Total commissions: ${}", total_commission);
30//! # Ok(())
31//! # }
32//! ```
33//!
34//! ## Supported FLEX Sections
35//!
36//! ### Activity FLEX
37//! - ✅ Trades
38//! - ✅ Open Positions
39//! - ✅ Cash Transactions
40//! - ✅ Corporate Actions
41//! - ✅ Securities Info
42//! - ✅ FX Conversion Rates
43//!
44//! ### Trade Confirmation FLEX
45//! - ✅ Trade executions with all details
46//! - ✅ Commission breakdown
47//!
48//! ## Known Limitations
49//!
50//! 1. **Date formats**: Only ISO-8601 (yyyy-MM-dd) and yyyyMMdd supported
51//! 2. **Schema versions**: Tested with FLEX schema version 3
52
53#![warn(missing_docs)]
54#![warn(clippy::all)]
55
56pub mod error;
57pub mod parsers;
58pub mod types;
59pub mod version;
60
61#[cfg(feature = "api-client")]
62pub mod api;
63
64// Re-export commonly used types
65pub use error::{ParseError, Result};
66pub use types::{
67    ActivityFlexStatement, AssetCategory, BuySell, CashTransaction, CorporateAction, OpenClose,
68    OrderType, Position, PutCall, Trade, TradeConfirmationStatement,
69};
70pub use version::FlexSchemaVersion;
71
72/// Parse an Activity FLEX XML statement
73///
74/// Parses Interactive Brokers Activity FLEX XML into a structured
75/// Rust type with all trades, positions, cash flows, and other data.
76///
77/// # Arguments
78///
79/// * `xml` - XML string from IB FLEX query (Activity type)
80///
81/// # Returns
82///
83/// * `Ok(ActivityFlexStatement)` - Successfully parsed statement
84/// * `Err(ParseError)` - Parse error with detailed context
85///
86/// # Errors
87///
88/// Returns `ParseError` if:
89/// - XML is malformed or invalid
90/// - Required fields are missing
91/// - Date/decimal formats are invalid
92/// - FLEX schema version is unsupported
93///
94/// # Example
95///
96/// ```rust,no_run
97/// use ib_flex::parse_activity_flex;
98///
99/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
100/// let xml = std::fs::read_to_string("statement.xml")?;
101/// let statement = parse_activity_flex(&xml)?;
102///
103/// println!("Trades: {}", statement.trades.items.len());
104/// # Ok(())
105/// # }
106/// ```
107pub fn parse_activity_flex(xml: &str) -> Result<ActivityFlexStatement> {
108    parsers::parse_activity_flex(xml)
109}
110
111/// Parse a Trade Confirmation FLEX XML statement
112///
113/// Parses Interactive Brokers Trade Confirmation FLEX XML into a structured
114/// Rust type with real-time trade execution data.
115///
116/// # Arguments
117///
118/// * `xml` - XML string from IB FLEX query (Trade Confirmation type)
119///
120/// # Returns
121///
122/// * `Ok(TradeConfirmationStatement)` - Successfully parsed statement
123/// * `Err(ParseError)` - Parse error with detailed context
124///
125/// # Errors
126///
127/// Returns `ParseError` if:
128/// - XML is malformed or invalid
129/// - Required fields are missing
130/// - Date/decimal formats are invalid
131///
132/// # Example
133///
134/// ```rust,no_run
135/// use ib_flex::parse_trade_confirmation;
136///
137/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
138/// let xml = std::fs::read_to_string("trade_conf.xml")?;
139/// let statement = parse_trade_confirmation(&xml)?;
140///
141/// println!("Trade executions: {}", statement.trades.items.len());
142/// # Ok(())
143/// # }
144/// ```
145pub fn parse_trade_confirmation(xml: &str) -> Result<TradeConfirmationStatement> {
146    parsers::parse_trade_confirmation(xml)
147}
148
149/// Detect FLEX statement type from XML
150///
151/// Examines the XML structure to determine whether it's an Activity FLEX
152/// or Trade Confirmation FLEX statement.
153///
154/// # Arguments
155///
156/// * `xml` - XML string from IB FLEX query
157///
158/// # Returns
159///
160/// * `Ok(StatementType)` - Detected statement type
161/// * `Err(ParseError)` - If type cannot be determined
162///
163/// # Example
164///
165/// ```rust,no_run
166/// use ib_flex::{detect_statement_type, StatementType};
167///
168/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
169/// let xml = std::fs::read_to_string("statement.xml")?;
170///
171/// match detect_statement_type(&xml)? {
172///     StatementType::Activity => println!("Activity FLEX"),
173///     StatementType::TradeConfirmation => println!("Trade Confirmation"),
174/// }
175/// # Ok(())
176/// # }
177/// ```
178pub fn detect_statement_type(xml: &str) -> Result<StatementType> {
179    version::detect_statement_type(xml)
180}
181
182/// FLEX statement type
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum StatementType {
185    /// Activity FLEX statement (daily EOD)
186    Activity,
187    /// Trade Confirmation FLEX statement (real-time)
188    TradeConfirmation,
189}