From 45b60efe6132af02ee5aedc5c72a4da8aff1e7c7 Mon Sep 17 00:00:00 2001 From: 5Ub-Z3r0 <1673590+5Ub-Z3r0@users.noreply.github.com> Date: Mon, 20 May 2024 15:32:01 +0200 Subject: [PATCH 1/3] Add a TransferLot Type to the list of Transfer types available. TransferLot has additional information on the different lots that composes a Transfer, similar to Lot in Trades. --- ibflex/Types.py | 39 ++++++++++++++++++++++++++++++++++++--- tests/test_types.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/ibflex/Types.py b/ibflex/Types.py index a292987..be8b020 100644 --- a/ibflex/Types.py +++ b/ibflex/Types.py @@ -804,7 +804,8 @@ class CashReportCurrency(FlexElement): slbNetSettledCashSec: Optional[decimal.Decimal] = None slbNetSettledCashCom: Optional[decimal.Decimal] = None slbNetSettledCashPaxos: Optional[decimal.Decimal] = None - + + @dataclass(frozen=True) class CFDCharge(FlexElement): """ Wrapped in """ @@ -848,8 +849,8 @@ class CFDCharge(FlexElement): acctAlias: Optional[str] = None model: Optional[str] = None levelOfDetail: Optional[str] = None - - + + @dataclass(frozen=True) class StatementOfFundsLine(FlexElement): """ Wrapped in """ @@ -906,6 +907,7 @@ class StatementOfFundsLine(FlexElement): weight: Optional[str] = None actionID: Optional[str] = None + @dataclass(frozen=True) class ChangeInPositionValue(FlexElement): """ Wrapped in """ @@ -1107,6 +1109,37 @@ class Trade(FlexElement): figi: Optional[str] = None +@dataclass(frozen=True) +class TransferLot(FlexElement): + """ Wrapped in """ + accountId: Optional[str] = None + currency: Optional[str] = None + fxRateToBase: Optional[decimal.Decimal] = None + assetCategory: Optional[enums.AssetClass] = None + symbol: Optional[str] = None + description: Optional[str] = None + conid: Optional[str] = None + securityID: Optional[str] = None + securityIDType: Optional[str] = None + cusip: Optional[str] = None + isin: Optional[str] = None + listingExchange: Optional[str] = None + multiplier: Optional[decimal.Decimal] = None + reportDate: Optional[datetime.date] = None + date: Optional[datetime.date] = None + dateTime: Optional[datetime.datetime] = None + type: Optional[enums.TransferType] = None + direction: Optional[enums.InOut] = None + company: Optional[str] = None + account: Optional[str] = None + deliveringBroker: Optional[str] = None + quantity: Optional[decimal.Decimal] = None + transferPrice: Optional[decimal.Decimal] = None + pnlAmount: Optional[decimal.Decimal] = None + pnlAmountInBase: Optional[decimal.Decimal] = None + code: Tuple[enums.Code, ...] = () + + @dataclass(frozen=True) class Lot(FlexElement): """ Wrapped in """ diff --git a/tests/test_types.py b/tests/test_types.py index e43224b..9c0082d 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1004,6 +1004,49 @@ def testParse(self): self.assertEqual(instance.clientReference, None) +class TransferLotTestCase(unittest.TestCase): + data = ET.fromstring( + ('') + ) + + def testParse(self): + instance = parser.parse_data_element(self.data) + self.assertIsInstance(instance, Types.TransferLot) + self.assertEqual(instance.accountId, "U123456") + self.assertEqual(instance.currency, "USD") + self.assertEqual(instance.fxRateToBase, decimal.Decimal("1")) + self.assertEqual(instance.assetCategory, enums.AssetClass.STOCK) + self.assertEqual(instance.symbol, "FMTIF") + self.assertEqual(instance.description, "FMI HOLDINGS LTD") + self.assertEqual(instance.conid, "86544467") + self.assertEqual(instance.securityID, None) + self.assertEqual(instance.securityIDType, None) + self.assertEqual(instance.cusip, "02K123K") + self.assertEqual(instance.isin, None) + self.assertEqual(instance.listingExchange, "NYSE") + self.assertEqual(instance.multiplier, decimal.Decimal("1")) + self.assertEqual(instance.reportDate, datetime.date(2011, 7, 18)) + self.assertEqual(instance.date, datetime.date(2011, 7, 18)) + self.assertEqual(instance.dateTime, datetime.datetime(2011, 7, 18, 0, 0, 0)) + self.assertEqual(instance.type, enums.TransferType.FOP) + self.assertEqual(instance.direction, enums.InOut.IN) + self.assertEqual(instance.company, 'HOOLI') + self.assertEqual(instance.account, "12345678") + self.assertEqual(instance.deliveringBroker, "12345") + self.assertEqual(instance.quantity, decimal.Decimal("701.5")) + self.assertEqual(instance.transferPrice, decimal.Decimal("0")) + self.assertEqual(instance.pnlAmount, decimal.Decimal("0")) + self.assertEqual(instance.pnlAmountInBase, decimal.Decimal("0")) + self.assertEqual(instance.code, (enums.Code.STCG, )) + + class CorporateActionTestCase(unittest.TestCase): data = ET.fromstring( (' Date: Mon, 20 May 2024 22:41:24 +0200 Subject: [PATCH 2/3] Add a few extra fields to TransferLot that also appears in Transfer. --- ibflex/Types.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ibflex/Types.py b/ibflex/Types.py index be8b020..6895de8 100644 --- a/ibflex/Types.py +++ b/ibflex/Types.py @@ -1138,6 +1138,28 @@ class TransferLot(FlexElement): pnlAmount: Optional[decimal.Decimal] = None pnlAmountInBase: Optional[decimal.Decimal] = None code: Tuple[enums.Code, ...] = () + acctAlias: Optional[str] = None + model: Optional[str] = None + underlyingConid: Optional[str] = None + underlyingSymbol: Optional[str] = None + underlyingSecurityID: Optional[str] = None + underlyingListingExchange: Optional[str] = None + issuer: Optional[str] = None + strike: Optional[decimal.Decimal] = None + expiry: Optional[datetime.date] = None + putCall: Optional[enums.PutCall] = None + principalAdjustFactor: Optional[decimal.Decimal] = None + accountName: Optional[str] = None + positionAmount: Optional[decimal.Decimal] = None + positionAmountInBase: Optional[decimal.Decimal] = None + cashTransfer: Optional[decimal.Decimal] = None + clientReference: Optional[str] = None + transactionID: 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) From 3249e0ca0004679529aa23f07385a489198b5706 Mon Sep 17 00:00:00 2001 From: 5Ub-Z3r0 <1673590+5Ub-Z3r0@users.noreply.github.com> Date: Mon, 20 May 2024 22:49:19 +0200 Subject: [PATCH 3/3] Add origTransactionID and relatedTransactionID fields to the Lot (Trade Lots) type, along with a new test for TradeLot types. I've forked the Trade test case for Lots since they share many fields. --- ibflex/Types.py | 2 + tests/test_types.py | 106 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/ibflex/Types.py b/ibflex/Types.py index 6895de8..a5e0a57 100644 --- a/ibflex/Types.py +++ b/ibflex/Types.py @@ -1250,6 +1250,8 @@ class Lot(FlexElement): commodityType: Optional[str] = None fineness: Optional[decimal.Decimal] = None weight: Optional[str] = None + origTransactionID: Optional[str] = None + relatedTransactionID: Optional[str] = None @dataclass(frozen=True) diff --git a/tests/test_types.py b/tests/test_types.py index 9c0082d..e704a7d 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -623,6 +623,112 @@ def testParse(self): self.assertEqual(instance.weight, "0.0 ()") +class TradeLotTestCase(unittest.TestCase): + data = ET.fromstring( + ('') + ) + + def testParse(self): + instance = parser.parse_data_element(self.data) + self.assertIsInstance(instance, Types.Lot) + self.assertEqual(instance.accountId, "U123456") + self.assertEqual(instance.acctAlias, "ibflex test") + self.assertEqual(instance.model, None) + self.assertEqual(instance.currency, "USD") + self.assertEqual(instance.fxRateToBase, decimal.Decimal('1')) + self.assertEqual(instance.assetCategory, enums.AssetClass.STOCK) + self.assertEqual(instance.symbol, "VXX 110917C00005000") + self.assertEqual(instance.description, "VXX 17SEP11 5.0 C") + self.assertEqual(instance.conid, "83615386") + self.assertEqual(instance.securityID, None) + self.assertEqual(instance.securityIDType, None) + self.assertEqual(instance.cusip, None) + self.assertEqual(instance.isin, None) + self.assertEqual(instance.underlyingConid, "80789235") + self.assertEqual(instance.underlyingSymbol, "VXX") + self.assertEqual(instance.issuer, None) + self.assertEqual(instance.multiplier, decimal.Decimal('100')) + self.assertEqual(instance.strike, decimal.Decimal('5')) + self.assertEqual(instance.expiry, datetime.date(2011, 9, 17)) + self.assertEqual(instance.putCall, enums.PutCall.CALL) + self.assertEqual(instance.principalAdjustFactor, None) + self.assertEqual(instance.tradeID, "594763148") + self.assertEqual(instance.reportDate, datetime.date(2011, 8, 12)) + self.assertEqual(instance.tradeDate, datetime.date(2011, 8, 11)) + self.assertEqual(instance.tradeTime, datetime.time(16, 20, 0)) + self.assertEqual(instance.settleDateTarget, datetime.date(2011, 8, 12)) + self.assertEqual(instance.transactionType, enums.TradeType.BOOKTRADE) + self.assertEqual(instance.exchange, None) + self.assertEqual(instance.quantity, decimal.Decimal("3")) + self.assertEqual(instance.tradePrice, decimal.Decimal("0")) + self.assertEqual(instance.tradeMoney, decimal.Decimal("0")) + self.assertEqual(instance.proceeds, decimal.Decimal("-0")) + self.assertEqual(instance.taxes, decimal.Decimal("0")) + self.assertEqual(instance.ibCommission, decimal.Decimal("0")) + self.assertEqual(instance.ibCommissionCurrency, "USD") + self.assertEqual(instance.netCash, decimal.Decimal("0")) + self.assertEqual(instance.closePrice, decimal.Decimal("29.130974")) + self.assertEqual(instance.openCloseIndicator, enums.OpenClose.CLOSE) + self.assertEqual(instance.notes, (enums.Code.ASSIGNMENT, )) + self.assertEqual(instance.cost, decimal.Decimal("8398.81122")) + self.assertEqual(instance.fifoPnlRealized, decimal.Decimal("0")) + self.assertEqual(instance.fxPnl, decimal.Decimal("0")) + self.assertEqual(instance.mtmPnl, decimal.Decimal("8739.2922")) + self.assertEqual(instance.origTradePrice, decimal.Decimal("0")) + self.assertEqual(instance.origTradeDate, None) + self.assertEqual(instance.origTradeID, None) + self.assertEqual(instance.origOrderID, "0") + self.assertEqual(instance.clearingFirmID, None) + self.assertEqual(instance.transactionID, "2381339439") + self.assertEqual(instance.buySell, enums.BuySell.BUY) + self.assertEqual(instance.ibOrderID, "2381339439") + self.assertEqual(instance.ibExecID, None) + self.assertEqual(instance.brokerageOrderID, None) + self.assertEqual(instance.orderReference, None) + self.assertEqual(instance.volatilityOrderLink, None) + self.assertEqual(instance.exchOrderId, None) + self.assertEqual(instance.extExecID, None) + self.assertEqual(instance.orderTime, None) + self.assertEqual(instance.openDateTime, None) + self.assertEqual(instance.holdingPeriodDateTime, None) + self.assertEqual(instance.whenRealized, None) + self.assertEqual(instance.whenReopened, None) + self.assertEqual(instance.levelOfDetail, "EXECUTION") + self.assertEqual(instance.changeInPrice, decimal.Decimal("0")) + self.assertEqual(instance.changeInQuantity, decimal.Decimal("0")) + self.assertEqual(instance.orderType, None) + self.assertEqual(instance.traderID, None) + self.assertEqual(instance.isAPIOrder, False) + self.assertEqual(instance.accruedInt, decimal.Decimal("0")) + self.assertEqual(instance.serialNumber, None) + self.assertEqual(instance.deliveryType, None) + self.assertEqual(instance.commodityType, None) + self.assertEqual(instance.fineness, decimal.Decimal("0")) + self.assertEqual(instance.weight, "0.0 ()") + self.assertEqual(instance.origTransactionID, "1234") + self.assertEqual(instance.relatedTransactionID, "3456") + + class OptionEAETestCase(unittest.TestCase): data = ET.fromstring( ('