Skip to main content

truefix_twsapi_client/
decoder.rs

1use prost::Message;
2use rust_decimal::Decimal;
3
4use crate::error::{TwsApiError, TwsApiResult};
5use crate::events::{Event, ScannerDataRow};
6use crate::message::{Incoming, PROTOBUF_MSG_ID};
7use crate::protobuf;
8use crate::types::{
9    BarData, ComboLeg, CommissionAndFeesReport, Contract, ContractDescription, ContractDetails,
10    DeltaNeutralContract, Execution, HistogramEntry, HistoricalSession, HistoricalTick,
11    HistoricalTickBidAsk, HistoricalTickLast, IneligibilityReason, LegOpenClose, NewsProvider,
12    Order, OrderAllocation, OrderCondition, OrderState, Origin, PriceIncrement, SmartComponent,
13    SoftDollarTier, TagValue, TickAttribBidAsk, TickAttribLast, TickByTick,
14};
15use crate::types::{DepthMarketDataDescription, FamilyCode};
16
17mod order;
18mod order_proto;
19
20/// Decodes a field-based incoming payload into an [`Event`].
21pub fn decode_payload(server_uses_raw_msg_id: bool, payload: &[u8]) -> TwsApiResult<Event> {
22    let (msg_id, body) = split_message_id(server_uses_raw_msg_id, payload)?;
23    if msg_id > PROTOBUF_MSG_ID {
24        return decode_protobuf_event(msg_id - PROTOBUF_MSG_ID, body);
25    }
26
27    let fields = crate::comm::read_fields(body)
28        .into_iter()
29        .map(|field| String::from_utf8_lossy(field).into_owned())
30        .collect::<Vec<_>>();
31
32    match Incoming::try_from(msg_id) {
33        Ok(Incoming::NextValidId) => {
34            let order_id = parse_i32(fields.first())?;
35            Ok(Event::NextValidId { order_id })
36        }
37        Ok(Incoming::CurrentTime) => {
38            let time = parse_i64(fields.first())?;
39            Ok(Event::CurrentTime { time })
40        }
41        Ok(Incoming::CurrentTimeInMillis) => {
42            let time_in_millis = parse_i64(fields.first())?;
43            Ok(Event::CurrentTimeInMillis { time_in_millis })
44        }
45        Ok(Incoming::ErrorMessage) => {
46            let req_id = parse_i32(fields.first())?;
47            let code = parse_i32(fields.get(1))?;
48            let message = fields.get(2).cloned().unwrap_or_default();
49            let advanced_order_reject_json = fields.get(3).cloned().unwrap_or_default();
50            Ok(Event::Error {
51                req_id,
52                time: 0,
53                code,
54                message,
55                advanced_order_reject_json,
56            })
57        }
58        Ok(Incoming::ManagedAccounts) => Ok(Event::ManagedAccounts {
59            accounts: fields.first().cloned().unwrap_or_default(),
60        }),
61        Ok(Incoming::AccountValue) => Ok(Event::AccountValue {
62            key: fields.first().cloned().unwrap_or_default(),
63            value: fields.get(1).cloned().unwrap_or_default(),
64            currency: fields.get(2).cloned().unwrap_or_default(),
65            account_name: fields.get(3).cloned().unwrap_or_default(),
66        }),
67        Ok(Incoming::AccountUpdateTime) => Ok(Event::AccountUpdateTime {
68            timestamp: fields.first().cloned().unwrap_or_default(),
69        }),
70        Ok(Incoming::AccountDownloadEnd) => Ok(Event::AccountDownloadEnd {
71            account_name: fields.first().cloned().unwrap_or_default(),
72        }),
73        Ok(Incoming::NewsBulletins) => Ok(Event::NewsBulletin {
74            news_msg_id: parse_i32(fields.first())?,
75            news_msg_type: parse_i32(fields.get(1))?,
76            news_message: fields.get(2).cloned().unwrap_or_default(),
77            originating_exch: fields.get(3).cloned().unwrap_or_default(),
78        }),
79        Ok(Incoming::ReceiveFa) => Ok(Event::ReceiveFa {
80            fa_data_type: parse_i32(fields.first())?,
81            xml: fields.get(1).cloned().unwrap_or_default(),
82        }),
83        Ok(Incoming::ScannerParameters) => Ok(Event::ScannerParameters {
84            xml: fields.first().cloned().unwrap_or_default(),
85        }),
86        Ok(Incoming::ScannerData) => decode_scanner_data_fields(&fields),
87        Ok(Incoming::SoftDollarTiers) => decode_soft_dollar_tiers_fields(&fields),
88        Ok(Incoming::FamilyCodes) => decode_family_codes_fields(&fields),
89        Ok(Incoming::SymbolSamples) => decode_symbol_samples_fields(&fields),
90        Ok(Incoming::SmartComponents) => decode_smart_components_fields(&fields),
91        Ok(Incoming::MarketDepthExchanges) => decode_market_depth_exchanges_fields(&fields),
92        Ok(Incoming::HeadTimestamp) => Ok(Event::HeadTimestamp {
93            req_id: parse_i32(fields.first())?,
94            head_timestamp: fields.get(1).cloned().unwrap_or_default(),
95        }),
96        Ok(Incoming::HistogramData) => decode_histogram_data_fields(&fields),
97        Ok(Incoming::RerouteMarketDataRequest) => Ok(Event::RerouteMarketDataRequest {
98            req_id: parse_i32(fields.first())?,
99            con_id: parse_i32(fields.get(1))?,
100            exchange: fields.get(2).cloned().unwrap_or_default(),
101        }),
102        Ok(Incoming::RerouteMarketDepthRequest) => Ok(Event::RerouteMarketDepthRequest {
103            req_id: parse_i32(fields.first())?,
104            con_id: parse_i32(fields.get(1))?,
105            exchange: fields.get(2).cloned().unwrap_or_default(),
106        }),
107        Ok(Incoming::MarketRule) => decode_market_rule_fields(&fields),
108        Ok(Incoming::DisplayGroupList) => Ok(Event::DisplayGroupList {
109            req_id: parse_i32(fields.first())?,
110            groups: fields.get(1).cloned().unwrap_or_default(),
111        }),
112        Ok(Incoming::DisplayGroupUpdated) => Ok(Event::DisplayGroupUpdated {
113            req_id: parse_i32(fields.first())?,
114            contract_info: fields.get(1).cloned().unwrap_or_default(),
115        }),
116        Ok(Incoming::MarketDataType) => Ok(Event::MarketDataType {
117            req_id: parse_i32(fields.first())?,
118            market_data_type: parse_i32(fields.get(1))?,
119        }),
120        Ok(Incoming::TickPrice) => Ok(Event::TickPrice {
121            req_id: parse_i32(fields.first())?,
122            tick_type: parse_i32(fields.get(1))?,
123            price: parse_f64(fields.get(2))?,
124            attrib: parse_i32(fields.get(3)).unwrap_or_default(),
125        }),
126        Ok(Incoming::TickSize) => Ok(Event::TickSize {
127            req_id: parse_i32(fields.first())?,
128            tick_type: parse_i32(fields.get(1))?,
129            size: parse_decimal(fields.get(2))?,
130        }),
131        Ok(Incoming::TickGeneric) => Ok(Event::TickGeneric {
132            req_id: parse_i32(fields.first())?,
133            tick_type: parse_i32(fields.get(1))?,
134            value: parse_f64(fields.get(2))?,
135        }),
136        Ok(Incoming::TickString) => Ok(Event::TickString {
137            req_id: parse_i32(fields.first())?,
138            tick_type: parse_i32(fields.get(1))?,
139            value: fields.get(2).cloned().unwrap_or_default(),
140        }),
141        Ok(Incoming::TickOptionComputation) => decode_tick_option_computation_fields(&fields),
142        Ok(Incoming::TickEfp) => Ok(Event::TickEfp {
143            req_id: parse_i32(fields.first())?,
144            tick_type: parse_i32(fields.get(1))?,
145            basis_points: parse_f64(fields.get(2))?,
146            formatted_basis_points: fields.get(3).cloned().unwrap_or_default(),
147            total_dividends: parse_f64(fields.get(4))?,
148            hold_days: parse_i32(fields.get(5))?,
149            future_last_trade_date: fields.get(6).cloned().unwrap_or_default(),
150            dividend_impact: parse_f64(fields.get(7))?,
151            dividends_to_last_trade_date: parse_f64(fields.get(8))?,
152        }),
153        Ok(Incoming::TickRequestParameters) => Ok(Event::TickReqParams {
154            req_id: parse_i32(fields.first())?,
155            min_tick: fields.get(1).cloned().unwrap_or_default(),
156            bbo_exchange: fields.get(2).cloned().unwrap_or_default(),
157            snapshot_permissions: parse_i32(fields.get(3))?,
158            last_price_precision: String::new(),
159            last_size_precision: String::new(),
160        }),
161        Ok(Incoming::TickSnapshotEnd) => Ok(Event::TickSnapshotEnd {
162            req_id: parse_i32(fields.first())?,
163        }),
164        Ok(Incoming::MarketDepth) => decode_market_depth_fields(&fields, false),
165        Ok(Incoming::MarketDepthL2) => decode_market_depth_fields(&fields, true),
166        Ok(Incoming::OrderStatus) => {
167            let offset = if server_uses_raw_msg_id { 0 } else { 1 };
168            Ok(Event::OrderStatus {
169                order_id: parse_i32(fields.get(offset))?,
170                status: fields.get(offset + 1).cloned().unwrap_or_default(),
171                filled: parse_decimal(fields.get(offset + 2))?,
172                remaining: parse_decimal(fields.get(offset + 3))?,
173                avg_fill_price: parse_f64(fields.get(offset + 4))?,
174                perm_id: parse_i64(fields.get(offset + 5))?,
175                parent_id: parse_i32(fields.get(offset + 6))?,
176                last_fill_price: parse_f64(fields.get(offset + 7))?,
177                client_id: parse_i32(fields.get(offset + 8))?,
178                why_held: fields.get(offset + 9).cloned().unwrap_or_default(),
179                market_cap_price: parse_f64(fields.get(offset + 10)).unwrap_or_default(),
180            })
181        }
182        Ok(Incoming::DeltaNeutralValidation) => Ok(Event::DeltaNeutralValidation {
183            req_id: parse_i32(fields.get(1))?,
184            delta_neutral_contract: DeltaNeutralContract {
185                con_id: parse_i32(fields.get(2))?,
186                delta: parse_f64(fields.get(3))?,
187                price: parse_f64(fields.get(4))?,
188            },
189        }),
190        Ok(Incoming::CommissionAndFeesReport) => Ok(Event::CommissionAndFeesReport {
191            report: CommissionAndFeesReport {
192                exec_id: fields.get(1).cloned().unwrap_or_default(),
193                commission_and_fees: parse_f64(fields.get(2))?,
194                currency: fields.get(3).cloned().unwrap_or_default(),
195                realized_pnl: parse_f64(fields.get(4))?,
196                bond_yield: parse_f64(fields.get(5))?,
197                yield_redemption_date: fields.get(6).cloned().unwrap_or_default(),
198            },
199        }),
200        Ok(Incoming::PortfolioValue) => decode_portfolio_value_fields(&fields),
201        Ok(Incoming::OpenOrder) => order::decode_open_order_fields(&fields),
202        Ok(Incoming::OpenOrderEnd) => Ok(Event::OpenOrderEnd),
203        Ok(Incoming::ContractData) => decode_contract_data_fields(&fields),
204        Ok(Incoming::BondContractData) => decode_bond_contract_data_fields(&fields),
205        Ok(Incoming::ContractDataEnd) => Ok(Event::ContractDetailsEnd {
206            req_id: parse_i32(fields.first())?,
207        }),
208        Ok(Incoming::ExecutionData) => decode_execution_data_fields(&fields),
209        Ok(Incoming::ExecutionDataEnd) => Ok(Event::ExecutionDetailsEnd {
210            req_id: parse_i32(fields.first())?,
211        }),
212        Ok(Incoming::PositionData) => decode_position_fields(&fields),
213        Ok(Incoming::PositionEnd) => Ok(Event::PositionEnd),
214        Ok(Incoming::PositionMulti) => decode_position_multi_fields(&fields),
215        Ok(Incoming::PositionMultiEnd) => Ok(Event::PositionMultiEnd {
216            req_id: parse_i32(fields.first())?,
217        }),
218        Ok(Incoming::AccountSummary) => Ok(Event::AccountSummary {
219            req_id: parse_i32(fields.first())?,
220            account: fields.get(1).cloned().unwrap_or_default(),
221            tag: fields.get(2).cloned().unwrap_or_default(),
222            value: fields.get(3).cloned().unwrap_or_default(),
223            currency: fields.get(4).cloned().unwrap_or_default(),
224        }),
225        Ok(Incoming::AccountSummaryEnd) => Ok(Event::AccountSummaryEnd {
226            req_id: parse_i32(fields.first())?,
227        }),
228        Ok(Incoming::AccountUpdateMulti) => Ok(Event::AccountUpdateMulti {
229            req_id: parse_i32(fields.first())?,
230            account: fields.get(1).cloned().unwrap_or_default(),
231            model_code: fields.get(2).cloned().unwrap_or_default(),
232            key: fields.get(3).cloned().unwrap_or_default(),
233            value: fields.get(4).cloned().unwrap_or_default(),
234            currency: fields.get(5).cloned().unwrap_or_default(),
235        }),
236        Ok(Incoming::AccountUpdateMultiEnd) => Ok(Event::AccountUpdateMultiEnd {
237            req_id: parse_i32(fields.first())?,
238        }),
239        Ok(Incoming::VerifyMessageApi) => Ok(Event::VerifyMessageApi {
240            api_data: fields.first().cloned().unwrap_or_default(),
241        }),
242        Ok(Incoming::VerifyCompleted) => Ok(Event::VerifyCompleted {
243            is_successful: parse_bool(fields.first()),
244            error_text: fields.get(1).cloned().unwrap_or_default(),
245        }),
246        Ok(Incoming::VerifyAndAuthMessageApi) => Ok(Event::VerifyAndAuthMessageApi {
247            api_data: fields.first().cloned().unwrap_or_default(),
248            challenge: fields.get(1).cloned().unwrap_or_default(),
249        }),
250        Ok(Incoming::VerifyAndAuthCompleted) => Ok(Event::VerifyAndAuthCompleted {
251            is_successful: parse_bool(fields.first()),
252            error_text: fields.get(1).cloned().unwrap_or_default(),
253        }),
254        Ok(Incoming::SecurityDefinitionOptionParameter) => {
255            decode_security_definition_option_parameter_fields(&fields)
256        }
257        Ok(Incoming::SecurityDefinitionOptionParameterEnd) => {
258            Ok(Event::SecurityDefinitionOptionParameterEnd {
259                req_id: parse_i32(fields.first())?,
260            })
261        }
262        Ok(Incoming::HistoricalData) => decode_historical_data_fields(&fields),
263        Ok(Incoming::HistoricalDataUpdate) => decode_historical_data_update_fields(&fields),
264        Ok(Incoming::HistoricalTicks) => decode_historical_ticks_fields(&fields),
265        Ok(Incoming::HistoricalTicksBidAsk) => decode_historical_ticks_bid_ask_fields(&fields),
266        Ok(Incoming::HistoricalTicksLast) => decode_historical_ticks_last_fields(&fields),
267        Ok(Incoming::TickByTick) => decode_tick_by_tick_fields(&fields),
268        Ok(Incoming::RealTimeBars) => decode_real_time_bar_fields(&fields),
269        Ok(Incoming::HistoricalSchedule) => decode_historical_schedule_fields(&fields),
270        Ok(Incoming::Pnl) => decode_pnl_fields(&fields),
271        Ok(Incoming::PnlSingle) => decode_pnl_single_fields(&fields),
272        Ok(Incoming::NewsArticle) => Ok(Event::NewsArticle {
273            req_id: parse_i32(fields.first())?,
274            article_type: parse_i32(fields.get(1))?,
275            article_text: fields.get(2).cloned().unwrap_or_default(),
276        }),
277        Ok(Incoming::NewsProviders) => decode_news_providers_fields(&fields),
278        Ok(Incoming::HistoricalNews) => Ok(Event::HistoricalNews {
279            req_id: parse_i32(fields.first())?,
280            time: fields.get(1).cloned().unwrap_or_default(),
281            provider_code: fields.get(2).cloned().unwrap_or_default(),
282            article_id: fields.get(3).cloned().unwrap_or_default(),
283            headline: fields.get(4).cloned().unwrap_or_default(),
284        }),
285        Ok(Incoming::HistoricalNewsEnd) => Ok(Event::HistoricalNewsEnd {
286            req_id: parse_i32(fields.first())?,
287            has_more: parse_bool(fields.get(1)),
288        }),
289        Ok(Incoming::TickNews) => Ok(Event::TickNews {
290            req_id: parse_i32(fields.first())?,
291            timestamp: parse_i64(fields.get(1))?,
292            provider_code: fields.get(2).cloned().unwrap_or_default(),
293            article_id: fields.get(3).cloned().unwrap_or_default(),
294            headline: fields.get(4).cloned().unwrap_or_default(),
295            extra_data: fields.get(5).cloned().unwrap_or_default(),
296        }),
297        Ok(Incoming::HistoricalDataEnd) => Ok(Event::HistoricalDataEnd {
298            req_id: parse_i32(fields.first())?,
299            start: fields.get(1).cloned().unwrap_or_default(),
300            end: fields.get(2).cloned().unwrap_or_default(),
301        }),
302        Ok(Incoming::ReplaceFaEnd) => Ok(Event::ReplaceFaEnd {
303            req_id: parse_i32(fields.first())?,
304            text: fields.get(1).cloned().unwrap_or_default(),
305        }),
306        Ok(Incoming::WshMetaData) => Ok(Event::WshMetaData {
307            req_id: parse_i32(fields.first())?,
308            data_json: fields.get(1).cloned().unwrap_or_default(),
309        }),
310        Ok(Incoming::WshEventData) => Ok(Event::WshEventData {
311            req_id: parse_i32(fields.first())?,
312            data_json: fields.get(1).cloned().unwrap_or_default(),
313        }),
314        Ok(Incoming::CompletedOrdersEnd) => Ok(Event::CompletedOrdersEnd),
315        Ok(Incoming::CompletedOrder) => order::decode_completed_order_fields(&fields),
316        Ok(Incoming::OrderBound) => Ok(Event::OrderBound {
317            perm_id: parse_i64(fields.first())?,
318            client_id: parse_i32(fields.get(1))?,
319            order_id: parse_i32(fields.get(2))?,
320        }),
321        Ok(Incoming::UserInfo) => Ok(Event::UserInfo {
322            req_id: parse_i32(fields.first())?,
323            white_branding_id: fields.get(1).cloned().unwrap_or_default(),
324        }),
325        _ => Ok(Event::Raw { msg_id, fields }),
326    }
327}
328
329/// Decodes a protobuf incoming payload into an [`Event`].
330pub fn decode_protobuf_event(msg_id: i32, payload: &[u8]) -> TwsApiResult<Event> {
331    match Incoming::try_from(msg_id) {
332        Ok(Incoming::NextValidId) => {
333            let msg = protobuf::NextValidId::decode(payload)?;
334            Ok(Event::NextValidId {
335                order_id: msg.order_id.unwrap_or_default(),
336            })
337        }
338        Ok(Incoming::CurrentTime) => {
339            let msg = protobuf::CurrentTime::decode(payload)?;
340            Ok(Event::CurrentTime {
341                time: msg.current_time.unwrap_or_default(),
342            })
343        }
344        Ok(Incoming::CurrentTimeInMillis) => {
345            let msg = protobuf::CurrentTimeInMillis::decode(payload)?;
346            Ok(Event::CurrentTimeInMillis {
347                time_in_millis: msg.current_time_in_millis.unwrap_or_default(),
348            })
349        }
350        Ok(Incoming::ErrorMessage) => {
351            let msg = protobuf::ErrorMessage::decode(payload)?;
352            Ok(Event::Error {
353                req_id: msg.id.unwrap_or_default(),
354                time: msg.error_time.unwrap_or_default(),
355                code: msg.error_code.unwrap_or_default(),
356                message: msg.error_msg.unwrap_or_default(),
357                advanced_order_reject_json: msg.advanced_order_reject_json.unwrap_or_default(),
358            })
359        }
360        Ok(Incoming::ManagedAccounts) => {
361            let msg = protobuf::ManagedAccounts::decode(payload)?;
362            Ok(Event::ManagedAccounts {
363                accounts: msg.accounts_list.unwrap_or_default(),
364            })
365        }
366        Ok(Incoming::OrderStatus) => {
367            let msg = protobuf::OrderStatus::decode(payload)?;
368            Ok(Event::OrderStatus {
369                order_id: msg.order_id.unwrap_or_default(),
370                status: msg.status.unwrap_or_default(),
371                filled: parse_decimal_string(msg.filled.as_deref())?,
372                remaining: parse_decimal_string(msg.remaining.as_deref())?,
373                avg_fill_price: msg.avg_fill_price.unwrap_or_default(),
374                perm_id: msg.perm_id.unwrap_or_default(),
375                parent_id: msg.parent_id.unwrap_or_default(),
376                last_fill_price: msg.last_fill_price.unwrap_or_default(),
377                client_id: msg.client_id.unwrap_or_default(),
378                why_held: msg.why_held.unwrap_or_default(),
379                market_cap_price: msg.mkt_cap_price.unwrap_or_default(),
380            })
381        }
382        Ok(Incoming::TickString) => {
383            let msg = protobuf::TickString::decode(payload)?;
384            Ok(Event::TickString {
385                req_id: msg.req_id.unwrap_or_default(),
386                tick_type: msg.tick_type.unwrap_or_default(),
387                value: msg.value.unwrap_or_default(),
388            })
389        }
390        Ok(Incoming::TickPrice) => {
391            let msg = protobuf::TickPrice::decode(payload)?;
392            Ok(Event::TickPrice {
393                req_id: msg.req_id.unwrap_or_default(),
394                tick_type: msg.tick_type.unwrap_or_default(),
395                price: msg.price.unwrap_or_default(),
396                attrib: msg.attr_mask.unwrap_or_default(),
397            })
398        }
399        Ok(Incoming::TickSize) => {
400            let msg = protobuf::TickSize::decode(payload)?;
401            Ok(Event::TickSize {
402                req_id: msg.req_id.unwrap_or_default(),
403                tick_type: msg.tick_type.unwrap_or_default(),
404                size: parse_decimal_string(msg.size.as_deref())?,
405            })
406        }
407        Ok(Incoming::TickGeneric) => {
408            let msg = protobuf::TickGeneric::decode(payload)?;
409            Ok(Event::TickGeneric {
410                req_id: msg.req_id.unwrap_or_default(),
411                tick_type: msg.tick_type.unwrap_or_default(),
412                value: msg.value.unwrap_or_default(),
413            })
414        }
415        Ok(Incoming::TickOptionComputation) => {
416            let msg = protobuf::TickOptionComputation::decode(payload)?;
417            Ok(Event::TickOptionComputation {
418                req_id: msg.req_id.unwrap_or_default(),
419                tick_type: msg.tick_type.unwrap_or_default(),
420                tick_attrib: msg.tick_attrib.unwrap_or_default(),
421                implied_vol: msg.implied_vol.unwrap_or_default(),
422                delta: msg.delta.unwrap_or_default(),
423                opt_price: msg.opt_price.unwrap_or_default(),
424                pv_dividend: msg.pv_dividend.unwrap_or_default(),
425                gamma: msg.gamma.unwrap_or_default(),
426                vega: msg.vega.unwrap_or_default(),
427                theta: msg.theta.unwrap_or_default(),
428                und_price: msg.und_price.unwrap_or_default(),
429            })
430        }
431        Ok(Incoming::TickRequestParameters) => {
432            let msg = protobuf::TickReqParams::decode(payload)?;
433            Ok(Event::TickReqParams {
434                req_id: msg.req_id.unwrap_or_default(),
435                min_tick: msg.min_tick.unwrap_or_default(),
436                bbo_exchange: msg.bbo_exchange.unwrap_or_default(),
437                snapshot_permissions: msg.snapshot_permissions.unwrap_or_default(),
438                last_price_precision: msg.last_price_precision.unwrap_or_default(),
439                last_size_precision: msg.last_size_precision.unwrap_or_default(),
440            })
441        }
442        Ok(Incoming::CommissionAndFeesReport) => {
443            let msg = protobuf::CommissionAndFeesReport::decode(payload)?;
444            Ok(Event::CommissionAndFeesReport {
445                report: CommissionAndFeesReport {
446                    exec_id: msg.exec_id.unwrap_or_default(),
447                    commission_and_fees: msg.commission_and_fees.unwrap_or_default(),
448                    currency: msg.currency.unwrap_or_default(),
449                    realized_pnl: msg.realized_pnl.unwrap_or_default(),
450                    bond_yield: msg.bond_yield.unwrap_or_default(),
451                    yield_redemption_date: msg.yield_redemption_date.unwrap_or_default(),
452                },
453            })
454        }
455        Ok(Incoming::TickSnapshotEnd) => {
456            let msg = protobuf::TickSnapshotEnd::decode(payload)?;
457            Ok(Event::TickSnapshotEnd {
458                req_id: msg.req_id.unwrap_or_default(),
459            })
460        }
461        Ok(Incoming::MarketDataType) => {
462            let msg = protobuf::MarketDataType::decode(payload)?;
463            Ok(Event::MarketDataType {
464                req_id: msg.req_id.unwrap_or_default(),
465                market_data_type: msg.market_data_type.unwrap_or_default(),
466            })
467        }
468        Ok(Incoming::OpenOrderEnd) => Ok(Event::OpenOrderEnd),
469        Ok(Incoming::AccountValue) => {
470            let msg = protobuf::AccountValue::decode(payload)?;
471            Ok(Event::AccountValue {
472                key: msg.key.unwrap_or_default(),
473                value: msg.value.unwrap_or_default(),
474                currency: msg.currency.unwrap_or_default(),
475                account_name: msg.account_name.unwrap_or_default(),
476            })
477        }
478        Ok(Incoming::PortfolioValue) => {
479            let msg = protobuf::PortfolioValue::decode(payload)?;
480            Ok(Event::PortfolioValue {
481                contract: Box::new(proto_contract_to_contract(msg.contract)),
482                position: parse_decimal_string(msg.position.as_deref())?,
483                market_price: msg.market_price.unwrap_or_default(),
484                market_value: msg.market_value.unwrap_or_default(),
485                average_cost: msg.average_cost.unwrap_or_default(),
486                unrealized_pnl: msg.unrealized_pnl.unwrap_or_default(),
487                realized_pnl: msg.realized_pnl.unwrap_or_default(),
488                account_name: msg.account_name.unwrap_or_default(),
489            })
490        }
491        Ok(Incoming::AccountUpdateTime) => {
492            let msg = protobuf::AccountUpdateTime::decode(payload)?;
493            Ok(Event::AccountUpdateTime {
494                timestamp: msg.time_stamp.unwrap_or_default(),
495            })
496        }
497        Ok(Incoming::AccountDownloadEnd) => {
498            let msg = protobuf::AccountDataEnd::decode(payload)?;
499            Ok(Event::AccountDownloadEnd {
500                account_name: msg.account_name.unwrap_or_default(),
501            })
502        }
503        Ok(Incoming::MarketDepth) => {
504            let msg = protobuf::MarketDepth::decode(payload)?;
505            proto_market_depth_to_event(msg.req_id, msg.market_depth_data)
506        }
507        Ok(Incoming::MarketDepthL2) => {
508            let msg = protobuf::MarketDepthL2::decode(payload)?;
509            proto_market_depth_to_event(msg.req_id, msg.market_depth_data)
510        }
511        Ok(Incoming::MarketDepthExchanges) => {
512            let msg = protobuf::MarketDepthExchanges::decode(payload)?;
513            Ok(Event::MarketDepthExchanges {
514                descriptions: msg
515                    .depth_market_data_descriptions
516                    .into_iter()
517                    .map(|description| DepthMarketDataDescription {
518                        exchange: description.exchange.unwrap_or_default(),
519                        security_type: description.sec_type.unwrap_or_default(),
520                        listing_exchange: description.listing_exch.unwrap_or_default(),
521                        service_data_type: description.service_data_type.unwrap_or_default(),
522                        aggregate_group: description.agg_group.unwrap_or_default(),
523                    })
524                    .collect(),
525            })
526        }
527        Ok(Incoming::SmartComponents) => {
528            let msg = protobuf::SmartComponents::decode(payload)?;
529            Ok(Event::SmartComponents {
530                req_id: msg.req_id.unwrap_or_default(),
531                components: msg
532                    .smart_components
533                    .into_iter()
534                    .map(proto_smart_component)
535                    .collect(),
536            })
537        }
538        Ok(Incoming::RerouteMarketDataRequest) => {
539            let msg = protobuf::RerouteMarketDataRequest::decode(payload)?;
540            Ok(Event::RerouteMarketDataRequest {
541                req_id: msg.req_id.unwrap_or_default(),
542                con_id: msg.con_id.unwrap_or_default(),
543                exchange: msg.exchange.unwrap_or_default(),
544            })
545        }
546        Ok(Incoming::RerouteMarketDepthRequest) => {
547            let msg = protobuf::RerouteMarketDepthRequest::decode(payload)?;
548            Ok(Event::RerouteMarketDepthRequest {
549                req_id: msg.req_id.unwrap_or_default(),
550                con_id: msg.con_id.unwrap_or_default(),
551                exchange: msg.exchange.unwrap_or_default(),
552            })
553        }
554        Ok(Incoming::OpenOrder) => {
555            let msg = protobuf::OpenOrder::decode(payload)?;
556            Ok(Event::OpenOrder {
557                order_id: msg.order_id.unwrap_or_default(),
558                contract: Box::new(proto_contract_to_contract(msg.contract)),
559                order: Box::new(order_proto::proto_order_to_order(msg.order)?),
560                order_state: Box::new(order_proto::proto_order_state_to_order_state(
561                    msg.order_state,
562                )),
563            })
564        }
565        Ok(Incoming::ContractData) => {
566            let msg = protobuf::ContractData::decode(payload)?;
567            Ok(Event::ContractDetails {
568                req_id: msg.req_id.unwrap_or_default(),
569                details: Box::new(proto_contract_details_to_contract_details(
570                    msg.contract,
571                    msg.contract_details,
572                )?),
573            })
574        }
575        Ok(Incoming::BondContractData) => {
576            let msg = protobuf::ContractData::decode(payload)?;
577            Ok(Event::BondContractDetails {
578                req_id: msg.req_id.unwrap_or_default(),
579                details: Box::new(proto_contract_details_to_contract_details(
580                    msg.contract,
581                    msg.contract_details,
582                )?),
583            })
584        }
585        Ok(Incoming::ContractDataEnd) => {
586            let msg = protobuf::ContractDataEnd::decode(payload)?;
587            Ok(Event::ContractDetailsEnd {
588                req_id: msg.req_id.unwrap_or_default(),
589            })
590        }
591        Ok(Incoming::ExecutionData) => {
592            let msg = protobuf::ExecutionDetails::decode(payload)?;
593            Ok(Event::ExecutionDetails {
594                req_id: msg.req_id.unwrap_or_default(),
595                contract: Box::new(proto_contract_to_contract(msg.contract)),
596                execution: proto_execution_to_execution(msg.execution)?,
597            })
598        }
599        Ok(Incoming::ExecutionDataEnd) => {
600            let msg = protobuf::ExecutionDetailsEnd::decode(payload)?;
601            Ok(Event::ExecutionDetailsEnd {
602                req_id: msg.req_id.unwrap_or_default(),
603            })
604        }
605        Ok(Incoming::HistoricalData) => {
606            let msg = protobuf::HistoricalData::decode(payload)?;
607            Ok(Event::HistoricalDataBars {
608                req_id: msg.req_id.unwrap_or_default(),
609                bars: msg
610                    .historical_data_bars
611                    .into_iter()
612                    .map(proto_bar_to_bar)
613                    .collect::<TwsApiResult<Vec<_>>>()?,
614            })
615        }
616        Ok(Incoming::HistoricalDataUpdate) => {
617            let msg = protobuf::HistoricalDataUpdate::decode(payload)?;
618            Ok(Event::HistoricalDataUpdate {
619                req_id: msg.req_id.unwrap_or_default(),
620                bar: proto_bar_to_bar(msg.historical_data_bar.unwrap_or_default())?,
621            })
622        }
623        Ok(Incoming::RealTimeBars) => {
624            let msg = protobuf::RealTimeBarTick::decode(payload)?;
625            Ok(Event::RealTimeBar {
626                req_id: msg.req_id.unwrap_or_default(),
627                time: msg.time.unwrap_or_default(),
628                bar: BarData {
629                    date: msg.time.unwrap_or_default().to_string(),
630                    open: msg.open.unwrap_or_default(),
631                    high: msg.high.unwrap_or_default(),
632                    low: msg.low.unwrap_or_default(),
633                    close: msg.close.unwrap_or_default(),
634                    volume: parse_decimal_string(msg.volume.as_deref())?,
635                    wap: parse_decimal_string(msg.wap.as_deref())?,
636                    bar_count: msg.count.unwrap_or_default(),
637                },
638            })
639        }
640        Ok(Incoming::HeadTimestamp) => {
641            let msg = protobuf::HeadTimestamp::decode(payload)?;
642            Ok(Event::HeadTimestamp {
643                req_id: msg.req_id.unwrap_or_default(),
644                head_timestamp: msg.head_timestamp.unwrap_or_default(),
645            })
646        }
647        Ok(Incoming::HistogramData) => {
648            let msg = protobuf::HistogramData::decode(payload)?;
649            Ok(Event::HistogramData {
650                req_id: msg.req_id.unwrap_or_default(),
651                items: msg
652                    .histogram_data_entries
653                    .into_iter()
654                    .map(|entry| {
655                        Ok(HistogramEntry {
656                            price: entry.price.unwrap_or_default(),
657                            size: parse_decimal_string(entry.size.as_deref())?,
658                        })
659                    })
660                    .collect::<TwsApiResult<Vec<_>>>()?,
661            })
662        }
663        Ok(Incoming::ScannerParameters) => {
664            let msg = protobuf::ScannerParameters::decode(payload)?;
665            Ok(Event::ScannerParameters {
666                xml: msg.xml.unwrap_or_default(),
667            })
668        }
669        Ok(Incoming::ScannerData) => {
670            let msg = protobuf::ScannerData::decode(payload)?;
671            Ok(Event::ScannerData {
672                req_id: msg.req_id.unwrap_or_default(),
673                rows: msg
674                    .scanner_data_element
675                    .into_iter()
676                    .map(|row| ScannerDataRow {
677                        rank: row.rank.unwrap_or_default(),
678                        contract: Box::new(proto_contract_to_contract(row.contract)),
679                        market_name: row.market_name.unwrap_or_default(),
680                        distance: row.distance.unwrap_or_default(),
681                        benchmark: row.benchmark.unwrap_or_default(),
682                        projection: row.projection.unwrap_or_default(),
683                        combo_key: row.combo_key.unwrap_or_default(),
684                    })
685                    .collect(),
686            })
687        }
688        Ok(Incoming::SoftDollarTiers) => {
689            let msg = protobuf::SoftDollarTiers::decode(payload)?;
690            Ok(Event::SoftDollarTiers {
691                req_id: msg.req_id.unwrap_or_default(),
692                tiers: msg
693                    .soft_dollar_tiers
694                    .into_iter()
695                    .map(|tier| SoftDollarTier {
696                        name: tier.name.unwrap_or_default(),
697                        value: tier.value.unwrap_or_default(),
698                        display_name: tier.display_name.unwrap_or_default(),
699                    })
700                    .collect(),
701            })
702        }
703        Ok(Incoming::FamilyCodes) => {
704            let msg = protobuf::FamilyCodes::decode(payload)?;
705            Ok(Event::FamilyCodes {
706                family_codes: msg
707                    .family_codes
708                    .into_iter()
709                    .map(|code| FamilyCode {
710                        account_id: code.account_id.unwrap_or_default(),
711                        family_code: code.family_code.unwrap_or_default(),
712                    })
713                    .collect(),
714            })
715        }
716        Ok(Incoming::SymbolSamples) => {
717            let msg = protobuf::SymbolSamples::decode(payload)?;
718            Ok(Event::SymbolSamples {
719                req_id: msg.req_id.unwrap_or_default(),
720                descriptions: msg
721                    .contract_descriptions
722                    .into_iter()
723                    .map(proto_contract_description)
724                    .collect(),
725            })
726        }
727        Ok(Incoming::MarketRule) => {
728            let msg = protobuf::MarketRule::decode(payload)?;
729            Ok(Event::MarketRule {
730                market_rule_id: msg.market_rule_id.unwrap_or_default(),
731                price_increments: msg
732                    .price_increments
733                    .into_iter()
734                    .map(|increment| PriceIncrement {
735                        low_edge: increment.low_edge.unwrap_or_default(),
736                        increment: increment.increment.unwrap_or_default(),
737                    })
738                    .collect(),
739            })
740        }
741        Ok(Incoming::PositionData) => {
742            let msg = protobuf::Position::decode(payload)?;
743            Ok(Event::Position {
744                account: msg.account.unwrap_or_default(),
745                contract: Box::new(proto_contract_to_contract(msg.contract)),
746                position: parse_decimal_string(msg.position.as_deref())?,
747                avg_cost: msg.avg_cost.unwrap_or_default(),
748            })
749        }
750        Ok(Incoming::PositionEnd) => Ok(Event::PositionEnd),
751        Ok(Incoming::PositionMulti) => {
752            let msg = protobuf::PositionMulti::decode(payload)?;
753            Ok(Event::PositionMulti {
754                req_id: msg.req_id.unwrap_or_default(),
755                account: msg.account.unwrap_or_default(),
756                model_code: msg.model_code.unwrap_or_default(),
757                contract: Box::new(proto_contract_to_contract(msg.contract)),
758                position: parse_decimal_string(msg.position.as_deref())?,
759                avg_cost: msg.avg_cost.unwrap_or_default(),
760            })
761        }
762        Ok(Incoming::PositionMultiEnd) => {
763            let msg = protobuf::PositionMultiEnd::decode(payload)?;
764            Ok(Event::PositionMultiEnd {
765                req_id: msg.req_id.unwrap_or_default(),
766            })
767        }
768        Ok(Incoming::AccountSummary) => {
769            let msg = protobuf::AccountSummary::decode(payload)?;
770            Ok(Event::AccountSummary {
771                req_id: msg.req_id.unwrap_or_default(),
772                account: msg.account.unwrap_or_default(),
773                tag: msg.tag.unwrap_or_default(),
774                value: msg.value.unwrap_or_default(),
775                currency: msg.currency.unwrap_or_default(),
776            })
777        }
778        Ok(Incoming::AccountSummaryEnd) => {
779            let msg = protobuf::AccountSummaryEnd::decode(payload)?;
780            Ok(Event::AccountSummaryEnd {
781                req_id: msg.req_id.unwrap_or_default(),
782            })
783        }
784        Ok(Incoming::AccountUpdateMulti) => {
785            let msg = protobuf::AccountUpdateMulti::decode(payload)?;
786            Ok(Event::AccountUpdateMulti {
787                req_id: msg.req_id.unwrap_or_default(),
788                account: msg.account.unwrap_or_default(),
789                model_code: msg.model_code.unwrap_or_default(),
790                key: msg.key.unwrap_or_default(),
791                value: msg.value.unwrap_or_default(),
792                currency: msg.currency.unwrap_or_default(),
793            })
794        }
795        Ok(Incoming::AccountUpdateMultiEnd) => {
796            let msg = protobuf::AccountUpdateMultiEnd::decode(payload)?;
797            Ok(Event::AccountUpdateMultiEnd {
798                req_id: msg.req_id.unwrap_or_default(),
799            })
800        }
801        Ok(Incoming::HistoricalDataEnd) => {
802            let msg = protobuf::HistoricalDataEnd::decode(payload)?;
803            Ok(Event::HistoricalDataEnd {
804                req_id: msg.req_id.unwrap_or_default(),
805                start: msg.start_date_str.unwrap_or_default(),
806                end: msg.end_date_str.unwrap_or_default(),
807            })
808        }
809        Ok(Incoming::HistoricalTicks) => {
810            let msg = protobuf::HistoricalTicks::decode(payload)?;
811            Ok(Event::HistoricalTicks {
812                req_id: msg.req_id.unwrap_or_default(),
813                ticks: msg
814                    .historical_ticks
815                    .into_iter()
816                    .map(proto_historical_tick)
817                    .collect::<TwsApiResult<Vec<_>>>()?,
818                done: msg.is_done.unwrap_or_default(),
819            })
820        }
821        Ok(Incoming::HistoricalTicksBidAsk) => {
822            let msg = protobuf::HistoricalTicksBidAsk::decode(payload)?;
823            Ok(Event::HistoricalTicksBidAsk {
824                req_id: msg.req_id.unwrap_or_default(),
825                ticks: msg
826                    .historical_ticks_bid_ask
827                    .into_iter()
828                    .map(proto_historical_tick_bid_ask)
829                    .collect::<TwsApiResult<Vec<_>>>()?,
830                done: msg.is_done.unwrap_or_default(),
831            })
832        }
833        Ok(Incoming::HistoricalTicksLast) => {
834            let msg = protobuf::HistoricalTicksLast::decode(payload)?;
835            Ok(Event::HistoricalTicksLast {
836                req_id: msg.req_id.unwrap_or_default(),
837                ticks: msg
838                    .historical_ticks_last
839                    .into_iter()
840                    .map(proto_historical_tick_last)
841                    .collect::<TwsApiResult<Vec<_>>>()?,
842                done: msg.is_done.unwrap_or_default(),
843            })
844        }
845        Ok(Incoming::TickByTick) => {
846            let msg = protobuf::TickByTickData::decode(payload)?;
847            Ok(Event::TickByTick {
848                req_id: msg.req_id.unwrap_or_default(),
849                tick_type: msg.tick_type.unwrap_or_default(),
850                tick: proto_tick_by_tick(msg.tick)?,
851            })
852        }
853        Ok(Incoming::HistoricalSchedule) => {
854            let msg = protobuf::HistoricalSchedule::decode(payload)?;
855            Ok(Event::HistoricalSchedule {
856                req_id: msg.req_id.unwrap_or_default(),
857                start_date_time: msg.start_date_time.unwrap_or_default(),
858                end_date_time: msg.end_date_time.unwrap_or_default(),
859                time_zone: msg.time_zone.unwrap_or_default(),
860                sessions: msg
861                    .historical_sessions
862                    .into_iter()
863                    .map(proto_historical_session)
864                    .collect(),
865            })
866        }
867        Ok(Incoming::Pnl) => {
868            let msg = protobuf::PnL::decode(payload)?;
869            Ok(Event::Pnl {
870                req_id: msg.req_id.unwrap_or_default(),
871                daily_pnl: msg.daily_pn_l.unwrap_or_default(),
872                unrealized_pnl: msg.unrealized_pn_l.unwrap_or_default(),
873                realized_pnl: msg.realized_pn_l.unwrap_or_default(),
874            })
875        }
876        Ok(Incoming::PnlSingle) => {
877            let msg = protobuf::PnLSingle::decode(payload)?;
878            Ok(Event::PnlSingle {
879                req_id: msg.req_id.unwrap_or_default(),
880                position: parse_decimal_string(msg.position.as_deref())?,
881                daily_pnl: msg.daily_pn_l.unwrap_or_default(),
882                unrealized_pnl: msg.unrealized_pn_l.unwrap_or_default(),
883                realized_pnl: msg.realized_pn_l.unwrap_or_default(),
884                value: msg.value.unwrap_or_default(),
885            })
886        }
887        Ok(Incoming::NewsArticle) => {
888            let msg = protobuf::NewsArticle::decode(payload)?;
889            Ok(Event::NewsArticle {
890                req_id: msg.req_id.unwrap_or_default(),
891                article_type: msg.article_type.unwrap_or_default(),
892                article_text: msg.article_text.unwrap_or_default(),
893            })
894        }
895        Ok(Incoming::NewsBulletins) => {
896            let msg = protobuf::NewsBulletin::decode(payload)?;
897            Ok(Event::NewsBulletin {
898                news_msg_id: msg.news_msg_id.unwrap_or_default(),
899                news_msg_type: msg.news_msg_type.unwrap_or_default(),
900                news_message: msg.news_message.unwrap_or_default(),
901                originating_exch: msg.originating_exch.unwrap_or_default(),
902            })
903        }
904        Ok(Incoming::NewsProviders) => {
905            let msg = protobuf::NewsProviders::decode(payload)?;
906            Ok(Event::NewsProviders {
907                providers: msg
908                    .news_providers
909                    .into_iter()
910                    .map(|provider| NewsProvider {
911                        code: provider.provider_code.unwrap_or_default(),
912                        name: provider.provider_name.unwrap_or_default(),
913                    })
914                    .collect(),
915            })
916        }
917        Ok(Incoming::HistoricalNews) => {
918            let msg = protobuf::HistoricalNews::decode(payload)?;
919            Ok(Event::HistoricalNews {
920                req_id: msg.req_id.unwrap_or_default(),
921                time: msg.time.unwrap_or_default(),
922                provider_code: msg.provider_code.unwrap_or_default(),
923                article_id: msg.article_id.unwrap_or_default(),
924                headline: msg.headline.unwrap_or_default(),
925            })
926        }
927        Ok(Incoming::HistoricalNewsEnd) => {
928            let msg = protobuf::HistoricalNewsEnd::decode(payload)?;
929            Ok(Event::HistoricalNewsEnd {
930                req_id: msg.req_id.unwrap_or_default(),
931                has_more: msg.has_more.unwrap_or_default(),
932            })
933        }
934        Ok(Incoming::TickNews) => {
935            let msg = protobuf::TickNews::decode(payload)?;
936            Ok(Event::TickNews {
937                req_id: msg.req_id.unwrap_or_default(),
938                timestamp: msg.timestamp.unwrap_or_default(),
939                provider_code: msg.provider_code.unwrap_or_default(),
940                article_id: msg.article_id.unwrap_or_default(),
941                headline: msg.headline.unwrap_or_default(),
942                extra_data: msg.extra_data.unwrap_or_default(),
943            })
944        }
945        Ok(Incoming::WshMetaData) => {
946            let msg = protobuf::WshMetaData::decode(payload)?;
947            Ok(Event::WshMetaData {
948                req_id: msg.req_id.unwrap_or_default(),
949                data_json: msg.data_json.unwrap_or_default(),
950            })
951        }
952        Ok(Incoming::WshEventData) => {
953            let msg = protobuf::WshEventData::decode(payload)?;
954            Ok(Event::WshEventData {
955                req_id: msg.req_id.unwrap_or_default(),
956                data_json: msg.data_json.unwrap_or_default(),
957            })
958        }
959        Ok(Incoming::ReceiveFa) => {
960            let msg = protobuf::ReceiveFa::decode(payload)?;
961            Ok(Event::ReceiveFa {
962                fa_data_type: msg.fa_data_type.unwrap_or_default(),
963                xml: msg.xml.unwrap_or_default(),
964            })
965        }
966        Ok(Incoming::ReplaceFaEnd) => {
967            let msg = protobuf::ReplaceFaEnd::decode(payload)?;
968            Ok(Event::ReplaceFaEnd {
969                req_id: msg.req_id.unwrap_or_default(),
970                text: msg.text.unwrap_or_default(),
971            })
972        }
973        Ok(Incoming::DisplayGroupList) => {
974            let msg = protobuf::DisplayGroupList::decode(payload)?;
975            Ok(Event::DisplayGroupList {
976                req_id: msg.req_id.unwrap_or_default(),
977                groups: msg.groups.unwrap_or_default(),
978            })
979        }
980        Ok(Incoming::DisplayGroupUpdated) => {
981            let msg = protobuf::DisplayGroupUpdated::decode(payload)?;
982            Ok(Event::DisplayGroupUpdated {
983                req_id: msg.req_id.unwrap_or_default(),
984                contract_info: msg.contract_info.unwrap_or_default(),
985            })
986        }
987        Ok(Incoming::VerifyMessageApi) => {
988            let msg = protobuf::VerifyMessageApi::decode(payload)?;
989            Ok(Event::VerifyMessageApi {
990                api_data: msg.api_data.unwrap_or_default(),
991            })
992        }
993        Ok(Incoming::VerifyCompleted) => {
994            let msg = protobuf::VerifyCompleted::decode(payload)?;
995            Ok(Event::VerifyCompleted {
996                is_successful: msg.is_successful.unwrap_or_default(),
997                error_text: msg.error_text.unwrap_or_default(),
998            })
999        }
1000        Ok(Incoming::OrderBound) => {
1001            let msg = protobuf::OrderBound::decode(payload)?;
1002            Ok(Event::OrderBound {
1003                perm_id: msg.perm_id.unwrap_or_default(),
1004                client_id: msg.client_id.unwrap_or_default(),
1005                order_id: msg.order_id.unwrap_or_default(),
1006            })
1007        }
1008        Ok(Incoming::CompletedOrder) => {
1009            let msg = protobuf::CompletedOrder::decode(payload)?;
1010            Ok(Event::CompletedOrder {
1011                contract: Box::new(proto_contract_to_contract(msg.contract)),
1012                order: Box::new(order_proto::proto_order_to_order(msg.order)?),
1013                order_state: Box::new(order_proto::proto_order_state_to_order_state(
1014                    msg.order_state,
1015                )),
1016            })
1017        }
1018        Ok(Incoming::CompletedOrdersEnd) => Ok(Event::CompletedOrdersEnd),
1019        Ok(Incoming::UserInfo) => {
1020            let msg = protobuf::UserInfo::decode(payload)?;
1021            Ok(Event::UserInfo {
1022                req_id: msg.req_id.unwrap_or_default(),
1023                white_branding_id: msg.white_branding_id.unwrap_or_default(),
1024            })
1025        }
1026        Ok(Incoming::ConfigResponse) => {
1027            let msg = protobuf::ConfigResponse::decode(payload)?;
1028            Ok(Event::ConfigResponse {
1029                req_id: msg.req_id.unwrap_or_default(),
1030                status: String::new(),
1031                message: format!(
1032                    "lock_and_exit={}, messages={}, api={}, orders={}",
1033                    msg.lock_and_exit.is_some(),
1034                    msg.messages.len(),
1035                    msg.api.is_some(),
1036                    msg.orders.is_some()
1037                ),
1038            })
1039        }
1040        Ok(Incoming::UpdateConfigResponse) => {
1041            let msg = protobuf::UpdateConfigResponse::decode(payload)?;
1042            Ok(Event::UpdateConfigResponse {
1043                req_id: msg.req_id.unwrap_or_default(),
1044                status: msg.status.unwrap_or_default(),
1045                message: msg.message.unwrap_or_default(),
1046                changed_fields: msg.changed_fields,
1047                errors: msg.errors,
1048            })
1049        }
1050        _ => Ok(Event::RawProtobuf {
1051            msg_id,
1052            payload: payload.to_vec(),
1053        }),
1054    }
1055}
1056
1057fn proto_market_depth_to_event(
1058    req_id: Option<i32>,
1059    data: Option<protobuf::MarketDepthData>,
1060) -> TwsApiResult<Event> {
1061    let data = data.unwrap_or_default();
1062    Ok(Event::MarketDepth {
1063        req_id: req_id.unwrap_or_default(),
1064        position: data.position.unwrap_or_default(),
1065        operation: data.operation.unwrap_or_default(),
1066        side: data.side.unwrap_or_default(),
1067        price: data.price.unwrap_or_default(),
1068        size: parse_decimal_string(data.size.as_deref())?,
1069        market_maker: data.market_maker.unwrap_or_default(),
1070        is_smart_depth: data.is_smart_depth.unwrap_or_default(),
1071    })
1072}
1073
1074fn proto_bar_to_bar(bar: protobuf::HistoricalDataBar) -> TwsApiResult<BarData> {
1075    Ok(BarData {
1076        date: bar.date.unwrap_or_default(),
1077        open: bar.open.unwrap_or_default(),
1078        high: bar.high.unwrap_or_default(),
1079        low: bar.low.unwrap_or_default(),
1080        close: bar.close.unwrap_or_default(),
1081        volume: parse_decimal_string(bar.volume.as_deref())?,
1082        wap: parse_decimal_string(bar.wap.as_deref())?,
1083        bar_count: bar.bar_count.unwrap_or_default(),
1084    })
1085}
1086
1087fn proto_historical_tick(tick: protobuf::HistoricalTick) -> TwsApiResult<HistoricalTick> {
1088    Ok(HistoricalTick {
1089        time: tick.time.unwrap_or_default(),
1090        price: tick.price.unwrap_or_default(),
1091        size: parse_decimal_string(tick.size.as_deref())?,
1092    })
1093}
1094
1095fn proto_tick_attrib_bid_ask(attrib: Option<protobuf::TickAttribBidAsk>) -> TickAttribBidAsk {
1096    let Some(attrib) = attrib else {
1097        return TickAttribBidAsk::default();
1098    };
1099
1100    TickAttribBidAsk {
1101        bid_past_low: attrib.bid_past_low.unwrap_or_default(),
1102        ask_past_high: attrib.ask_past_high.unwrap_or_default(),
1103    }
1104}
1105
1106fn proto_tick_attrib_last(attrib: Option<protobuf::TickAttribLast>) -> TickAttribLast {
1107    let Some(attrib) = attrib else {
1108        return TickAttribLast::default();
1109    };
1110
1111    TickAttribLast {
1112        past_limit: attrib.past_limit.unwrap_or_default(),
1113        unreported: attrib.unreported.unwrap_or_default(),
1114    }
1115}
1116
1117fn proto_historical_tick_bid_ask(
1118    tick: protobuf::HistoricalTickBidAsk,
1119) -> TwsApiResult<HistoricalTickBidAsk> {
1120    Ok(HistoricalTickBidAsk {
1121        time: tick.time.unwrap_or_default(),
1122        tick_attrib_bid_ask: proto_tick_attrib_bid_ask(tick.tick_attrib_bid_ask),
1123        price_bid: tick.price_bid.unwrap_or_default(),
1124        price_ask: tick.price_ask.unwrap_or_default(),
1125        size_bid: parse_decimal_string(tick.size_bid.as_deref())?,
1126        size_ask: parse_decimal_string(tick.size_ask.as_deref())?,
1127    })
1128}
1129
1130fn proto_historical_tick_last(
1131    tick: protobuf::HistoricalTickLast,
1132) -> TwsApiResult<HistoricalTickLast> {
1133    Ok(HistoricalTickLast {
1134        time: tick.time.unwrap_or_default(),
1135        tick_attrib_last: proto_tick_attrib_last(tick.tick_attrib_last),
1136        price: tick.price.unwrap_or_default(),
1137        size: parse_decimal_string(tick.size.as_deref())?,
1138        exchange: tick.exchange.unwrap_or_default(),
1139        special_conditions: tick.special_conditions.unwrap_or_default(),
1140    })
1141}
1142
1143fn proto_tick_by_tick(
1144    tick: Option<protobuf::tick_by_tick_data::Tick>,
1145) -> TwsApiResult<Option<TickByTick>> {
1146    let Some(tick) = tick else {
1147        return Ok(None);
1148    };
1149
1150    let tick = match tick {
1151        protobuf::tick_by_tick_data::Tick::HistoricalTickLast(tick) => {
1152            TickByTick::Last(proto_historical_tick_last(tick)?)
1153        }
1154        protobuf::tick_by_tick_data::Tick::HistoricalTickBidAsk(tick) => {
1155            TickByTick::BidAsk(proto_historical_tick_bid_ask(tick)?)
1156        }
1157        protobuf::tick_by_tick_data::Tick::HistoricalTickMidPoint(tick) => {
1158            TickByTick::MidPoint(proto_historical_tick(tick)?)
1159        }
1160    };
1161    Ok(Some(tick))
1162}
1163
1164fn proto_historical_session(session: protobuf::HistoricalSession) -> HistoricalSession {
1165    HistoricalSession {
1166        start_date_time: session.start_date_time.unwrap_or_default(),
1167        end_date_time: session.end_date_time.unwrap_or_default(),
1168        ref_date: session.ref_date.unwrap_or_default(),
1169    }
1170}
1171
1172fn proto_smart_component(component: protobuf::SmartComponent) -> SmartComponent {
1173    SmartComponent {
1174        bit_number: component.bit_number.unwrap_or_default(),
1175        exchange: component.exchange.unwrap_or_default(),
1176        exchange_letter: component.exchange_letter.unwrap_or_default(),
1177    }
1178}
1179
1180fn proto_contract_description(description: protobuf::ContractDescription) -> ContractDescription {
1181    ContractDescription {
1182        contract: proto_contract_to_contract(description.contract),
1183        derivative_sec_types: description.derivative_sec_types,
1184    }
1185}
1186
1187fn proto_execution_to_execution(execution: Option<protobuf::Execution>) -> TwsApiResult<Execution> {
1188    let Some(execution) = execution else {
1189        return Ok(Execution::default());
1190    };
1191
1192    Ok(Execution {
1193        order_id: execution.order_id.unwrap_or_default(),
1194        exec_id: execution.exec_id.unwrap_or_default(),
1195        time: execution.time.unwrap_or_default(),
1196        acct_number: execution.acct_number.unwrap_or_default(),
1197        exchange: execution.exchange.unwrap_or_default(),
1198        side: execution.side.unwrap_or_default(),
1199        shares: parse_decimal_string(execution.shares.as_deref())?,
1200        price: execution.price.unwrap_or_default(),
1201        perm_id: execution.perm_id.unwrap_or_default(),
1202        client_id: execution.client_id.unwrap_or_default(),
1203        liquidation: i32::from(execution.is_liquidation.unwrap_or_default()),
1204        cum_qty: parse_decimal_string(execution.cum_qty.as_deref())?,
1205        avg_price: execution.avg_price.unwrap_or_default(),
1206        order_ref: execution.order_ref.unwrap_or_default(),
1207        ev_rule: execution.ev_rule.unwrap_or_default(),
1208        ev_multiplier: execution.ev_multiplier.unwrap_or_default(),
1209        model_code: execution.model_code.unwrap_or_default(),
1210        last_liquidity: execution.last_liquidity.unwrap_or_default(),
1211        pending_price_revision: execution.is_price_revision_pending.unwrap_or_default(),
1212        submitter: execution.submitter.unwrap_or_default(),
1213        opt_exercise_or_lapse_type: execution.opt_exercise_or_lapse_type.unwrap_or_default(),
1214    })
1215}
1216
1217fn proto_contract_details_to_contract_details(
1218    contract: Option<protobuf::Contract>,
1219    details: Option<protobuf::ContractDetails>,
1220) -> TwsApiResult<ContractDetails> {
1221    let Some(details) = details else {
1222        return Ok(ContractDetails {
1223            contract: proto_contract_to_contract(contract),
1224            ..ContractDetails::default()
1225        });
1226    };
1227
1228    let mut sec_id_list = details
1229        .sec_id_list
1230        .into_iter()
1231        .map(|(tag, value)| TagValue { tag, value })
1232        .collect::<Vec<_>>();
1233    sec_id_list.sort_by(|left, right| left.tag.cmp(&right.tag));
1234
1235    Ok(ContractDetails {
1236        contract: proto_contract_to_contract(contract),
1237        market_name: details.market_name.unwrap_or_default(),
1238        min_tick: details
1239            .min_tick
1240            .as_deref()
1241            .and_then(|value| value.parse::<f64>().ok())
1242            .unwrap_or_default(),
1243        order_types: details.order_types.unwrap_or_default(),
1244        valid_exchanges: details.valid_exchanges.unwrap_or_default(),
1245        price_magnifier: details.price_magnifier.unwrap_or_default(),
1246        under_con_id: details.under_con_id.unwrap_or_default(),
1247        long_name: details.long_name.unwrap_or_default(),
1248        contract_month: details.contract_month.unwrap_or_default(),
1249        industry: details.industry.unwrap_or_default(),
1250        category: details.category.unwrap_or_default(),
1251        subcategory: details.subcategory.unwrap_or_default(),
1252        time_zone_id: details.time_zone_id.unwrap_or_default(),
1253        trading_hours: details.trading_hours.unwrap_or_default(),
1254        liquid_hours: details.liquid_hours.unwrap_or_default(),
1255        ev_rule: details.ev_rule.unwrap_or_default(),
1256        ev_multiplier: details.ev_multiplier.unwrap_or_default(),
1257        sec_id_list,
1258        aggregate_group: details.agg_group.unwrap_or_default(),
1259        under_symbol: details.under_symbol.unwrap_or_default(),
1260        under_sec_type: details.under_sec_type.unwrap_or_default(),
1261        market_rule_ids: details.market_rule_ids.unwrap_or_default(),
1262        cusip: details.cusip.unwrap_or_default(),
1263        issue_date: details.issue_date.unwrap_or_default(),
1264        ratings: details.ratings.unwrap_or_default(),
1265        bond_type: details.bond_type.unwrap_or_default(),
1266        coupon: details.coupon.unwrap_or_default(),
1267        coupon_type: details.coupon_type.unwrap_or_default(),
1268        convertible: details.convertible.unwrap_or_default(),
1269        callable: details.callable.unwrap_or_default(),
1270        puttable: details.puttable.unwrap_or_default(),
1271        desc_append: details.desc_append.unwrap_or_default(),
1272        next_option_date: details.next_option_date.unwrap_or_default(),
1273        next_option_type: details.next_option_type.unwrap_or_default(),
1274        next_option_partial: details.next_option_partial.unwrap_or_default(),
1275        bond_notes: details.bond_notes.unwrap_or_default(),
1276        real_expiration_date: details.real_expiration_date.unwrap_or_default(),
1277        stock_type: details.stock_type.unwrap_or_default(),
1278        min_size: parse_decimal_string(details.min_size.as_deref())?,
1279        size_increment: parse_decimal_string(details.size_increment.as_deref())?,
1280        suggested_size_increment: parse_decimal_string(
1281            details.suggested_size_increment.as_deref(),
1282        )?,
1283        fund_name: details.fund_name.unwrap_or_default(),
1284        fund_family: details.fund_family.unwrap_or_default(),
1285        fund_type: details.fund_type.unwrap_or_default(),
1286        fund_front_load: details.fund_front_load.unwrap_or_default(),
1287        fund_back_load: details.fund_back_load.unwrap_or_default(),
1288        fund_back_load_time_interval: details.fund_back_load_time_interval.unwrap_or_default(),
1289        fund_management_fee: details.fund_management_fee.unwrap_or_default(),
1290        fund_closed: details.fund_closed.unwrap_or_default(),
1291        fund_closed_for_new_investors: details.fund_closed_for_new_investors.unwrap_or_default(),
1292        fund_closed_for_new_money: details.fund_closed_for_new_money.unwrap_or_default(),
1293        fund_notify_amount: details.fund_notify_amount.unwrap_or_default(),
1294        fund_minimum_initial_purchase: details.fund_minimum_initial_purchase.unwrap_or_default(),
1295        fund_minimum_subsequent_purchase: details
1296            .fund_minimum_subsequent_purchase
1297            .unwrap_or_default(),
1298        fund_blue_sky_states: details.fund_blue_sky_states.unwrap_or_default(),
1299        fund_blue_sky_territories: details.fund_blue_sky_territories.unwrap_or_default(),
1300        fund_distribution_policy_indicator: details
1301            .fund_distribution_policy_indicator
1302            .unwrap_or_default(),
1303        fund_asset_type: details.fund_asset_type.unwrap_or_default(),
1304        ineligibility_reason_list: details
1305            .ineligibility_reason_list
1306            .into_iter()
1307            .map(|reason| IneligibilityReason {
1308                id: reason.id.unwrap_or_default(),
1309                description: reason.description.unwrap_or_default(),
1310            })
1311            .collect(),
1312        event_contract1: details.event_contract1.unwrap_or_default(),
1313        event_contract_description1: details.event_contract_description1.unwrap_or_default(),
1314        event_contract_description2: details.event_contract_description2.unwrap_or_default(),
1315        min_algo_size: parse_decimal_string(details.min_algo_size.as_deref())?,
1316        last_price_precision: parse_decimal_string(details.last_price_precision.as_deref())?,
1317        last_size_precision: parse_decimal_string(details.last_size_precision.as_deref())?,
1318    })
1319}
1320
1321fn proto_contract_to_contract(contract: Option<protobuf::Contract>) -> Contract {
1322    let Some(contract) = contract else {
1323        return Contract::default();
1324    };
1325
1326    Contract {
1327        con_id: contract.con_id.unwrap_or_default(),
1328        symbol: contract.symbol.unwrap_or_default(),
1329        sec_type: contract.sec_type.unwrap_or_default(),
1330        last_trade_date_or_contract_month: contract
1331            .last_trade_date_or_contract_month
1332            .unwrap_or_default(),
1333        last_trade_date: contract.last_trade_date.unwrap_or_default(),
1334        strike: contract.strike.unwrap_or_default(),
1335        right: contract.right.unwrap_or_default(),
1336        multiplier: contract
1337            .multiplier
1338            .map(|value| value.to_string())
1339            .unwrap_or_default(),
1340        exchange: contract.exchange.unwrap_or_default(),
1341        primary_exchange: contract.primary_exch.unwrap_or_default(),
1342        currency: contract.currency.unwrap_or_default(),
1343        local_symbol: contract.local_symbol.unwrap_or_default(),
1344        trading_class: contract.trading_class.unwrap_or_default(),
1345        include_expired: contract.include_expired.unwrap_or_default(),
1346        sec_id_type: contract.sec_id_type.unwrap_or_default(),
1347        sec_id: contract.sec_id.unwrap_or_default(),
1348        description: contract.description.unwrap_or_default(),
1349        issuer_id: contract.issuer_id.unwrap_or_default(),
1350        combo_legs_description: contract.combo_legs_descrip.unwrap_or_default(),
1351        combo_legs: contract
1352            .combo_legs
1353            .into_iter()
1354            .map(proto_combo_leg)
1355            .collect(),
1356        delta_neutral_contract: contract
1357            .delta_neutral_contract
1358            .map(|delta| DeltaNeutralContract {
1359                con_id: delta.con_id.unwrap_or_default(),
1360                delta: delta.delta.unwrap_or_default(),
1361                price: delta.price.unwrap_or_default(),
1362            }),
1363    }
1364}
1365
1366fn proto_combo_leg(leg: protobuf::ComboLeg) -> ComboLeg {
1367    ComboLeg {
1368        con_id: leg.con_id.unwrap_or_default(),
1369        ratio: leg.ratio.unwrap_or_default(),
1370        action: leg.action.unwrap_or_default(),
1371        exchange: leg.exchange.unwrap_or_default(),
1372        open_close: match leg.open_close.unwrap_or_default() {
1373            1 => LegOpenClose::OpenPosition,
1374            2 => LegOpenClose::ClosePosition,
1375            3 => LegOpenClose::Unknown,
1376            _ => LegOpenClose::SamePosition,
1377        },
1378        short_sale_slot: leg.short_sales_slot.unwrap_or_default(),
1379        designated_location: leg.designated_location.unwrap_or_default(),
1380        exempt_code: leg.exempt_code.unwrap_or(-1),
1381    }
1382}
1383
1384fn split_message_id(raw: bool, payload: &[u8]) -> TwsApiResult<(i32, &[u8])> {
1385    if raw {
1386        let (prefix, body) = payload
1387            .split_at_checked(4)
1388            .ok_or(TwsApiError::IncompleteFrame {
1389                needed: 4,
1390                available: payload.len(),
1391            })?;
1392        let prefix: [u8; 4] = prefix
1393            .try_into()
1394            .map_err(|_| TwsApiError::IncompleteFrame {
1395                needed: 4,
1396                available: payload.len(),
1397            })?;
1398        return Ok((i32::from_be_bytes(prefix), body));
1399    }
1400
1401    let nul = payload
1402        .iter()
1403        .position(|byte| *byte == 0)
1404        .ok_or(TwsApiError::MalformedHandshake)?;
1405    let (id, rest) = payload.split_at(nul);
1406    let rest = rest.get(1..).ok_or(TwsApiError::IncompleteFrame {
1407        needed: nul + 1,
1408        available: payload.len(),
1409    })?;
1410    let id = String::from_utf8_lossy(id).into_owned();
1411    let msg_id = id
1412        .parse::<i32>()
1413        .map_err(|source| TwsApiError::InvalidInteger { field: id, source })?;
1414    Ok((msg_id, rest))
1415}
1416
1417fn decode_portfolio_value_fields(fields: &[String]) -> TwsApiResult<Event> {
1418    let version = parse_i32(fields.first())?;
1419    let mut index = 1;
1420    let mut contract = Contract {
1421        con_id: next_i32(fields, &mut index)?,
1422        symbol: next_string(fields, &mut index),
1423        sec_type: next_string(fields, &mut index),
1424        last_trade_date_or_contract_month: next_string(fields, &mut index),
1425        strike: next_f64(fields, &mut index)?,
1426        right: next_string(fields, &mut index),
1427        ..Contract::default()
1428    };
1429
1430    if version >= 7 {
1431        contract.multiplier = next_string(fields, &mut index);
1432        contract.primary_exchange = next_string(fields, &mut index);
1433    }
1434
1435    contract.currency = next_string(fields, &mut index);
1436    contract.local_symbol = next_string(fields, &mut index);
1437    if version >= 8 {
1438        contract.trading_class = next_string(fields, &mut index);
1439    }
1440
1441    Ok(Event::PortfolioValue {
1442        contract: Box::new(contract),
1443        position: next_decimal(fields, &mut index)?,
1444        market_price: next_f64(fields, &mut index)?,
1445        market_value: next_f64(fields, &mut index)?,
1446        average_cost: next_f64(fields, &mut index)?,
1447        unrealized_pnl: next_f64(fields, &mut index)?,
1448        realized_pnl: next_f64(fields, &mut index)?,
1449        account_name: next_string(fields, &mut index),
1450    })
1451}
1452
1453fn decode_market_depth_fields(fields: &[String], is_l2: bool) -> TwsApiResult<Event> {
1454    let mut index = 1;
1455    let req_id = next_i32(fields, &mut index)?;
1456    let position = next_i32(fields, &mut index)?;
1457    let market_maker = if is_l2 {
1458        next_string(fields, &mut index)
1459    } else {
1460        String::new()
1461    };
1462    let operation = next_i32(fields, &mut index)?;
1463    let side = next_i32(fields, &mut index)?;
1464    let price = next_f64(fields, &mut index)?;
1465    let size = next_decimal(fields, &mut index)?;
1466    let is_smart_depth = is_l2 && parse_bool(fields.get(index));
1467
1468    Ok(Event::MarketDepth {
1469        req_id,
1470        position,
1471        operation,
1472        side,
1473        price,
1474        size,
1475        market_maker,
1476        is_smart_depth,
1477    })
1478}
1479
1480fn decode_tick_option_computation_fields(fields: &[String]) -> TwsApiResult<Event> {
1481    let has_version = fields.len() > 11;
1482    let mut index = usize::from(has_version);
1483    let req_id = next_i32(fields, &mut index)?;
1484    let tick_type = next_i32(fields, &mut index)?;
1485    let tick_attrib = if has_version && fields.len() == 10 {
1486        0
1487    } else {
1488        next_i32(fields, &mut index).unwrap_or_default()
1489    };
1490
1491    Ok(Event::TickOptionComputation {
1492        req_id,
1493        tick_type,
1494        tick_attrib,
1495        implied_vol: next_f64(fields, &mut index)?,
1496        delta: next_f64(fields, &mut index)?,
1497        opt_price: if index < fields.len() {
1498            next_f64(fields, &mut index)?
1499        } else {
1500            0.0
1501        },
1502        pv_dividend: if index < fields.len() {
1503            next_f64(fields, &mut index)?
1504        } else {
1505            0.0
1506        },
1507        gamma: if index < fields.len() {
1508            next_f64(fields, &mut index)?
1509        } else {
1510            0.0
1511        },
1512        vega: if index < fields.len() {
1513            next_f64(fields, &mut index)?
1514        } else {
1515            0.0
1516        },
1517        theta: if index < fields.len() {
1518            next_f64(fields, &mut index)?
1519        } else {
1520            0.0
1521        },
1522        und_price: if index < fields.len() {
1523            next_f64(fields, &mut index)?
1524        } else {
1525            0.0
1526        },
1527    })
1528}
1529
1530fn decode_scanner_data_fields(fields: &[String]) -> TwsApiResult<Event> {
1531    let mut index = 1;
1532    let req_id = next_i32(fields, &mut index)?;
1533    let row_count = next_i32(fields, &mut index)?.max(0) as usize;
1534    let mut rows = Vec::with_capacity(row_count);
1535
1536    for _ in 0..row_count {
1537        let rank = next_i32(fields, &mut index)?;
1538        let contract = Contract {
1539            con_id: next_i32(fields, &mut index)?,
1540            symbol: next_string(fields, &mut index),
1541            sec_type: next_string(fields, &mut index),
1542            last_trade_date_or_contract_month: next_string(fields, &mut index),
1543            strike: next_f64(fields, &mut index)?,
1544            right: next_string(fields, &mut index),
1545            exchange: next_string(fields, &mut index),
1546            currency: next_string(fields, &mut index),
1547            local_symbol: next_string(fields, &mut index),
1548            ..Contract::default()
1549        };
1550        let market_name = next_string(fields, &mut index);
1551        let mut contract = contract;
1552        contract.trading_class = next_string(fields, &mut index);
1553        rows.push(ScannerDataRow {
1554            rank,
1555            contract: Box::new(contract),
1556            market_name,
1557            distance: next_string(fields, &mut index),
1558            benchmark: next_string(fields, &mut index),
1559            projection: next_string(fields, &mut index),
1560            combo_key: next_string(fields, &mut index),
1561        });
1562    }
1563
1564    Ok(Event::ScannerData { req_id, rows })
1565}
1566
1567fn decode_soft_dollar_tiers_fields(fields: &[String]) -> TwsApiResult<Event> {
1568    let mut index = 0;
1569    let req_id = next_i32(fields, &mut index)?;
1570    let count = next_i32(fields, &mut index)?.max(0) as usize;
1571    let mut tiers = Vec::with_capacity(count);
1572    for _ in 0..count {
1573        tiers.push(SoftDollarTier {
1574            name: next_string(fields, &mut index),
1575            value: next_string(fields, &mut index),
1576            display_name: next_string(fields, &mut index),
1577        });
1578    }
1579    Ok(Event::SoftDollarTiers { req_id, tiers })
1580}
1581
1582fn decode_family_codes_fields(fields: &[String]) -> TwsApiResult<Event> {
1583    let mut index = 0;
1584    let count = next_i32(fields, &mut index)?.max(0) as usize;
1585    let mut family_codes = Vec::with_capacity(count);
1586    for _ in 0..count {
1587        family_codes.push(FamilyCode {
1588            account_id: next_string(fields, &mut index),
1589            family_code: next_string(fields, &mut index),
1590        });
1591    }
1592    Ok(Event::FamilyCodes { family_codes })
1593}
1594
1595fn decode_symbol_samples_fields(fields: &[String]) -> TwsApiResult<Event> {
1596    let mut index = 0;
1597    let req_id = next_i32(fields, &mut index)?;
1598    let count = next_i32(fields, &mut index)?.max(0) as usize;
1599    let mut descriptions = Vec::with_capacity(count);
1600    for _ in 0..count {
1601        let mut contract = Contract {
1602            con_id: next_i32(fields, &mut index)?,
1603            symbol: next_string(fields, &mut index),
1604            sec_type: next_string(fields, &mut index),
1605            primary_exchange: next_string(fields, &mut index),
1606            currency: next_string(fields, &mut index),
1607            ..Contract::default()
1608        };
1609        let derivative_count = next_i32(fields, &mut index)?.max(0) as usize;
1610        let mut derivative_sec_types = Vec::with_capacity(derivative_count);
1611        for _ in 0..derivative_count {
1612            derivative_sec_types.push(next_string(fields, &mut index));
1613        }
1614        if index + 1 < fields.len() {
1615            contract.description = next_string(fields, &mut index);
1616            contract.issuer_id = next_string(fields, &mut index);
1617        }
1618        descriptions.push(ContractDescription {
1619            contract,
1620            derivative_sec_types,
1621        });
1622    }
1623    Ok(Event::SymbolSamples {
1624        req_id,
1625        descriptions,
1626    })
1627}
1628
1629fn decode_smart_components_fields(fields: &[String]) -> TwsApiResult<Event> {
1630    let mut index = 0;
1631    let req_id = next_i32(fields, &mut index)?;
1632    let count = next_i32(fields, &mut index)?.max(0) as usize;
1633    let mut components = Vec::with_capacity(count);
1634    for _ in 0..count {
1635        components.push(SmartComponent {
1636            bit_number: next_i32(fields, &mut index)?,
1637            exchange: next_string(fields, &mut index),
1638            exchange_letter: next_string(fields, &mut index),
1639        });
1640    }
1641    Ok(Event::SmartComponents { req_id, components })
1642}
1643
1644fn decode_market_depth_exchanges_fields(fields: &[String]) -> TwsApiResult<Event> {
1645    let mut index = 0;
1646    let count = next_i32(fields, &mut index)?.max(0) as usize;
1647    let mut descriptions = Vec::with_capacity(count);
1648    for _ in 0..count {
1649        descriptions.push(DepthMarketDataDescription {
1650            exchange: next_string(fields, &mut index),
1651            security_type: next_string(fields, &mut index),
1652            listing_exchange: next_string(fields, &mut index),
1653            service_data_type: next_string(fields, &mut index),
1654            aggregate_group: next_i32(fields, &mut index).unwrap_or_default(),
1655        });
1656    }
1657    Ok(Event::MarketDepthExchanges { descriptions })
1658}
1659
1660fn decode_histogram_data_fields(fields: &[String]) -> TwsApiResult<Event> {
1661    let mut index = 0;
1662    let req_id = next_i32(fields, &mut index)?;
1663    let count = next_i32(fields, &mut index)?.max(0) as usize;
1664    let mut items = Vec::with_capacity(count);
1665    for _ in 0..count {
1666        items.push(HistogramEntry {
1667            price: next_f64(fields, &mut index)?,
1668            size: next_decimal(fields, &mut index)?,
1669        });
1670    }
1671    Ok(Event::HistogramData { req_id, items })
1672}
1673
1674fn decode_market_rule_fields(fields: &[String]) -> TwsApiResult<Event> {
1675    let mut index = 0;
1676    let market_rule_id = next_i32(fields, &mut index)?;
1677    let count = next_i32(fields, &mut index)?.max(0) as usize;
1678    let mut price_increments = Vec::with_capacity(count);
1679    for _ in 0..count {
1680        price_increments.push(PriceIncrement {
1681            low_edge: next_f64(fields, &mut index)?,
1682            increment: next_f64(fields, &mut index)?,
1683        });
1684    }
1685    Ok(Event::MarketRule {
1686        market_rule_id,
1687        price_increments,
1688    })
1689}
1690
1691fn decode_pnl_fields(fields: &[String]) -> TwsApiResult<Event> {
1692    let mut index = 0;
1693    Ok(Event::Pnl {
1694        req_id: next_i32(fields, &mut index)?,
1695        daily_pnl: next_f64(fields, &mut index)?,
1696        unrealized_pnl: if index < fields.len() {
1697            next_f64(fields, &mut index)?
1698        } else {
1699            0.0
1700        },
1701        realized_pnl: if index < fields.len() {
1702            next_f64(fields, &mut index)?
1703        } else {
1704            0.0
1705        },
1706    })
1707}
1708
1709fn decode_pnl_single_fields(fields: &[String]) -> TwsApiResult<Event> {
1710    let mut index = 0;
1711    let req_id = next_i32(fields, &mut index)?;
1712    let position = next_decimal(fields, &mut index)?;
1713    let daily_pnl = next_f64(fields, &mut index)?;
1714    let remaining = fields.len().saturating_sub(index);
1715    let unrealized_pnl = if remaining >= 3 {
1716        next_f64(fields, &mut index)?
1717    } else {
1718        0.0
1719    };
1720    let realized_pnl = if remaining >= 3 {
1721        next_f64(fields, &mut index)?
1722    } else {
1723        0.0
1724    };
1725    let value = if index < fields.len() {
1726        next_f64(fields, &mut index)?
1727    } else {
1728        0.0
1729    };
1730
1731    Ok(Event::PnlSingle {
1732        req_id,
1733        position,
1734        daily_pnl,
1735        unrealized_pnl,
1736        realized_pnl,
1737        value,
1738    })
1739}
1740
1741fn decode_news_providers_fields(fields: &[String]) -> TwsApiResult<Event> {
1742    let mut index = 0;
1743    let count = next_i32(fields, &mut index)?.max(0) as usize;
1744    let mut providers = Vec::with_capacity(count);
1745    for _ in 0..count {
1746        providers.push(NewsProvider {
1747            code: next_string(fields, &mut index),
1748            name: next_string(fields, &mut index),
1749        });
1750    }
1751    Ok(Event::NewsProviders { providers })
1752}
1753
1754fn decode_historical_schedule_fields(fields: &[String]) -> TwsApiResult<Event> {
1755    let mut index = 0;
1756    let req_id = next_i32(fields, &mut index)?;
1757    let start_date_time = next_string(fields, &mut index);
1758    let end_date_time = next_string(fields, &mut index);
1759    let time_zone = next_string(fields, &mut index);
1760    let count = next_i32(fields, &mut index)?.max(0) as usize;
1761    let mut sessions = Vec::with_capacity(count);
1762    for _ in 0..count {
1763        sessions.push(HistoricalSession {
1764            start_date_time: next_string(fields, &mut index),
1765            end_date_time: next_string(fields, &mut index),
1766            ref_date: next_string(fields, &mut index),
1767        });
1768    }
1769    Ok(Event::HistoricalSchedule {
1770        req_id,
1771        start_date_time,
1772        end_date_time,
1773        time_zone,
1774        sessions,
1775    })
1776}
1777
1778fn decode_execution_data_fields(fields: &[String]) -> TwsApiResult<Event> {
1779    let has_version = fields
1780        .get(3)
1781        .is_some_and(|field| field.parse::<i32>().is_ok());
1782    let mut index = 0;
1783    let version = if has_version {
1784        next_i32(fields, &mut index)?
1785    } else {
1786        i32::MAX
1787    };
1788    let req_id = if version >= 7 {
1789        next_i32(fields, &mut index)?
1790    } else {
1791        -1
1792    };
1793    let order_id = next_i32(fields, &mut index)?;
1794
1795    let mut contract = Contract {
1796        con_id: next_i32(fields, &mut index)?,
1797        symbol: next_string(fields, &mut index),
1798        sec_type: next_string(fields, &mut index),
1799        last_trade_date_or_contract_month: next_string(fields, &mut index),
1800        strike: next_f64(fields, &mut index)?,
1801        right: next_string(fields, &mut index),
1802        ..Contract::default()
1803    };
1804    if version >= 9 {
1805        contract.multiplier = next_string(fields, &mut index);
1806    }
1807    contract.exchange = next_string(fields, &mut index);
1808    contract.currency = next_string(fields, &mut index);
1809    contract.local_symbol = next_string(fields, &mut index);
1810    if version >= 10 {
1811        contract.trading_class = next_string(fields, &mut index);
1812    }
1813
1814    let mut execution = Execution {
1815        order_id,
1816        exec_id: next_string(fields, &mut index),
1817        time: next_string(fields, &mut index),
1818        acct_number: next_string(fields, &mut index),
1819        exchange: next_string(fields, &mut index),
1820        side: next_string(fields, &mut index),
1821        shares: next_decimal(fields, &mut index)?,
1822        price: next_f64(fields, &mut index)?,
1823        perm_id: i64::from(next_i32(fields, &mut index)?),
1824        client_id: next_i32(fields, &mut index)?,
1825        liquidation: next_i32(fields, &mut index)?,
1826        ..Execution::default()
1827    };
1828
1829    if version >= 6 {
1830        execution.cum_qty = next_decimal(fields, &mut index)?;
1831        execution.avg_price = next_f64(fields, &mut index)?;
1832    }
1833    if version >= 8 {
1834        execution.order_ref = next_string(fields, &mut index);
1835    }
1836    if version >= 9 {
1837        execution.ev_rule = next_string(fields, &mut index);
1838        execution.ev_multiplier = next_f64(fields, &mut index)?;
1839    }
1840    if index < fields.len() {
1841        execution.model_code = next_string(fields, &mut index);
1842    }
1843    if index < fields.len() {
1844        execution.last_liquidity = next_i32(fields, &mut index)?;
1845    }
1846    if index < fields.len() {
1847        execution.pending_price_revision = parse_bool(fields.get(index));
1848        index += 1;
1849    }
1850    if index < fields.len() {
1851        execution.submitter = next_string(fields, &mut index);
1852    }
1853
1854    Ok(Event::ExecutionDetails {
1855        req_id,
1856        contract: Box::new(contract),
1857        execution,
1858    })
1859}
1860
1861fn decode_contract_data_fields(fields: &[String]) -> TwsApiResult<Event> {
1862    let has_version = fields
1863        .get(1)
1864        .is_some_and(|field| field.parse::<i32>().is_ok());
1865    let mut index = 0;
1866    let version = if has_version {
1867        next_i32(fields, &mut index)?
1868    } else {
1869        8
1870    };
1871    let req_id = if version >= 3 {
1872        next_i32(fields, &mut index)?
1873    } else {
1874        -1
1875    };
1876
1877    let mut details = ContractDetails::default();
1878    details.contract.symbol = next_string(fields, &mut index);
1879    details.contract.sec_type = next_string(fields, &mut index);
1880    details.contract.last_trade_date_or_contract_month = next_string(fields, &mut index);
1881
1882    if !has_version
1883        || fields
1884            .get(index)
1885            .is_none_or(|field| field.parse::<f64>().is_err())
1886    {
1887        details.contract.last_trade_date = next_string(fields, &mut index);
1888    }
1889
1890    details.contract.strike = next_f64(fields, &mut index)?;
1891    details.contract.right = next_string(fields, &mut index);
1892    details.contract.exchange = next_string(fields, &mut index);
1893    details.contract.currency = next_string(fields, &mut index);
1894    details.contract.local_symbol = next_string(fields, &mut index);
1895    details.market_name = next_string(fields, &mut index);
1896    details.contract.trading_class = next_string(fields, &mut index);
1897    details.contract.con_id = next_i32(fields, &mut index)?;
1898    details.min_tick = next_f64(fields, &mut index)?;
1899    details.contract.multiplier = next_string(fields, &mut index);
1900    details.order_types = next_string(fields, &mut index);
1901    details.valid_exchanges = next_string(fields, &mut index);
1902    details.price_magnifier = next_i32(fields, &mut index)?;
1903
1904    if version >= 4 && index < fields.len() {
1905        details.under_con_id = next_i32(fields, &mut index).unwrap_or_default();
1906    }
1907    if version >= 5 && index + 1 < fields.len() {
1908        details.long_name = next_string(fields, &mut index);
1909        details.contract.primary_exchange = next_string(fields, &mut index);
1910    }
1911    if version >= 6 && index + 6 < fields.len() {
1912        details.contract_month = next_string(fields, &mut index);
1913        details.industry = next_string(fields, &mut index);
1914        details.category = next_string(fields, &mut index);
1915        details.subcategory = next_string(fields, &mut index);
1916        details.time_zone_id = next_string(fields, &mut index);
1917        details.trading_hours = next_string(fields, &mut index);
1918        details.liquid_hours = next_string(fields, &mut index);
1919    }
1920    if version >= 8 && index + 1 < fields.len() {
1921        details.ev_rule = next_string(fields, &mut index);
1922        details.ev_multiplier = next_f64(fields, &mut index).unwrap_or_default();
1923    }
1924    if version >= 7 && index < fields.len() {
1925        let sec_id_count = next_i32(fields, &mut index).unwrap_or_default().max(0) as usize;
1926        for _ in 0..sec_id_count {
1927            details.sec_id_list.push(TagValue {
1928                tag: next_string(fields, &mut index),
1929                value: next_string(fields, &mut index),
1930            });
1931        }
1932    }
1933    if index < fields.len() {
1934        details.aggregate_group = next_i32(fields, &mut index).unwrap_or_default();
1935    }
1936    if index + 1 < fields.len() {
1937        details.under_symbol = next_string(fields, &mut index);
1938        details.under_sec_type = next_string(fields, &mut index);
1939    }
1940    if index < fields.len() {
1941        details.market_rule_ids = next_string(fields, &mut index);
1942    }
1943
1944    if index < fields.len() {
1945        details.real_expiration_date = next_string(fields, &mut index);
1946    }
1947    if index < fields.len() {
1948        details.stock_type = next_string(fields, &mut index);
1949    }
1950    if index < fields.len() {
1951        details.min_size = next_decimal(fields, &mut index).unwrap_or_default();
1952    }
1953    if index < fields.len() {
1954        details.size_increment = next_decimal(fields, &mut index).unwrap_or_default();
1955    }
1956    if index < fields.len() {
1957        details.suggested_size_increment = next_decimal(fields, &mut index).unwrap_or_default();
1958    }
1959
1960    if details.contract.sec_type == "FUND" && index + 16 < fields.len() {
1961        details.fund_name = next_string(fields, &mut index);
1962        details.fund_family = next_string(fields, &mut index);
1963        details.fund_type = next_string(fields, &mut index);
1964        details.fund_front_load = next_string(fields, &mut index);
1965        details.fund_back_load = next_string(fields, &mut index);
1966        details.fund_back_load_time_interval = next_string(fields, &mut index);
1967        details.fund_management_fee = next_string(fields, &mut index);
1968        details.fund_closed = next_bool(fields, &mut index);
1969        details.fund_closed_for_new_investors = next_bool(fields, &mut index);
1970        details.fund_closed_for_new_money = next_bool(fields, &mut index);
1971        details.fund_notify_amount = next_string(fields, &mut index);
1972        details.fund_minimum_initial_purchase = next_string(fields, &mut index);
1973        details.fund_minimum_subsequent_purchase = next_string(fields, &mut index);
1974        details.fund_blue_sky_states = next_string(fields, &mut index);
1975        details.fund_blue_sky_territories = next_string(fields, &mut index);
1976        details.fund_distribution_policy_indicator = next_string(fields, &mut index);
1977        details.fund_asset_type = next_string(fields, &mut index);
1978    }
1979
1980    if index < fields.len() {
1981        let count = next_i32(fields, &mut index).unwrap_or_default().max(0) as usize;
1982        for _ in 0..count {
1983            if index + 1 >= fields.len() {
1984                break;
1985            }
1986            details.ineligibility_reason_list.push(IneligibilityReason {
1987                id: next_string(fields, &mut index),
1988                description: next_string(fields, &mut index),
1989            });
1990        }
1991    }
1992
1993    Ok(Event::ContractDetails {
1994        req_id,
1995        details: Box::new(details),
1996    })
1997}
1998
1999fn decode_bond_contract_data_fields(fields: &[String]) -> TwsApiResult<Event> {
2000    let has_version = fields
2001        .get(1)
2002        .is_some_and(|field| field.parse::<i32>().is_ok());
2003    let mut index = 0;
2004    let version = if has_version {
2005        next_i32(fields, &mut index)?
2006    } else {
2007        6
2008    };
2009    let req_id = if version >= 3 {
2010        next_i32(fields, &mut index)?
2011    } else {
2012        -1
2013    };
2014
2015    let mut details = ContractDetails::default();
2016    details.contract.symbol = next_string(fields, &mut index);
2017    details.contract.sec_type = next_string(fields, &mut index);
2018    details.cusip = next_string(fields, &mut index);
2019    details.coupon = next_f64(fields, &mut index)?;
2020    details.contract.last_trade_date_or_contract_month = next_string(fields, &mut index);
2021    details.issue_date = next_string(fields, &mut index);
2022    details.ratings = next_string(fields, &mut index);
2023    details.bond_type = next_string(fields, &mut index);
2024    details.coupon_type = next_string(fields, &mut index);
2025    details.convertible = next_bool(fields, &mut index);
2026    details.callable = next_bool(fields, &mut index);
2027    details.puttable = next_bool(fields, &mut index);
2028    details.desc_append = next_string(fields, &mut index);
2029    details.contract.exchange = next_string(fields, &mut index);
2030    details.contract.currency = next_string(fields, &mut index);
2031    details.market_name = next_string(fields, &mut index);
2032    details.contract.trading_class = next_string(fields, &mut index);
2033    details.contract.con_id = next_i32(fields, &mut index)?;
2034    details.min_tick = next_f64(fields, &mut index)?;
2035    details.order_types = next_string(fields, &mut index);
2036    details.valid_exchanges = next_string(fields, &mut index);
2037    details.next_option_date = next_string(fields, &mut index);
2038    details.next_option_type = next_string(fields, &mut index);
2039    details.next_option_partial = next_bool(fields, &mut index);
2040    details.bond_notes = next_string(fields, &mut index);
2041
2042    if version >= 4 && index < fields.len() {
2043        details.long_name = next_string(fields, &mut index);
2044    }
2045    if index + 2 < fields.len() {
2046        details.time_zone_id = next_string(fields, &mut index);
2047        details.trading_hours = next_string(fields, &mut index);
2048        details.liquid_hours = next_string(fields, &mut index);
2049    }
2050    if version >= 6 && index + 1 < fields.len() {
2051        details.ev_rule = next_string(fields, &mut index);
2052        details.ev_multiplier = next_f64(fields, &mut index).unwrap_or_default();
2053    }
2054    if version >= 5 && index < fields.len() {
2055        let sec_id_count = next_i32(fields, &mut index).unwrap_or_default().max(0) as usize;
2056        for _ in 0..sec_id_count {
2057            details.sec_id_list.push(TagValue {
2058                tag: next_string(fields, &mut index),
2059                value: next_string(fields, &mut index),
2060            });
2061        }
2062    }
2063    if index < fields.len() {
2064        details.aggregate_group = next_i32(fields, &mut index).unwrap_or_default();
2065    }
2066    if index < fields.len() {
2067        details.market_rule_ids = next_string(fields, &mut index);
2068    }
2069
2070    Ok(Event::ContractDetails {
2071        req_id,
2072        details: Box::new(details),
2073    })
2074}
2075
2076fn decode_historical_data_fields(fields: &[String]) -> TwsApiResult<Event> {
2077    let mut index = 0;
2078    let first = next_i32(fields, &mut index)?;
2079    let req_id = if fields
2080        .get(index)
2081        .and_then(|field| field.parse::<usize>().ok())
2082        .is_some_and(|count| fields.len() == index + 1 + count * 8)
2083    {
2084        first
2085    } else {
2086        next_i32(fields, &mut index)?
2087    };
2088
2089    let bar_count = next_i32(fields, &mut index)?.max(0) as usize;
2090    let mut bars = Vec::with_capacity(bar_count);
2091    for _ in 0..bar_count {
2092        bars.push(BarData {
2093            date: next_string(fields, &mut index),
2094            open: next_f64(fields, &mut index)?,
2095            high: next_f64(fields, &mut index)?,
2096            low: next_f64(fields, &mut index)?,
2097            close: next_f64(fields, &mut index)?,
2098            volume: next_decimal(fields, &mut index)?,
2099            wap: next_decimal(fields, &mut index)?,
2100            bar_count: next_i32(fields, &mut index)?,
2101        });
2102    }
2103
2104    Ok(Event::HistoricalDataBars { req_id, bars })
2105}
2106
2107fn decode_historical_data_update_fields(fields: &[String]) -> TwsApiResult<Event> {
2108    let mut index = 0;
2109    let req_id = next_i32(fields, &mut index)?;
2110    let bar_count = next_i32(fields, &mut index)?;
2111    let bar = BarData {
2112        date: next_string(fields, &mut index),
2113        open: next_f64(fields, &mut index)?,
2114        close: next_f64(fields, &mut index)?,
2115        high: next_f64(fields, &mut index)?,
2116        low: next_f64(fields, &mut index)?,
2117        wap: next_decimal(fields, &mut index)?,
2118        volume: next_decimal(fields, &mut index)?,
2119        bar_count,
2120    };
2121
2122    Ok(Event::HistoricalDataUpdate { req_id, bar })
2123}
2124
2125fn decode_historical_ticks_fields(fields: &[String]) -> TwsApiResult<Event> {
2126    let mut index = 0;
2127    let req_id = next_i32(fields, &mut index)?;
2128    let count = next_i32(fields, &mut index)?.max(0) as usize;
2129    let mut ticks = Vec::with_capacity(count);
2130    for _ in 0..count {
2131        let time = i64::from(next_i32(fields, &mut index)?);
2132        let _unused = next_string(fields, &mut index);
2133        ticks.push(HistoricalTick {
2134            time,
2135            price: next_f64(fields, &mut index)?,
2136            size: next_decimal(fields, &mut index)?,
2137        });
2138    }
2139    let done = next_bool(fields, &mut index);
2140    Ok(Event::HistoricalTicks {
2141        req_id,
2142        ticks,
2143        done,
2144    })
2145}
2146
2147fn decode_historical_ticks_bid_ask_fields(fields: &[String]) -> TwsApiResult<Event> {
2148    let mut index = 0;
2149    let req_id = next_i32(fields, &mut index)?;
2150    let count = next_i32(fields, &mut index)?.max(0) as usize;
2151    let mut ticks = Vec::with_capacity(count);
2152    for _ in 0..count {
2153        let time = i64::from(next_i32(fields, &mut index)?);
2154        let mask = next_i32(fields, &mut index)?;
2155        ticks.push(HistoricalTickBidAsk {
2156            time,
2157            tick_attrib_bid_ask: TickAttribBidAsk {
2158                ask_past_high: mask & 1 != 0,
2159                bid_past_low: mask & 2 != 0,
2160            },
2161            price_bid: next_f64(fields, &mut index)?,
2162            price_ask: next_f64(fields, &mut index)?,
2163            size_bid: next_decimal(fields, &mut index)?,
2164            size_ask: next_decimal(fields, &mut index)?,
2165        });
2166    }
2167    let done = next_bool(fields, &mut index);
2168    Ok(Event::HistoricalTicksBidAsk {
2169        req_id,
2170        ticks,
2171        done,
2172    })
2173}
2174
2175fn decode_historical_ticks_last_fields(fields: &[String]) -> TwsApiResult<Event> {
2176    let mut index = 0;
2177    let req_id = next_i32(fields, &mut index)?;
2178    let count = next_i32(fields, &mut index)?.max(0) as usize;
2179    let mut ticks = Vec::with_capacity(count);
2180    for _ in 0..count {
2181        let time = i64::from(next_i32(fields, &mut index)?);
2182        let mask = next_i32(fields, &mut index)?;
2183        ticks.push(HistoricalTickLast {
2184            time,
2185            tick_attrib_last: TickAttribLast {
2186                past_limit: mask & 1 != 0,
2187                unreported: mask & 2 != 0,
2188            },
2189            price: next_f64(fields, &mut index)?,
2190            size: next_decimal(fields, &mut index)?,
2191            exchange: next_string(fields, &mut index),
2192            special_conditions: next_string(fields, &mut index),
2193        });
2194    }
2195    let done = next_bool(fields, &mut index);
2196    Ok(Event::HistoricalTicksLast {
2197        req_id,
2198        ticks,
2199        done,
2200    })
2201}
2202
2203fn decode_tick_by_tick_fields(fields: &[String]) -> TwsApiResult<Event> {
2204    let mut index = 0;
2205    let req_id = next_i32(fields, &mut index)?;
2206    let tick_type = next_i32(fields, &mut index)?;
2207    let time = i64::from(next_i32(fields, &mut index)?);
2208    let tick = match tick_type {
2209        1 | 2 => {
2210            let price = next_f64(fields, &mut index)?;
2211            let size = next_decimal(fields, &mut index)?;
2212            let mask = next_i32(fields, &mut index)?;
2213            Some(TickByTick::Last(HistoricalTickLast {
2214                time,
2215                tick_attrib_last: TickAttribLast {
2216                    past_limit: mask & 1 != 0,
2217                    unreported: mask & 2 != 0,
2218                },
2219                price,
2220                size,
2221                exchange: next_string(fields, &mut index),
2222                special_conditions: next_string(fields, &mut index),
2223            }))
2224        }
2225        3 => {
2226            let price_bid = next_f64(fields, &mut index)?;
2227            let price_ask = next_f64(fields, &mut index)?;
2228            let size_bid = next_decimal(fields, &mut index)?;
2229            let size_ask = next_decimal(fields, &mut index)?;
2230            let mask = next_i32(fields, &mut index)?;
2231            Some(TickByTick::BidAsk(HistoricalTickBidAsk {
2232                time,
2233                tick_attrib_bid_ask: TickAttribBidAsk {
2234                    bid_past_low: mask & 1 != 0,
2235                    ask_past_high: mask & 2 != 0,
2236                },
2237                price_bid,
2238                price_ask,
2239                size_bid,
2240                size_ask,
2241            }))
2242        }
2243        4 => Some(TickByTick::MidPoint(HistoricalTick {
2244            time,
2245            price: next_f64(fields, &mut index)?,
2246            size: Decimal::default(),
2247        })),
2248        _ => None,
2249    };
2250
2251    Ok(Event::TickByTick {
2252        req_id,
2253        tick_type,
2254        tick,
2255    })
2256}
2257
2258fn decode_real_time_bar_fields(fields: &[String]) -> TwsApiResult<Event> {
2259    let mut index = 1;
2260    let req_id = next_i32(fields, &mut index)?;
2261    let bar = BarData {
2262        date: next_string(fields, &mut index),
2263        open: next_f64(fields, &mut index)?,
2264        high: next_f64(fields, &mut index)?,
2265        low: next_f64(fields, &mut index)?,
2266        close: next_f64(fields, &mut index)?,
2267        volume: next_decimal(fields, &mut index)?,
2268        wap: next_decimal(fields, &mut index)?,
2269        bar_count: next_i32(fields, &mut index)?,
2270    };
2271
2272    Ok(Event::RealTimeBar {
2273        req_id,
2274        time: bar.date.parse::<i64>().unwrap_or_default(),
2275        bar,
2276    })
2277}
2278
2279fn decode_position_fields(fields: &[String]) -> TwsApiResult<Event> {
2280    let version = parse_i32(fields.first())?;
2281    let mut index = 1;
2282    let account = next_string(fields, &mut index);
2283    let contract = decode_position_contract_fields(fields, &mut index, version >= 2)?;
2284    let position = next_decimal(fields, &mut index)?;
2285    let avg_cost = if version >= 3 {
2286        next_f64(fields, &mut index)?
2287    } else {
2288        0.0
2289    };
2290
2291    Ok(Event::Position {
2292        account,
2293        contract: Box::new(contract),
2294        position,
2295        avg_cost,
2296    })
2297}
2298
2299fn decode_position_multi_fields(fields: &[String]) -> TwsApiResult<Event> {
2300    let mut index = 1;
2301    let req_id = next_i32(fields, &mut index)?;
2302    let account = next_string(fields, &mut index);
2303    let contract = decode_position_contract_fields(fields, &mut index, true)?;
2304    let position = next_decimal(fields, &mut index)?;
2305    let avg_cost = next_f64(fields, &mut index)?;
2306    let model_code = next_string(fields, &mut index);
2307
2308    Ok(Event::PositionMulti {
2309        req_id,
2310        account,
2311        model_code,
2312        contract: Box::new(contract),
2313        position,
2314        avg_cost,
2315    })
2316}
2317
2318fn decode_position_contract_fields(
2319    fields: &[String],
2320    index: &mut usize,
2321    include_trading_class: bool,
2322) -> TwsApiResult<Contract> {
2323    let mut contract = Contract {
2324        con_id: next_i32(fields, index)?,
2325        symbol: next_string(fields, index),
2326        sec_type: next_string(fields, index),
2327        last_trade_date_or_contract_month: next_string(fields, index),
2328        strike: next_f64(fields, index)?,
2329        right: next_string(fields, index),
2330        multiplier: next_string(fields, index),
2331        exchange: next_string(fields, index),
2332        currency: next_string(fields, index),
2333        local_symbol: next_string(fields, index),
2334        ..Contract::default()
2335    };
2336
2337    if include_trading_class {
2338        contract.trading_class = next_string(fields, index);
2339    }
2340
2341    Ok(contract)
2342}
2343
2344fn decode_security_definition_option_parameter_fields(fields: &[String]) -> TwsApiResult<Event> {
2345    let req_id = parse_i32(fields.first())?;
2346    let exchange = fields.get(1).cloned().unwrap_or_default();
2347    let underlying_con_id = parse_i32(fields.get(2))?;
2348    let trading_class = fields.get(3).cloned().unwrap_or_default();
2349    let multiplier = fields.get(4).cloned().unwrap_or_default();
2350
2351    let mut index = 5;
2352    let expiration_count = parse_i32(fields.get(index)).unwrap_or_default().max(0) as usize;
2353    index += 1;
2354
2355    let mut expirations = Vec::with_capacity(expiration_count);
2356    for _ in 0..expiration_count {
2357        expirations.push(fields.get(index).cloned().unwrap_or_default());
2358        index += 1;
2359    }
2360
2361    let strike_count = parse_i32(fields.get(index)).unwrap_or_default().max(0) as usize;
2362    index += 1;
2363
2364    let mut strikes = Vec::with_capacity(strike_count);
2365    for _ in 0..strike_count {
2366        strikes.push(parse_f64(fields.get(index))?);
2367        index += 1;
2368    }
2369
2370    Ok(Event::SecurityDefinitionOptionParameter {
2371        req_id,
2372        exchange,
2373        underlying_con_id,
2374        trading_class,
2375        multiplier,
2376        expirations,
2377        strikes,
2378    })
2379}
2380
2381fn next_string(fields: &[String], index: &mut usize) -> String {
2382    let value = fields.get(*index).cloned().unwrap_or_default();
2383    *index += 1;
2384    value
2385}
2386
2387fn next_i32(fields: &[String], index: &mut usize) -> TwsApiResult<i32> {
2388    let value = parse_i32(fields.get(*index));
2389    *index += 1;
2390    value
2391}
2392
2393fn next_f64(fields: &[String], index: &mut usize) -> TwsApiResult<f64> {
2394    let value = parse_f64(fields.get(*index));
2395    *index += 1;
2396    value
2397}
2398
2399fn next_bool(fields: &[String], index: &mut usize) -> bool {
2400    let value = parse_bool(fields.get(*index));
2401    *index += 1;
2402    value
2403}
2404
2405fn next_decimal(fields: &[String], index: &mut usize) -> TwsApiResult<Decimal> {
2406    let value = parse_decimal(fields.get(*index));
2407    *index += 1;
2408    value
2409}
2410
2411fn parse_i32(value: Option<&String>) -> TwsApiResult<i32> {
2412    let field = value.cloned().unwrap_or_default();
2413    field
2414        .parse::<i32>()
2415        .map_err(|source| TwsApiError::InvalidInteger { field, source })
2416}
2417
2418fn parse_i64(value: Option<&String>) -> TwsApiResult<i64> {
2419    let field = value.cloned().unwrap_or_default();
2420    field
2421        .parse::<i64>()
2422        .map_err(|source| TwsApiError::InvalidInteger { field, source })
2423}
2424
2425fn parse_f64(value: Option<&String>) -> TwsApiResult<f64> {
2426    Ok(value
2427        .and_then(|field| field.parse::<f64>().ok())
2428        .unwrap_or_default())
2429}
2430
2431fn parse_bool(value: Option<&String>) -> bool {
2432    matches!(
2433        value.map(String::as_str),
2434        Some("1") | Some("true") | Some("True")
2435    )
2436}
2437
2438fn parse_decimal(value: Option<&String>) -> TwsApiResult<Decimal> {
2439    parse_decimal_string(value.map(String::as_str))
2440}
2441
2442fn parse_decimal_string(value: Option<&str>) -> TwsApiResult<Decimal> {
2443    let field = value.unwrap_or_default().to_owned();
2444    if field.is_empty() {
2445        return Ok(Decimal::default());
2446    }
2447    field
2448        .parse::<Decimal>()
2449        .map_err(|source| TwsApiError::InvalidDecimal { field, source })
2450}