diff --git a/piker/_daemon.py b/piker/_daemon.py
index 999b8fce..e732a15d 100644
--- a/piker/_daemon.py
+++ b/piker/_daemon.py
@@ -426,9 +426,19 @@ async def spawn_brokerd(
# ask `pikerd` to spawn a new sub-actor and manage it under its
# actor nursery
+ modpath = brokermod.__name__
+ broker_enable = [modpath]
+ for submodname in getattr(
+ brokermod,
+ '__enable_modules__',
+ [],
+ ):
+ subpath = f'{modpath}.{submodname}'
+ broker_enable.append(subpath)
+
portal = await _services.actor_n.start_actor(
dname,
- enable_modules=_data_mods + [brokermod.__name__],
+ enable_modules=_data_mods + broker_enable,
loglevel=loglevel,
debug_mode=_services.debug_mode,
**tractor_kwargs
diff --git a/piker/brokers/ib/__init__.py b/piker/brokers/ib/__init__.py
new file mode 100644
index 00000000..877b0667
--- /dev/null
+++ b/piker/brokers/ib/__init__.py
@@ -0,0 +1,54 @@
+# piker: trading gear for hackers
+# Copyright (C) Tyler Goodlet (in stewardship for pikers)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+"""
+Interactive Brokers API backend.
+
+Sub-modules within break into the core functionalities:
+
+- ``broker.py`` part for orders / trading endpoints
+- ``data.py`` for real-time data feed endpoints
+
+- ``client.py`` for the core API machinery which is ``trio``-ized
+ wrapping around ``ib_insync``.
+
+- ``report.py`` for the hackery to build manual pp calcs
+ to avoid ib's absolute bullshit FIFO style position
+ tracking..
+
+"""
+from .client import (
+ get_client,
+ open_history_client,
+ open_symbol_search,
+ stream_quotes,
+ trades_dialogue,
+)
+
+# tractor RPC enable arg
+__enable_modules__: list[str] = [
+ 'client',
+]
+
+# passed to ``tractor.ActorNursery.start_actor()``
+_spawn_kwargs = {
+ 'infect_asyncio': True,
+}
+
+# annotation to let backend agnostic code
+# know if ``brokerd`` should be spawned with
+# ``tractor``'s aio mode.
+_infect_asyncio: bool = True
diff --git a/piker/brokers/ib.py b/piker/brokers/ib/client.py
similarity index 99%
rename from piker/brokers/ib.py
rename to piker/brokers/ib/client.py
index 9b32521f..cbbbd8d4 100644
--- a/piker/brokers/ib.py
+++ b/piker/brokers/ib/client.py
@@ -15,11 +15,8 @@
# along with this program. If not, see .
"""
-Interactive Brokers API backend.
-
-Note the client runs under an ``asyncio`` loop (since ``ib_insync`` is
-built on it) and thus actor aware API calls must be spawned with
-``infected_aio==True``.
+``ib`` core API client machinery; mostly sane wrapping around
+``ib_insync``.
"""
from __future__ import annotations
@@ -61,12 +58,12 @@ import numpy as np
import pendulum
-from .. import config
-from ..log import get_logger, get_console_log
-from ..data._source import base_ohlc_dtype
-from ..data._sharedmem import ShmArray
-from ._util import SymbolNotFound, NoData
-from ..clearing._messages import (
+from piker import config
+from piker.log import get_logger, get_console_log
+from piker.data._source import base_ohlc_dtype
+from piker.data._sharedmem import ShmArray
+from .._util import SymbolNotFound, NoData
+from piker.clearing._messages import (
BrokerdOrder, BrokerdOrderAck, BrokerdStatus,
BrokerdPosition, BrokerdCancel,
BrokerdFill, BrokerdError,
@@ -75,10 +72,7 @@ from ..clearing._messages import (
log = get_logger(__name__)
-# passed to ``tractor.ActorNursery.start_actor()``
-_spawn_kwargs = {
- 'infect_asyncio': True,
-}
+
_time_units = {
's': ' sec',
'm': ' mins',
@@ -118,12 +112,6 @@ _search_conf = {
}
-# annotation to let backend agnostic code
-# know if ``brokerd`` should be spawned with
-# ``tractor``'s aio mode.
-_infect_asyncio: bool = True
-
-
# overrides to sidestep pretty questionable design decisions in
# ``ib_insync``:
class NonShittyWrapper(Wrapper):