From fa205e6ab532685940619d95c01ed88459c0c9f8 Mon Sep 17 00:00:00 2001 From: Da5hes Date: Tue, 10 Sep 2024 19:51:42 +0300 Subject: [PATCH 1/7] - added support for single position PnL - added support for defining order Id's to allow complex parent/child orders i.e bracket orders --- src/deephaven_ib/__init__.py | 2 +- src/deephaven_ib/_tws/tws_client.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index c0bd83fb..92271408 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -1107,7 +1107,7 @@ def request_tick_data_historical(self, contract: RegisteredContract, what_to_show = tick_type.historical_value() requests = [] - if tick_type not in [TickDataType.MIDPOINT, TickDataType.LAST]: + if tick_type not in [TickDataType.MIDPOINT, TickDataType.LAST, TickDataType.BID_ASK]: raise Exception(f"Unsupported tick data type: {tick_type}") for cd in contract.contract_details: diff --git a/src/deephaven_ib/_tws/tws_client.py b/src/deephaven_ib/_tws/tws_client.py index c666c5f9..dfd8b139 100644 --- a/src/deephaven_ib/_tws/tws_client.py +++ b/src/deephaven_ib/_tws/tws_client.py @@ -182,6 +182,10 @@ def _build_table_writers() -> Dict[str, TableWriter]: table_writers["accounts_pnl"] = TableWriter( ["RequestId", "DailyPnl", "UnrealizedPnl", "RealizedPnl"], [dtypes.int64, dtypes.float64, dtypes.float64, dtypes.float64]) + + table_writers["accounts_pnl_single"] = TableWriter( + ["RequestId", "Position", "DailyPnL", "UnrealizedPnL", "RealizedPnL", "Value"], + [dtypes.int64, dtypes.float64, dtypes.float64, dtypes.float64, dtypes.float64, dtypes.float64]) #### # News @@ -590,6 +594,25 @@ def request_account_positions(self, account: str, model_code: str = "") -> int: self.reqPositionsMulti(reqId=req_id, account=account, modelCode=model_code) return req_id + def request_single_pnl(self, account: str, model_code: str, conid: int) -> int: + """Request PNL updates for a single position. Results are returned in the `accounts_pnl_single` table. + + Args: + account (str): Account to request PNL for. + model_code (str): Model portfolio code to request PNL for. + con_id (int): Contract ID of the position to request PNL for. + + Returns: + Request ID + + Raises: + Exception + """ + + req_id = self.request_id_manager.next_id() + self.log_request(req_id, "PnlSingle", None, {"account": account, "model_code": model_code, "conid": conid}) + self.reqPnLSingle(reqId=req_id, account=account, modelCode=model_code, conid=conid) + return req_id #### # reqManagedAccts @@ -605,6 +628,9 @@ def managedAccounts(self, accountsList: str): self.request_account_pnl(account) self.request_account_overview(account) self.request_account_positions(account) + + # TODO: Implement PnL requests for individual positions + #### # reqFamilyCodes @@ -698,6 +724,20 @@ def accountSummary(self, reqId: int, account: str, tag: str, value: str, currenc self._table_writers["accounts_summary"].write_row([reqId, account, tag, value, currency]) #### + # reqPnLSingle + #### + + def pnlSingle(self, reqId: int, pos: decimal.Decimal, dailyPnL: float, unrealizedPnL: float, realizedPnL: float, value: float): + EWrapper.pnlSingle(self, reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value) + self._table_writers["accounts_pnl_single"].write_row([ + reqId, + pos, + dailyPnL, + unrealizedPnL, + realizedPnL, + value + ]) + # reqPositions #### From a7229c76bad534380931dbae9b5f9c10ea29fbdd Mon Sep 17 00:00:00 2001 From: Da5hes Date: Tue, 10 Sep 2024 19:59:22 +0300 Subject: [PATCH 2/7] fix --- src/deephaven_ib/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index 92271408..d1dcb474 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -1107,7 +1107,7 @@ def request_tick_data_historical(self, contract: RegisteredContract, what_to_show = tick_type.historical_value() requests = [] - if tick_type not in [TickDataType.MIDPOINT, TickDataType.LAST, TickDataType.BID_ASK]: + if tick_type not in [TickDataType.MIDPOINT, TickDataType.LAST]: raise Exception(f"Unsupported tick data type: {tick_type}") for cd in contract.contract_details: @@ -1156,7 +1156,12 @@ def order_place(self, contract: RegisteredContract, order: Order) -> Request: raise Exception( f"RegisteredContracts with multiple contract details are not supported for orders: {contract}") - req_id = self._client.next_order_id() + if order.orderId == 0 or order.orderId is None: + req_id = self._client.next_order_id() + order.orderId = req_id + else: + req_id = order.orderId + cd = contract.contract_details[0] self._client.log_request(req_id, "PlaceOrder", cd.contract, {"order": f"Order({order})"}) self._client.placeOrder(req_id, cd.contract, order) From 3779514bf38d3a2d8bb516ed722340e810d89be3 Mon Sep 17 00:00:00 2001 From: Da5hes Date: Tue, 10 Sep 2024 23:41:52 +0300 Subject: [PATCH 3/7] touchups --- src/deephaven_ib/__init__.py | 31 +++++++++++++++++++++++++++-- src/deephaven_ib/_tws/tws_client.py | 4 +--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index d1dcb474..5efa684a 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -384,7 +384,7 @@ class IbSessionTws: * **accounts_summary**: account summary. Automatically populated. * **accounts_positions**: account positions. Automatically populated. * **accounts_pnl**: account PNL. Automatically populated. - + * **accounts_pnl_single**: single PNL. populated by calling request_single_pnl() on a specific contract. #### # News #### @@ -608,6 +608,15 @@ def deephaven_ib_parse_note(note:str, key:str) -> Optional[str]: .move_columns_up(["RequestId", "ReceiveTime", "Account", "ModelCode"]) \ .drop_columns("Note") \ .last_by("RequestId"), + "accounts_pnl_single": tables_raw["raw_accounts_pnl_single"] \ + .natural_join(tables_raw["raw_requests"], on="RequestId", joins="Note") \ + .update([ + "Account=(String)deephaven_ib_parse_note(Note,`account`)", + "ModelCode=(String)deephaven_ib_parse_note(Note,`model_code`)", + "ConId=(String)deephaven_ib_parse_note(Note,`conid`)"]) \ + .move_columns_up(["RequestId", "ReceiveTime", "Account", "ModelCode"]) \ + .drop_columns("Note") \ + .last_by("RequestId"), "contracts_matching": tables_raw["raw_contracts_matching"] \ .natural_join(tables_raw["raw_requests"], on="RequestId", joins="Pattern=Note") \ .move_columns_up(["RequestId", "ReceiveTime", "Pattern"]) \ @@ -776,6 +785,24 @@ def request_account_positions(self, account: str, model_code: str = "") -> Reque req_id = self._client.request_account_positions(account, model_code) return Request(request_id=req_id) + def request_single_pnl(self, account: str, model_code: str = "", conid: int = 0) -> Request: + """Request PNL updates for a single position. Results are returned in the ``accounts_pnl_single`` table. + + Args: + account (str): Account to request PNL for. + model_code (str): Model portfolio code to request PNL for. + conid (int): Contract ID to request PNL for. + + Returns: + A Request. + + Raises: + Exception: problem executing action. + """ + self._assert_connected() + req_id = self._client.request_single_pnl(account, model_code, conid) + return Request(request_id=req_id) + #################################################################################################################### #################################################################################################################### @@ -1161,7 +1188,7 @@ def order_place(self, contract: RegisteredContract, order: Order) -> Request: order.orderId = req_id else: req_id = order.orderId - + cd = contract.contract_details[0] self._client.log_request(req_id, "PlaceOrder", cd.contract, {"order": f"Order({order})"}) self._client.placeOrder(req_id, cd.contract, order) diff --git a/src/deephaven_ib/_tws/tws_client.py b/src/deephaven_ib/_tws/tws_client.py index dfd8b139..a7b36cd3 100644 --- a/src/deephaven_ib/_tws/tws_client.py +++ b/src/deephaven_ib/_tws/tws_client.py @@ -628,9 +628,7 @@ def managedAccounts(self, accountsList: str): self.request_account_pnl(account) self.request_account_overview(account) self.request_account_positions(account) - - # TODO: Implement PnL requests for individual positions - + #### # reqFamilyCodes From effdd2e5e7b0f1463965b4212bcfe0cca332ead7 Mon Sep 17 00:00:00 2001 From: Daniel Shapira Date: Thu, 12 Sep 2024 00:10:26 +0300 Subject: [PATCH 4/7] Update src/deephaven_ib/__init__.py Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com> --- src/deephaven_ib/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index 5efa684a..5992a301 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -385,6 +385,7 @@ class IbSessionTws: * **accounts_positions**: account positions. Automatically populated. * **accounts_pnl**: account PNL. Automatically populated. * **accounts_pnl_single**: single PNL. populated by calling request_single_pnl() on a specific contract. + #### # News #### From c946a51c4da8cacfc3d9b95cc33668706f287af0 Mon Sep 17 00:00:00 2001 From: Daniel Shapira Date: Thu, 12 Sep 2024 00:10:46 +0300 Subject: [PATCH 5/7] Update src/deephaven_ib/__init__.py Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com> --- src/deephaven_ib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index 5992a301..781c0736 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -615,7 +615,7 @@ def deephaven_ib_parse_note(note:str, key:str) -> Optional[str]: "Account=(String)deephaven_ib_parse_note(Note,`account`)", "ModelCode=(String)deephaven_ib_parse_note(Note,`model_code`)", "ConId=(String)deephaven_ib_parse_note(Note,`conid`)"]) \ - .move_columns_up(["RequestId", "ReceiveTime", "Account", "ModelCode"]) \ + .move_columns_up(["RequestId", "ReceiveTime", "Account", "ModelCode", "ConId"]) \ .drop_columns("Note") \ .last_by("RequestId"), "contracts_matching": tables_raw["raw_contracts_matching"] \ From aa0bfdf57fe336d5bd8f0892c4cad5d88f217dbe Mon Sep 17 00:00:00 2001 From: Daniel Shapira Date: Thu, 12 Sep 2024 00:11:02 +0300 Subject: [PATCH 6/7] Update src/deephaven_ib/__init__.py Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com> --- src/deephaven_ib/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index 781c0736..43e2fb22 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -786,13 +786,13 @@ def request_account_positions(self, account: str, model_code: str = "") -> Reque req_id = self._client.request_account_positions(account, model_code) return Request(request_id=req_id) - def request_single_pnl(self, account: str, model_code: str = "", conid: int = 0) -> Request: + def request_single_pnl(self, contract: RegisteredContract, account: str, model_code: str = "") -> Request: """Request PNL updates for a single position. Results are returned in the ``accounts_pnl_single`` table. Args: + contract (RegisteredContract): contract data is requested for. account (str): Account to request PNL for. model_code (str): Model portfolio code to request PNL for. - conid (int): Contract ID to request PNL for. Returns: A Request. @@ -801,7 +801,7 @@ def request_single_pnl(self, account: str, model_code: str = "", conid: int = 0) Exception: problem executing action. """ self._assert_connected() - req_id = self._client.request_single_pnl(account, model_code, conid) + req_id = self._client.request_single_pnl(account, model_code, contract.conId) return Request(request_id=req_id) From af468aad7a879a79ffb41403edecb6e0e44b1454 Mon Sep 17 00:00:00 2001 From: Da5hes Date: Thu, 12 Sep 2024 00:30:19 +0300 Subject: [PATCH 7/7] fix access to contract id --- src/deephaven_ib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deephaven_ib/__init__.py b/src/deephaven_ib/__init__.py index 43e2fb22..39402d00 100644 --- a/src/deephaven_ib/__init__.py +++ b/src/deephaven_ib/__init__.py @@ -801,7 +801,7 @@ def request_single_pnl(self, contract: RegisteredContract, account: str, model_c Exception: problem executing action. """ self._assert_connected() - req_id = self._client.request_single_pnl(account, model_code, contract.conId) + req_id = self._client.request_single_pnl(account, model_code, contract.contract_details[0].contract.conId) return Request(request_id=req_id)