diff --git a/ibflex/Types.py b/ibflex/Types.py index b7bd660..267617f 100644 --- a/ibflex/Types.py +++ b/ibflex/Types.py @@ -90,6 +90,7 @@ class decorator. Class attributes are annotated with PEP 484 type hints. "SymbolSummary", "AssetSummary", "Order", + "StockGrantActivity", ] import datetime @@ -187,7 +188,7 @@ class FlexStatement(FlexElement): ConversionRates: Tuple["ConversionRate", ...] = () HKIPOOpenSubscriptions: Tuple = () # TODO CommissionCredits: Tuple = () # TODO - StockGrantActivities: Tuple = () # TODO + StockGrantActivities: Tuple["StockGrantActivity", ...] = () SLBCollaterals: Tuple = () # TODO IncentiveCouponAccrualDetails: Tuple = () # TODO DepositsOnHold: Tuple = () # TODO @@ -1298,7 +1299,6 @@ class Lot(FlexElement): relatedTradeID: Optional[str] = None rtn: Optional[str] = None initialInvestment: Optional[decimal.Decimal] = None - positionActionID: Optional[str] = None @dataclass(frozen=True) @@ -1429,39 +1429,6 @@ class SymbolSummary(FlexElement): relatedTradeID: Optional[str] = None origTransactionID: Optional[str] = None relatedTransactionID: Optional[str] = None - positionActionID: Optional[str] = None - changeInPrice: Optional[decimal.Decimal] = None - changeInQuantity: Optional[decimal.Decimal] = None - closePrice: Optional[decimal.Decimal] = None - commodityType: Optional[str] = None - cost: Optional[decimal.Decimal] = None - deliveryType: Optional[str] = None - exchOrderId: Optional[str] = None - extExecID: Optional[str] = None - fifoPnlRealized: Optional[decimal.Decimal] = None - fineness: Optional[decimal.Decimal] = None - holdingPeriodDateTime: Optional[datetime.datetime] = None - ibCommission: Optional[decimal.Decimal] = None - ibCommissionCurrency: Optional[str] = None - ibExecID: Optional[str] = None - ibOrderID: Optional[str] = None - initialInvestment: Optional[decimal.Decimal] = None - mtmPnl: Optional[decimal.Decimal] = None - netCash: Optional[decimal.Decimal] = None - notes: Optional[str] = None - openCloseIndicator: Optional[enums.OpenClose] = None - openDateTime: Optional[datetime.datetime] = None - origOrderID: Optional[str] = None - rtn: Optional[str] = None - serialNumber: Optional[str] = None - settleDateTarget: Optional[datetime.date] = None - taxes: Optional[decimal.Decimal] = None - tradeMoney: Optional[decimal.Decimal] = None - tradePrice: Optional[decimal.Decimal] = None - transactionID: Optional[str] = None - weight: Optional[str] = None - whenRealized: Optional[datetime.datetime] = None - whenReopened: Optional[datetime.datetime] = None @dataclass(frozen=True) @@ -1571,7 +1538,6 @@ class AssetSummary(FlexElement): relatedTransactionID: Optional[str] = None rtn: Optional[str] = None initialInvestment: Optional[decimal.Decimal] = None - positionActionID: Optional[str] = None @dataclass(frozen=True) @@ -1682,7 +1648,6 @@ class Order(FlexElement): weight: Optional[str] = None positionActionID: Optional[str] = None - @dataclass(frozen=True) class TradeConfirm(FlexElement): """Wrapped in """ @@ -2120,6 +2085,7 @@ class Transfer(FlexElement): securityID: Optional[str] = None cusip: Optional[str] = None isin: Optional[str] = None + figi: Optional[str] = None listingExchange: Optional[str] = None underlyingSecurityID: Optional[str] = None underlyingListingExchange: Optional[str] = None @@ -2127,6 +2093,7 @@ class Transfer(FlexElement): underlyingConid: Optional[str] = None date: Optional[datetime.date] = None dateTime: Optional[datetime.datetime] = None + settleDate: Optional[datetime.date] = None account: Optional[str] = None deliveringBroker: Optional[str] = None quantity: Optional[decimal.Decimal] = None @@ -2143,6 +2110,7 @@ class Transfer(FlexElement): securityIDType: Optional[str] = None underlyingSymbol: Optional[str] = None issuer: Optional[str] = None + issuerCountryCode: Optional[str] = None multiplier: Optional[decimal.Decimal] = None strike: Optional[decimal.Decimal] = None expiry: Optional[datetime.date] = None @@ -2154,6 +2122,9 @@ class Transfer(FlexElement): pnlAmountInBase: Optional[decimal.Decimal] = None fxPnl: Optional[decimal.Decimal] = None transactionID: Optional[str] = None + levelOfDetail: Optional[str] = None + positionInstructionID: Optional[str] = None # Took a punt on the type here because not seen in XML data + positionInstructionSetID: Optional[str] = None # Took a punt on the type here because not seen in XML data serialNumber: Optional[str] = None deliveryType: Optional[str] = None commodityType: Optional[str] = None @@ -2282,6 +2253,10 @@ class CorporateAction(FlexElement): commodityType: Optional[str] = None fineness: Optional[decimal.Decimal] = None weight: Optional[str] = None + figi: Optional[str] = None + issuerCountryCode: Optional[str] = None + costBasis: Optional[decimal.Decimal] = None + realizedPL: Optional[decimal.Decimal] = None @dataclass(frozen=True) @@ -2727,6 +2702,17 @@ class TransactionTax(FlexElement): source: Optional[str] = None code: Tuple[enums.Code, ...] = () levelOfDetail: Optional[str] = None + subCategory: Optional[str] = None + figi: Optional[str] = None + issuerCountryCode: Optional[str] = None + settleDate: Optional[datetime.date] = None + orderId: Optional[str] = None + serialNumber: Optional[str] = None + deliveryType: Optional[str] = None + commodityType: Optional[str] = None + fineness: Optional[decimal.Decimal] = None + weight: Optional[str] = None + @dataclass(frozen=True) @@ -2856,5 +2842,51 @@ class SLBOpenContract(FlexElement): fineness: Optional[decimal.Decimal] = None weight: Optional[decimal.Decimal] = None +@dataclass(frozen=True) +class StockGrantActivity(FlexElement): + """Wrapped in """ + + accountId: Optional[str] = None + acctAlias: Optional[str] = None + model: Optional[str] = None + currency: Optional[str] = None + fxRateToBase: Optional[decimal.Decimal] = None + assetCategory: Optional[enums.AssetClass] = None # Called 'AssetClass; in the configuration form # Mentioned in the report configuration screen but not seen in the XML data + subCategory: Optional[str] = None + symbol: Optional[str] = None # symbol of instrument traded, e.g. AAPL, not unique in IBKR as it can exist on different exchanges: (symbol, Exchange, Currency, Asset Type) is unique + description: Optional[str] = None + conid: Optional[str] = None # IBKR identifier of instrument, unique key within IBKR + securityID: Optional[str] = None + securityIDType: Optional[str] = None + cusip: Optional[str] = None + isin: Optional[str] = None + figi: Optional[str] = None + listingExchange: Optional[str] = None + underlyingConid: Optional[str] = None + underlyingSymbol: Optional[str] = None + underlyingSecurityID: Optional[str] = None + underlyingListingExchange: Optional[str] = None + issuer: Optional[str] = None + issuerCountryCode: Optional[str] = None + multiplier: Optional[decimal.Decimal] = None + strike: Optional[decimal.Decimal] = None + expiry: Optional[datetime.date] = None + putCall: Optional[enums.PutCall] = None + principalAdjustFactor: Optional[decimal.Decimal] = None + reportDate: Optional[datetime.date] = None + activityDescription: Optional[str] = None + awardDate: Optional[datetime.date] = None + vestingDate: Optional[datetime.date] = None + quantity: Optional[decimal.Decimal] = None + price: Optional[decimal.Decimal] = None + value: Optional[decimal.Decimal] = None + serialNumber: Optional[str] = None + deliveryType: Optional[str] = None + commodityType: Optional[str] = None + fineness: Optional[decimal.Decimal] = None + weight: Optional[decimal.Decimal] = None + + + # Type alias to work around https://github.com/python/mypy/issues/1775 _ClientFeesDetail = ClientFeesDetail diff --git a/tests/test_types.py b/tests/test_types.py index bf53cf4..d89c14f 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1984,6 +1984,67 @@ def testParse(self): self.assertEqual(instance.mtmPnl, decimal.Decimal("-118.00")) self.assertEqual(instance.tradeID, None) +class StockGrantActivityTestCase(unittest.TestCase): + data = ET.fromstring( + ( + '' + ) + ) + + def testParse(self): + instance = parser.parse_data_element(self.data) + self.assertIsInstance(instance, Types.StockGrantActivity) + self.assertEqual(instance.accountId, "U123456") + self.assertEqual(instance.acctAlias, None) + self.assertEqual(instance.model, None) + self.assertEqual(instance.currency, "USD") + self.assertEqual(instance.fxRateToBase, decimal.Decimal("0.73459")) + self.assertEqual(instance.assetCategory, enums.AssetClass.STOCK) + self.assertEqual(instance.subCategory, "COMMON") + self.assertEqual(instance.symbol, "IBKR") + self.assertEqual(instance.description, "INTERACTIVE BROKERS GRO-CL A") + self.assertEqual(instance.conid, "43645865") + self.assertEqual(instance.securityID, "US45841N1072") + self.assertEqual(instance.securityIDType, "ISIN") + self.assertEqual(instance.cusip, "45841N107") + self.assertEqual(instance.isin, "US45841N1072") + self.assertEqual(instance.figi, "BBG000LV0836") + self.assertEqual(instance.listingExchange, "NASDAQ") + self.assertEqual(instance.underlyingConid, None) + self.assertEqual(instance.underlyingSymbol, "IBKR") + self.assertEqual(instance.underlyingSecurityID, None) + self.assertEqual(instance.underlyingListingExchange, None) + self.assertEqual(instance.issuer, None) + self.assertEqual(instance.issuerCountryCode, "US") + self.assertEqual(instance.multiplier, decimal.Decimal("1")) + self.assertEqual(instance.strike, None) + self.assertEqual(instance.expiry, None) + self.assertEqual(instance.putCall, None) + self.assertEqual(instance.principalAdjustFactor, None) + self.assertEqual(instance.reportDate, datetime.date(2025,6,12)) + self.assertEqual(instance.activityDescription, "Stock Award Grant for Cash Deposit") + self.assertEqual(instance.awardDate, datetime.date(2025,6,12)) + self.assertEqual(instance.vestingDate, datetime.date(2026,6,12)) + self.assertEqual(instance.quantity, decimal.Decimal("2.6454")) + self.assertEqual(instance.price, decimal.Decimal("204.51")) + self.assertEqual(instance.value, decimal.Decimal("541.01")) + self.assertEqual(instance.serialNumber, None) + self.assertEqual(instance.deliveryType, None) + self.assertEqual(instance.commodityType, None) + self.assertEqual(instance.fineness, decimal.Decimal("0.0")) + self.assertEqual(instance.weight, decimal.Decimal("0.0")) if __name__ == '__main__': unittest.main(verbosity=3)