Skip to main content

ib_flex/types/
common.rs

1//! Common enums used across FLEX statements
2
3use chrono::NaiveDate;
4use rust_decimal::Decimal;
5use serde::{Deserialize, Serialize};
6
7/// Asset category (security type)
8///
9/// Maps to IB's AssetCategory field. Represents the type of financial instrument.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
11#[serde(rename_all = "UPPERCASE")]
12pub enum AssetCategory {
13    /// Stock
14    #[serde(rename = "STK")]
15    Stock,
16
17    /// Option
18    #[serde(rename = "OPT")]
19    Option,
20
21    /// Future
22    #[serde(rename = "FUT")]
23    Future,
24
25    /// Future Option
26    #[serde(rename = "FOP")]
27    FutureOption,
28
29    /// Cash/Forex
30    #[serde(rename = "CASH")]
31    Cash,
32
33    /// Bond
34    #[serde(rename = "BOND")]
35    Bond,
36
37    /// Treasury Bill (maturity < 1 year)
38    #[serde(rename = "BILL")]
39    Bill,
40
41    /// Commodity
42    #[serde(rename = "CMDTY")]
43    Commodity,
44
45    /// Contract for Difference
46    #[serde(rename = "CFD")]
47    Cfd,
48
49    /// Forex CFD
50    #[serde(rename = "FXCFD")]
51    ForexCfd,
52
53    /// Warrant
54    #[serde(rename = "WAR")]
55    Warrant,
56
57    /// Mutual Fund
58    #[serde(rename = "FUND")]
59    Fund,
60
61    /// Structured Product / Dutch Warrant / Indexed Option
62    #[serde(rename = "IOPT")]
63    StructuredProduct,
64
65    /// Combination / Basket order (spread, combo legs)
66    #[serde(rename = "BAG")]
67    Bag,
68
69    /// Cryptocurrency
70    #[serde(rename = "CRYPTO")]
71    Cryptocurrency,
72
73    /// Physical metals (gold, silver, etc.)
74    #[serde(rename = "METAL")]
75    Metal,
76
77    /// Exchange for Physical
78    #[serde(rename = "EFP")]
79    ExchangeForPhysical,
80
81    /// Event Contract
82    #[serde(rename = "EC")]
83    EventContract,
84
85    /// Index
86    #[serde(rename = "IND")]
87    Index,
88
89    /// Options on Futures (futures-style settlement)
90    #[serde(rename = "FSFOP")]
91    OptionsOnFutures,
92
93    /// Futures-style option
94    #[serde(rename = "FSOPT")]
95    OptionsFuturesStyle,
96
97    /// Unknown or unrecognized asset category
98    #[serde(other)]
99    Unknown,
100}
101
102/// Buy or Sell side
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
104#[serde(rename_all = "UPPERCASE")]
105pub enum BuySell {
106    /// Buy
107    #[serde(rename = "BUY")]
108    Buy,
109
110    /// Sell
111    #[serde(rename = "SELL")]
112    Sell,
113
114    /// Cancelled buy
115    #[serde(rename = "BUY (Ca.)")]
116    CancelBuy,
117
118    /// Cancelled sell
119    #[serde(rename = "SELL (Ca.)")]
120    CancelSell,
121
122    /// Unknown
123    #[serde(other)]
124    Unknown,
125}
126
127/// Open or Close indicator (for options/futures)
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
129pub enum OpenClose {
130    /// Opening trade
131    #[serde(rename = "O")]
132    Open,
133
134    /// Closing trade
135    #[serde(rename = "C")]
136    Close,
137
138    /// Close and open (same-day round trip)
139    #[serde(rename = "C;O")]
140    CloseOpen,
141
142    /// Unknown
143    #[serde(other)]
144    Unknown,
145}
146
147/// Order type
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
149#[serde(rename_all = "UPPERCASE")]
150pub enum OrderType {
151    /// Market order
152    #[serde(rename = "MKT")]
153    Market,
154
155    /// Limit order
156    #[serde(rename = "LMT")]
157    Limit,
158
159    /// Stop order
160    #[serde(rename = "STP")]
161    Stop,
162
163    /// Stop limit order. Flex XML emits the no-space form `STPLMT`; the
164    /// spaced TWS/API spelling is accepted as an alias.
165    #[serde(rename = "STPLMT", alias = "STP LMT")]
166    StopLimit,
167
168    /// Market on close
169    #[serde(rename = "MOC")]
170    MarketOnClose,
171
172    /// Limit on close
173    #[serde(rename = "LOC")]
174    LimitOnClose,
175
176    /// Market if touched
177    #[serde(rename = "MIT")]
178    MarketIfTouched,
179
180    /// Limit if touched
181    #[serde(rename = "LIT")]
182    LimitIfTouched,
183
184    /// Trailing stop
185    #[serde(rename = "TRAIL")]
186    TrailingStop,
187
188    /// Trailing limit. Flex XML emits the no-space form `TRAILLMT`; the
189    /// spaced TWS/API spelling is accepted as an alias.
190    #[serde(rename = "TRAILLMT", alias = "TRAIL LMT")]
191    TrailingLimit,
192
193    /// Mid-price order
194    #[serde(rename = "MIDPX")]
195    MidPrice,
196
197    /// Relative order
198    #[serde(rename = "REL")]
199    Relative,
200
201    /// Multiple order types (complex orders)
202    #[serde(rename = "MULTIPLE")]
203    Multiple,
204
205    /// Unknown or unrecognized order type
206    #[serde(other)]
207    Unknown,
208}
209
210/// Put or Call (for options)
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
212pub enum PutCall {
213    /// Put option
214    #[serde(rename = "P")]
215    Put,
216
217    /// Call option
218    #[serde(rename = "C")]
219    Call,
220
221    /// Unknown
222    #[serde(other)]
223    Unknown,
224}
225
226/// Long or Short position side
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
228pub enum LongShort {
229    /// Long position
230    Long,
231
232    /// Short position
233    Short,
234
235    /// Unknown
236    #[serde(other)]
237    Unknown,
238}
239
240/// Transaction type for trades
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
242pub enum TradeType {
243    /// Exchange trade
244    ExchTrade,
245
246    /// Book trade
247    BookTrade,
248
249    /// Delivery vs Payment trade
250    DvpTrade,
251
252    /// Fractional share trade
253    FracShare,
254
255    /// Fractional share cancellation
256    FracShareCancel,
257
258    /// Manual adjustment
259    Adjustment,
260
261    /// Trade correction
262    TradeCorrect,
263
264    /// Trade cancellation
265    TradeCancel,
266
267    /// IBKR trade
268    IBKRTrade,
269
270    /// Unknown
271    #[serde(other)]
272    Unknown,
273}
274
275/// Cash transaction action type
276///
277/// Represents the type of cash transaction (dividend, interest, fee, etc.).
278/// This enum is used by the `CashTransaction` struct to classify cash activity
279/// in the account statement.
280///
281/// **XML Mapping**: Maps to the `type` attribute in `<CashTransaction>` elements.
282#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
283pub enum CashTransactionType {
284    /// Deposits and withdrawals
285    #[serde(rename = "Deposits & Withdrawals")]
286    DepositsWithdrawals,
287
288    /// Dividend payments
289    Dividends,
290
291    /// Withholding tax
292    #[serde(rename = "Withholding Tax")]
293    WithholdingTax,
294
295    /// Broker interest paid
296    #[serde(rename = "Broker Interest Paid")]
297    BrokerInterestPaid,
298
299    /// Broker interest received
300    #[serde(rename = "Broker Interest Received")]
301    BrokerInterestReceived,
302
303    /// Bond interest received
304    #[serde(rename = "Bond Interest Received")]
305    BondInterestReceived,
306
307    /// Bond interest paid
308    #[serde(rename = "Bond Interest Paid")]
309    BondInterestPaid,
310
311    /// Bond interest (generic)
312    #[serde(rename = "Bond Interest")]
313    BondInterest,
314
315    /// Payment in lieu of dividends
316    #[serde(rename = "Payment In Lieu Of Dividends")]
317    PaymentInLieuOfDividends,
318
319    /// Other fees
320    #[serde(rename = "Other Fees")]
321    OtherFees,
322
323    /// Commission adjustments
324    #[serde(rename = "Commission Adjustments")]
325    CommissionAdjustments,
326
327    /// Advisor fees
328    #[serde(rename = "Advisor Fees")]
329    AdvisorFees,
330
331    /// Cash receipts
332    #[serde(rename = "Cash Receipts")]
333    CashReceipts,
334
335    /// Fees
336    Fees,
337
338    /// Unknown type
339    #[serde(other)]
340    Unknown,
341}
342
343/// Corporate action reorganization type
344///
345/// Represents the type of corporate action (split, merger, spinoff, etc.).
346/// This enum is used by the `CorporateAction` struct to classify corporate events
347/// that affect security positions and holdings.
348///
349/// **XML Mapping**: Maps to the `type` attribute in `<CorporateAction>` elements.
350#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
351pub enum CorporateActionType {
352    /// Stock split (forward split)
353    #[serde(rename = "Stock Split")]
354    StockSplit,
355
356    /// Forward split (issue)
357    #[serde(rename = "Forward Split (Issue)")]
358    ForwardSplitIssue,
359
360    /// Forward split
361    #[serde(rename = "Forward Split")]
362    ForwardSplit,
363
364    /// Reverse split
365    #[serde(rename = "Reverse Split")]
366    ReverseSplit,
367
368    /// Merger
369    Merger,
370
371    /// Spinoff
372    Spinoff,
373
374    /// Contract spinoff
375    #[serde(rename = "Contract Spinoff")]
376    ContractSpinoff,
377
378    /// Stock dividend
379    #[serde(rename = "Stock Dividend")]
380    StockDividend,
381
382    /// Cash dividend
383    #[serde(rename = "Cash Dividend")]
384    CashDividend,
385
386    /// Choice dividend
387    #[serde(rename = "Choice Dividend")]
388    ChoiceDividend,
389
390    /// Choice dividend (delivery)
391    #[serde(rename = "Choice Dividend (Delivery)")]
392    ChoiceDivDelivery,
393
394    /// Choice dividend (issue)
395    #[serde(rename = "Choice Dividend (Issue)")]
396    ChoiceDivIssue,
397
398    /// Dividend rights issue
399    #[serde(rename = "Dividend Rights Issue")]
400    DivRightsIssue,
401
402    /// Expired dividend right
403    #[serde(rename = "Expired Dividend Right")]
404    ExpiredDivRight,
405
406    /// Delisted
407    Delisted,
408
409    /// Delist (worthless)
410    #[serde(rename = "Delist (Worthless)")]
411    DelistWorthless,
412
413    /// Name change
414    #[serde(rename = "Name Change")]
415    NameChange,
416
417    /// Symbol change
418    #[serde(rename = "Symbol Change")]
419    SymbolChange,
420
421    /// Issue change
422    #[serde(rename = "Issue Change")]
423    IssueChange,
424
425    /// Bond conversion
426    #[serde(rename = "Bond Conversion")]
427    BondConversion,
428
429    /// Bond maturity
430    #[serde(rename = "Bond Maturity")]
431    BondMaturity,
432
433    /// T-Bill maturity
434    #[serde(rename = "T-Bill Maturity")]
435    TBillMaturity,
436
437    /// Convertible issue
438    #[serde(rename = "Convertible Issue")]
439    ConvertibleIssue,
440
441    /// Coupon payment
442    #[serde(rename = "Coupon Payment")]
443    CouponPayment,
444
445    /// Contract consolidation
446    #[serde(rename = "Contract Consolidation")]
447    ContractConsolidation,
448
449    /// Contract split
450    #[serde(rename = "Contract Split")]
451    ContractSplit,
452
453    /// Contract termination
454    #[serde(rename = "CFD Termination")]
455    CfdTermination,
456
457    /// Fee allocation
458    #[serde(rename = "Fee Allocation")]
459    FeeAllocation,
460
461    /// Rights issue
462    #[serde(rename = "Rights Issue")]
463    RightsIssue,
464
465    /// Subscribe rights
466    #[serde(rename = "Subscribe Rights")]
467    SubscribeRights,
468
469    /// Tender
470    Tender,
471
472    /// Tender (issue)
473    #[serde(rename = "Tender (Issue)")]
474    TenderIssue,
475
476    /// Proxy vote
477    #[serde(rename = "Proxy Vote")]
478    ProxyVote,
479
480    /// Generic voluntary
481    #[serde(rename = "Generic Voluntary")]
482    GenericVoluntary,
483
484    /// Asset purchase
485    #[serde(rename = "Asset Purchase")]
486    AssetPurchase,
487
488    /// Purchase (issue)
489    #[serde(rename = "Purchase (Issue)")]
490    PurchaseIssue,
491
492    /// Unknown
493    #[serde(other)]
494    Unknown,
495}
496
497/// Option action type
498#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
499pub enum OptionAction {
500    /// Assignment
501    Assignment,
502
503    /// Exercise
504    Exercise,
505
506    /// Expiration
507    Expiration,
508
509    /// Expire (alternate form)
510    Expire,
511
512    /// Cash settlement
513    #[serde(rename = "Cash Settlement")]
514    CashSettlement,
515
516    /// Buy to open/close
517    Buy,
518
519    /// Sell to open/close
520    Sell,
521
522    /// Unknown
523    #[serde(other)]
524    Unknown,
525}
526
527/// Transfer type
528#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
529pub enum TransferType {
530    /// ACATS transfer (older statements abbreviate this as `ACAT`)
531    #[serde(rename = "ACATS", alias = "ACAT")]
532    ACATS,
533
534    /// ATON transfer
535    ATON,
536
537    /// Free of payment
538    FOP,
539
540    /// Internal transfer
541    INTERNAL,
542
543    /// Intercompany transfer
544    INTERCOMPANY,
545
546    /// Over-the-counter transfer
547    OTC,
548
549    /// Delivery vs payment
550    DVP,
551
552    /// Unknown
553    #[serde(other)]
554    Unknown,
555}
556
557/// Transaction code
558///
559/// Comprehensive list of IB transaction classification codes.
560/// These codes appear in `notes` fields and can be combined (e.g., "C;W" for closing + wash sale).
561/// They provide critical context for tax reporting and trade classification.
562#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
563pub enum TransactionCode {
564    /// Assignment - Option assignment triggering stock delivery
565    #[serde(rename = "A")]
566    Assignment,
567
568    /// Adjustment - Manual adjustment affecting cost basis
569    #[serde(rename = "Adj")]
570    Adjustment,
571
572    /// Allocation - Trade allocation to sub-account (master/sub allocation)
573    #[serde(rename = "Al")]
574    Allocation,
575
576    /// Auto Exercise - Automatic exercise (dividend-related, exercise before ex-div)
577    #[serde(rename = "Ae")]
578    AutoExercise,
579
580    /// Auto FX - AutoFX currency conversion for settlement
581    #[serde(rename = "Af")]
582    AutoFx,
583
584    /// Away Trade - Trade executed away from IB (third-party execution)
585    #[serde(rename = "Aw")]
586    AwayTrade,
587
588    /// Buy-In - Forced purchase to cover failed delivery (forced short cover)
589    #[serde(rename = "B")]
590    BuyIn,
591
592    /// Borrow - Securities borrowing fee (lending charge)
593    #[serde(rename = "Bo")]
594    BorrowFee,
595
596    /// Cancellation - Trade cancelled/busted (trade reversed)
597    #[serde(rename = "Ca")]
598    Cancelled,
599
600    /// Closing - Closing trade (reduces position)
601    #[serde(rename = "C")]
602    Closing,
603
604    /// Cash Delivery - Cash delivery for exercise (cash vs physical)
605    #[serde(rename = "Cd")]
606    CashDelivery,
607
608    /// Complex Position - Complex/combo position (multi-leg strategy)
609    #[serde(rename = "Cp")]
610    ComplexPosition,
611
612    /// Correction - Trade correction (amended execution)
613    #[serde(rename = "Cr")]
614    Correction,
615
616    /// Crossing - Internal IB cross (matched internally)
617    #[serde(rename = "Cs")]
618    Crossing,
619
620    /// Dual Agent - IB dual agent capacity (disclosed dual role)
621    #[serde(rename = "D")]
622    DualAgent,
623
624    /// ETF - ETF creation/redemption (in-kind basket)
625    #[serde(rename = "Et")]
626    Etf,
627
628    /// Expired - From expired position (option/warrant expiry)
629    #[serde(rename = "Ex")]
630    Expired,
631
632    /// Exercise - Option exercise (long option exercised)
633    #[serde(rename = "O")]
634    Exercise,
635
636    /// Guaranteed - Guaranteed account segment (special margin)
637    #[serde(rename = "G")]
638    Guaranteed,
639
640    /// Highest Cost - Highest cost tax lot (tax lot selection)
641    #[serde(rename = "Hc")]
642    HighestCost,
643
644    /// HF Investment - Hedge fund investment (fund subscription)
645    #[serde(rename = "Hi")]
646    HfInvestment,
647
648    /// HF Redemption - Hedge fund redemption (fund redemption)
649    #[serde(rename = "Hr")]
650    HfRedemption,
651
652    /// Internal - Internal transfer (between IB accounts)
653    #[serde(rename = "I")]
654    InternalTransfer,
655
656    /// Affiliate - Affiliate execution (related party trade)
657    #[serde(rename = "Ia")]
658    Affiliate,
659
660    /// Investor - Investment from investor (capital contribution)
661    #[serde(rename = "Iv")]
662    Investor,
663
664    /// Margin Violation - Liquidation due to margin (forced liquidation)
665    #[serde(rename = "L")]
666    MarginLiquidation,
667
668    /// LIFO - LIFO tax lot (tax lot selection)
669    #[serde(rename = "Li")]
670    Lifo,
671
672    /// Loan - Securities lending income (lending income)
673    #[serde(rename = "Ln")]
674    Loan,
675
676    /// Long-Term - Long-term gain/loss (holding > 1 year)
677    #[serde(rename = "Lt")]
678    LongTermGain,
679
680    /// Manual - Manual IB entry (manual adjustment)
681    #[serde(rename = "M")]
682    ManualEntry,
683
684    /// Max Loss - Maximize losses (tax optimization)
685    #[serde(rename = "Ml")]
686    MaxLoss,
687
688    /// Min LT Gain - Minimize long-term gain (tax optimization)
689    #[serde(rename = "Mn")]
690    MinLongTermGain,
691
692    /// Max ST Gain - Maximize short-term gain (tax optimization)
693    #[serde(rename = "Ms")]
694    MaxShortTermGain,
695
696    /// Min ST Gain - Minimize short-term gain (tax optimization)
697    #[serde(rename = "Mi")]
698    MinShortTermGain,
699
700    /// Manual Exercise - Manual exercise (discretionary exercise)
701    #[serde(rename = "Mx")]
702    ManualExercise,
703
704    /// Opening - Opening trade (new position)
705    #[serde(rename = "P")]
706    Opening,
707
708    /// Partial - Partial execution (partial fill)
709    #[serde(rename = "Pt")]
710    Partial,
711
712    /// Frac Riskless - Fractional riskless principal (fractional share method)
713    #[serde(rename = "Fr")]
714    FracRiskless,
715
716    /// Frac Principal - Fractional principal (fractional share method)
717    #[serde(rename = "Fp")]
718    FracPrincipal,
719
720    /// Price Improvement - Better than quoted (price improvement)
721    #[serde(rename = "Pi")]
722    PriceImprovement,
723
724    /// Post Accrual - Accrual posting (accrual entry)
725    #[serde(rename = "Pa")]
726    PostAccrual,
727
728    /// Principal - IB principal execution (principal trade)
729    #[serde(rename = "Pr")]
730    Principal,
731
732    /// Reinvestment - Dividend reinvestment (DRIP)
733    #[serde(rename = "Re")]
734    Reinvestment,
735
736    /// Redemption - Capital distribution (fund redemption)
737    #[serde(rename = "Rd")]
738    Redemption,
739
740    /// Reopen - Position reopened (wash sale reopen)
741    #[serde(rename = "R")]
742    Reopen,
743
744    /// Reverse - Accrual reversal (accounting reversal)
745    #[serde(rename = "Rv")]
746    Reverse,
747
748    /// Reimbursement - Fee refund (expense refund)
749    #[serde(rename = "Ri")]
750    Reimbursement,
751
752    /// Solicited IB - IB solicited order (IB-initiated)
753    #[serde(rename = "Si")]
754    SolicitedIb,
755
756    /// Specific Lot - Specific tax lot (tax lot selection)
757    #[serde(rename = "Sp")]
758    SpecificLot,
759
760    /// Solicited Other - Third-party solicited (broker-solicited)
761    #[serde(rename = "So")]
762    SolicitedOther,
763
764    /// Short Settlement - T+0 or T+1 settlement (accelerated settle)
765    #[serde(rename = "Ss")]
766    ShortSettlement,
767
768    /// Short-Term - Short-term gain/loss (holding <= 1 year)
769    #[serde(rename = "St")]
770    ShortTermGain,
771
772    /// Stock Yield - Stock yield eligible (lending eligible)
773    #[serde(rename = "Sy")]
774    StockYield,
775
776    /// Transfer - Position transfer
777    #[serde(rename = "T")]
778    Transfer,
779
780    /// Wash Sale - Wash sale (loss disallowed)
781    #[serde(rename = "W")]
782    WashSale,
783
784    /// Unknown code
785    #[serde(other)]
786    Unknown,
787}
788
789/// Direction (To/From)
790#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
791pub enum ToFrom {
792    /// To
793    To,
794
795    /// From
796    From,
797
798    /// Unknown
799    #[serde(other)]
800    Unknown,
801}
802
803/// Direction (In/Out)
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
805pub enum InOut {
806    /// Incoming
807    IN,
808
809    /// Outgoing
810    OUT,
811
812    /// Unknown
813    #[serde(other)]
814    Unknown,
815}
816
817/// Delivered or Received
818#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
819pub enum DeliveredReceived {
820    /// Delivered
821    Delivered,
822
823    /// Received
824    Received,
825
826    /// Unknown
827    #[serde(other)]
828    Unknown,
829}
830
831/// Level of detail for reporting
832///
833/// Specifies the granularity of data in FLEX reports.
834/// Used by `Trade`, `Position`, and `CashTransaction` structs to indicate
835/// the level of detail requested in the FLEX query.
836///
837/// **XML Mapping**: Maps to the `levelOfDetail` attribute in various elements.
838#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
839pub enum LevelOfDetail {
840    /// Summary level - aggregated data with minimal details (`SUMMARY`)
841    #[serde(rename = "SUMMARY", alias = "Summary")]
842    Summary,
843
844    /// Detail level - standard reporting with all key fields (`DETAIL`)
845    #[serde(rename = "DETAIL", alias = "Detail")]
846    Detail,
847
848    /// Execution level - detailed execution information including time and venue (`EXECUTION`)
849    #[serde(rename = "EXECUTION", alias = "Execution")]
850    Execution,
851
852    /// Tax-lot level details for cost-basis tracking (`LOT`)
853    #[serde(rename = "LOT", alias = "Lot")]
854    Lot,
855
856    /// Closed tax lot (`CLOSED_LOT`) - the realized side of a lot
857    #[serde(rename = "CLOSED_LOT")]
858    ClosedLot,
859
860    /// Order roll-up row (`ORDER`)
861    #[serde(rename = "ORDER")]
862    Order,
863
864    /// Wash-sale adjustment row (`WASH_SALE`)
865    #[serde(rename = "WASH_SALE")]
866    WashSale,
867
868    /// Per-symbol roll-up row (`SYMBOL_SUMMARY`)
869    #[serde(rename = "SYMBOL_SUMMARY")]
870    SymbolSummary,
871
872    /// Per-asset-class roll-up row (`ASSET_SUMMARY`)
873    #[serde(rename = "ASSET_SUMMARY")]
874    AssetSummary,
875
876    /// Per-currency row in cash / equity summaries (`Currency`)
877    Currency,
878
879    /// Base-currency summary row (`BaseCurrency`)
880    BaseCurrency,
881
882    /// Unknown or unrecognized level of detail
883    #[serde(other)]
884    Unknown,
885}
886
887/// Security identifier type
888///
889/// Specifies the type of security identifier used in the `securityID` field.
890/// Different identifiers are used in different markets and contexts.
891///
892/// **XML Mapping**: Maps to the `securityIDType` attribute in various elements.
893///
894/// **Used by**: `Trade`, `SecurityInfo`
895#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
896pub enum SecurityIdType {
897    /// CUSIP - Committee on Uniform Securities Identification Procedures
898    /// 9-character alphanumeric identifier for North American securities
899    #[serde(rename = "CUSIP")]
900    Cusip,
901
902    /// ISIN - International Securities Identification Number
903    /// 12-character alphanumeric code (ISO 6166 standard)
904    #[serde(rename = "ISIN")]
905    Isin,
906
907    /// FIGI - Financial Instrument Global Identifier
908    /// 12-character alphanumeric identifier (Bloomberg Open Symbology)
909    #[serde(rename = "FIGI")]
910    Figi,
911
912    /// SEDOL - Stock Exchange Daily Official List
913    /// 7-character alphanumeric identifier for UK and Irish securities
914    #[serde(rename = "SEDOL")]
915    Sedol,
916
917    /// Unknown or unrecognized security ID type
918    #[serde(other)]
919    Unknown,
920}
921
922/// Security sub-category
923///
924/// Provides additional classification for securities beyond the basic asset category.
925/// Most commonly used for stocks to distinguish between common shares, ETFs, ADRs, REITs, etc.
926///
927/// **XML Mapping**: Maps to the `subCategory` attribute in various elements.
928///
929/// **Used by**: `Trade`, `Position`, `SecurityInfo`
930#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
931pub enum SubCategory {
932    /// Exchange-traded fund
933    #[serde(rename = "ETF")]
934    Etf,
935
936    /// American Depositary Receipt - represents foreign company shares traded in US
937    #[serde(rename = "ADR")]
938    Adr,
939
940    /// Real Estate Investment Trust
941    #[serde(rename = "REIT")]
942    Reit,
943
944    /// Preferred stock
945    #[serde(rename = "Preferred", alias = "PREFERRED")]
946    Preferred,
947
948    /// Common stock
949    #[serde(rename = "Common", alias = "COMMON")]
950    Common,
951
952    /// Depositary Receipt (general)
953    #[serde(rename = "DR")]
954    DepositaryReceipt,
955
956    /// Global Depositary Receipt
957    #[serde(rename = "GDR")]
958    Gdr,
959
960    /// Limited Partnership
961    #[serde(rename = "LP")]
962    LimitedPartnership,
963
964    /// Master Limited Partnership
965    #[serde(rename = "MLP")]
966    MasterLimitedPartnership,
967
968    /// Right (subscription right)
969    #[serde(rename = "Right")]
970    Right,
971
972    /// Unit (combination of securities)
973    #[serde(rename = "Unit")]
974    Unit,
975
976    /// When-Issued security
977    #[serde(rename = "WI")]
978    WhenIssued,
979
980    /// Tracking stock
981    #[serde(rename = "Tracking")]
982    Tracking,
983
984    /// Closed-end fund
985    #[serde(rename = "CEF")]
986    ClosedEndFund,
987
988    /// Unknown or unrecognized sub-category
989    #[serde(other)]
990    Unknown,
991}
992
993/// Derivative instrument information
994///
995/// Contains structured information about derivative contracts (options, futures, warrants).
996/// This enum consolidates derivative-specific fields based on the instrument type.
997///
998/// **Used by**: `Trade`, `Position`
999#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1000#[serde(tag = "type")]
1001pub enum DerivativeInfo {
1002    /// Option contract (equity or index option)
1003    ///
1004    /// Standard option giving the right (but not obligation) to buy or sell
1005    /// an underlying asset at a specified strike price by the expiration date.
1006    Option {
1007        /// Strike price - price at which the option can be exercised
1008        strike: Decimal,
1009
1010        /// Expiration date - last date the option can be exercised
1011        expiry: NaiveDate,
1012
1013        /// Put or Call - right to sell (Put) or buy (Call)
1014        #[serde(rename = "putCall")]
1015        put_call: PutCall,
1016
1017        /// Symbol of the underlying security (e.g., "AAPL" for Apple stock)
1018        #[serde(rename = "underlyingSymbol")]
1019        underlying_symbol: String,
1020
1021        /// IB contract ID of the underlying security
1022        #[serde(rename = "underlyingConid")]
1023        underlying_conid: Option<String>,
1024    },
1025
1026    /// Future contract
1027    ///
1028    /// Agreement to buy or sell an asset at a predetermined price
1029    /// on a specified future date.
1030    Future {
1031        /// Expiration date - settlement date for the futures contract
1032        expiry: NaiveDate,
1033
1034        /// Symbol of the underlying asset
1035        #[serde(rename = "underlyingSymbol")]
1036        underlying_symbol: String,
1037
1038        /// IB contract ID of the underlying asset
1039        #[serde(rename = "underlyingConid")]
1040        underlying_conid: Option<String>,
1041    },
1042
1043    /// Future option (option on a futures contract)
1044    ///
1045    /// Option where the underlying asset is a futures contract rather than a stock.
1046    FutureOption {
1047        /// Strike price for the option
1048        strike: Decimal,
1049
1050        /// Expiration date of the option
1051        expiry: NaiveDate,
1052
1053        /// Put or Call
1054        #[serde(rename = "putCall")]
1055        put_call: PutCall,
1056
1057        /// Symbol of the underlying futures contract
1058        #[serde(rename = "underlyingSymbol")]
1059        underlying_symbol: String,
1060
1061        /// IB contract ID of the underlying futures
1062        #[serde(rename = "underlyingConid")]
1063        underlying_conid: Option<String>,
1064    },
1065
1066    /// Warrant
1067    ///
1068    /// Long-term option-like security issued by a company, typically
1069    /// with longer expiration periods than standard options.
1070    Warrant {
1071        /// Strike price (if applicable)
1072        strike: Option<Decimal>,
1073
1074        /// Expiration date (if applicable)
1075        expiry: Option<NaiveDate>,
1076
1077        /// Symbol of the underlying security (if applicable)
1078        #[serde(rename = "underlyingSymbol")]
1079        underlying_symbol: Option<String>,
1080    },
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085    use super::*;
1086
1087    #[test]
1088    fn test_asset_category_basic() {
1089        // Test enum construction and comparison
1090        let stock = AssetCategory::Stock;
1091        assert_eq!(stock, AssetCategory::Stock);
1092        assert_ne!(stock, AssetCategory::Option);
1093    }
1094
1095    #[test]
1096    fn test_buy_sell_basic() {
1097        // Test enum construction and comparison
1098        let buy = BuySell::Buy;
1099        assert_eq!(buy, BuySell::Buy);
1100        assert_ne!(buy, BuySell::Sell);
1101    }
1102
1103    #[test]
1104    fn test_open_close_basic() {
1105        let open = OpenClose::Open;
1106        assert_eq!(open, OpenClose::Open);
1107        assert_ne!(open, OpenClose::Close);
1108    }
1109
1110    #[test]
1111    fn test_put_call_basic() {
1112        let call = PutCall::Call;
1113        assert_eq!(call, PutCall::Call);
1114        assert_ne!(call, PutCall::Put);
1115    }
1116}