Skip to content

Commit

Permalink
Change FA account subscriptions so that there are no errors (#53)
Browse files Browse the repository at this point in the history
* Ignore errors for ignored FA operations.

* Add an explicit FA flag.

* Document using `is_fa`.

* Document using `is_fa`.

* Added error logging back in.
  • Loading branch information
chipkent authored May 11, 2022
1 parent fa88995 commit c7dee3c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 8 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ settings. By default, production trading uses port 7496, and paper trading uses

`read_only` is a boolean value that is used to enable trading. By default `read_only=True`, preventing trading. Use `read_only=False` to enable trading.

`is_fa` is a boolean value that is used to indicate if an account is a financial advisor (FA) account or a regular acccount.
By using `is_fa=True`, FA account configuration details are requested. By default `is_fa=False`.
If `is_fa=True` is used on a non-FA account, everything should work fine, but there will be error messages.
If `is_fa=False` (the default) is used on a FA account, FA account configurations will not be populated in tables such as
`accounts_groups`, `accounts_allocation_profiles`, and `accounts_aliases`.

`order_id_strategy` is the strategy used for obtaining new order ids. Order id algorithms have tradeoffs in execution time, support for multiple, concurrent sessions, and avoidance of TWS bugs.
* `OrderIdStrategy.RETRY` (default) - Request a new order ID from TWS every time one is needed. Retry if TWS does not respond quickly. This usually avoids a TWS bug where it does not always respond.
* `OrderIdStrategy.BASIC` - Request a new order ID from TWS every time one is needed. Does not retry, so it may deadlock if TWS does not respond.
Expand All @@ -243,6 +249,14 @@ client = dhib.IbSessionTws(host="host.docker.internal", port=7497, read_only=Tru
client.connect()
```

For a read-only financial advisor (FA) session that does not allow trading:
```python
import deephaven_ib as dhib
client = dhib.IbSessionTws(host="host.docker.internal", port=7497, read_only=True, is_fa=True)
client.connect()
```

After `client.connect()` is called, TWS requires that the connection be accepted.
![](docs/assets/accept-connection.png)
Expand Down
5 changes: 3 additions & 2 deletions src/deephaven_ib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ class IbSessionTws:
download_short_rates (bool): True to download a short rates table.
order_id_strategy (OrderIdStrategy): strategy for obtaining new order ids.
read_only (bool): True to create a read only client that can not trade; false to create a read-write client that can trade. Default is true.
is_fa (bool): True for financial advisor accounts; false otherwise. Default is false.
Tables:
Expand Down Expand Up @@ -395,12 +396,12 @@ class IbSessionTws:
_tables_raw: Dict[str, Table]
_tables: Dict[str, Table]

def __init__(self, host: str = "", port: int = 7497, client_id: int = 0, download_short_rates: bool = True, order_id_strategy: OrderIdStrategy = OrderIdStrategy.RETRY, read_only:bool = True):
def __init__(self, host: str = "", port: int = 7497, client_id: int = 0, download_short_rates: bool = True, order_id_strategy: OrderIdStrategy = OrderIdStrategy.RETRY, read_only: bool = True, is_fa: bool = False):
self._host = host
self._port = port
self._client_id = client_id
self._read_only = read_only
self._client = IbTwsClient(download_short_rates=download_short_rates, order_id_strategy=order_id_strategy, read_only=read_only)
self._client = IbTwsClient(download_short_rates=download_short_rates, order_id_strategy=order_id_strategy, read_only=read_only, is_fa=is_fa)
self._tables_raw = {f"raw_{k}": v for k, v in self._client.tables.items()}
self._tables = dict(sorted(IbSessionTws._make_tables(self._tables_raw).items()))

Expand Down
17 changes: 11 additions & 6 deletions src/deephaven_ib/_tws/tws_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ class IbTwsClient(EWrapper, EClient):
_accounts_managed: Set[str]
_order_id_strategy: OrderIdStrategy
_read_only: bool
_is_fa: bool

def __init__(self, download_short_rates: bool, order_id_strategy: OrderIdStrategy, read_only: bool):
def __init__(self, download_short_rates: bool, order_id_strategy: OrderIdStrategy, read_only: bool, is_fa: bool):
EWrapper.__init__(self)
EClient.__init__(self, wrapper=self)
self._table_writers = IbTwsClient._build_table_writers()
Expand All @@ -91,6 +92,7 @@ def __init__(self, download_short_rates: bool, order_id_strategy: OrderIdStrateg
self._accounts_managed = None
self._order_id_strategy = order_id_strategy
self._read_only = read_only
self._is_fa = is_fa

tables = {name: tw.table() for (name, tw) in self._table_writers.items()}

Expand Down Expand Up @@ -357,11 +359,14 @@ def _subscribe(self) -> None:
"""Subscribe to IB data."""

self.reqFamilyCodes()
self.requestFA(1) # request GROUPS. See FaDataTypeEnum.
#TODO: see https://github.com/deephaven-examples/deephaven-ib/issues/32
#TODO: see https://github.com/deephaven-examples/deephaven-ib/issues/5
# self.requestFA(2) # request PROFILE. See FaDataTypeEnum.
self.requestFA(3) # request ACCOUNT ALIASES. See FaDataTypeEnum.

if self._is_fa:
self.requestFA(1) # request GROUPS. See FaDataTypeEnum.
#TODO: see https://github.com/deephaven-examples/deephaven-ib/issues/32
#TODO: see https://github.com/deephaven-examples/deephaven-ib/issues/5
# self.requestFA(2) # request PROFILE. See FaDataTypeEnum.
self.requestFA(3) # request ACCOUNT ALIASES. See FaDataTypeEnum.

self.request_account_summary("All")
self.request_account_pnl("All")
self.request_account_overview("All")
Expand Down

0 comments on commit c7dee3c

Please sign in to comment.