2021-09-15 11:38:21 +00:00
|
|
|
# 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 <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
'''
|
|
|
|
Main app startup and run.
|
|
|
|
|
|
|
|
'''
|
|
|
|
from functools import partial
|
2022-11-15 23:07:02 +00:00
|
|
|
from types import ModuleType
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
from PyQt5.QtCore import QEvent
|
|
|
|
import trio
|
|
|
|
|
|
|
|
from .._daemon import maybe_spawn_brokerd
|
|
|
|
from . import _event
|
|
|
|
from ._exec import run_qtractor
|
|
|
|
from ..data.feed import install_brokerd_search
|
2022-11-15 23:07:02 +00:00
|
|
|
from ..data._source import unpack_fqsn
|
2021-09-15 11:38:21 +00:00
|
|
|
from . import _search
|
|
|
|
from ._chart import GodWidget
|
|
|
|
from ..log import get_logger
|
|
|
|
|
|
|
|
log = get_logger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
async def load_provider_search(
|
2022-11-15 23:07:02 +00:00
|
|
|
brokermod: str,
|
2021-09-15 11:38:21 +00:00
|
|
|
loglevel: str,
|
|
|
|
|
|
|
|
) -> None:
|
|
|
|
|
2022-11-15 23:07:02 +00:00
|
|
|
name = brokermod.name
|
|
|
|
log.info(f'loading brokerd for {name}..')
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
async with (
|
|
|
|
|
|
|
|
maybe_spawn_brokerd(
|
2022-11-15 23:07:02 +00:00
|
|
|
name,
|
2021-09-15 11:38:21 +00:00
|
|
|
loglevel=loglevel
|
|
|
|
) as portal,
|
|
|
|
|
|
|
|
install_brokerd_search(
|
|
|
|
portal,
|
2022-11-15 23:07:02 +00:00
|
|
|
brokermod,
|
2021-09-15 11:38:21 +00:00
|
|
|
),
|
|
|
|
):
|
|
|
|
# keep search engine stream up until cancelled
|
|
|
|
await trio.sleep_forever()
|
|
|
|
|
|
|
|
|
|
|
|
async def _async_main(
|
|
|
|
|
|
|
|
# implicit required argument provided by ``qtractor_run()``
|
|
|
|
main_widget: GodWidget,
|
|
|
|
|
2022-11-07 20:33:52 +00:00
|
|
|
syms: list[str],
|
2022-11-15 23:07:02 +00:00
|
|
|
brokers: dict[str, ModuleType],
|
2021-09-15 11:38:21 +00:00
|
|
|
loglevel: str,
|
|
|
|
|
|
|
|
) -> None:
|
|
|
|
"""
|
|
|
|
Main Qt-trio routine invoked by the Qt loop with the widgets ``dict``.
|
|
|
|
|
|
|
|
Provision the "main" widget with initial symbol data and root nursery.
|
|
|
|
|
|
|
|
"""
|
|
|
|
from . import _display
|
2022-10-31 18:13:02 +00:00
|
|
|
from ._pg_overrides import _do_overrides
|
|
|
|
_do_overrides()
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
godwidget = main_widget
|
|
|
|
|
|
|
|
# attempt to configure DPI aware font size
|
|
|
|
screen = godwidget.window.current_screen()
|
|
|
|
|
|
|
|
# configure graphics update throttling based on display refresh rate
|
2021-09-28 11:56:14 +00:00
|
|
|
_display._quote_throttle_rate = min(
|
2021-09-15 11:38:21 +00:00
|
|
|
round(screen.refreshRate()),
|
2021-09-28 11:56:14 +00:00
|
|
|
_display._quote_throttle_rate,
|
2021-09-15 11:38:21 +00:00
|
|
|
)
|
2021-09-28 11:56:14 +00:00
|
|
|
log.info(f'Set graphics update rate to {_display._quote_throttle_rate} Hz')
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
# TODO: do styling / themeing setup
|
|
|
|
# _style.style_ze_sheets(godwidget)
|
|
|
|
|
|
|
|
sbar = godwidget.window.status_bar
|
|
|
|
starting_done = sbar.open_status('starting ze sexy chartz')
|
|
|
|
|
2022-11-15 23:07:02 +00:00
|
|
|
needed_brokermods: dict[str, ModuleType] = {}
|
|
|
|
for fqsn in syms:
|
|
|
|
brokername, *_ = unpack_fqsn(fqsn)
|
|
|
|
needed_brokermods[brokername] = brokers[brokername]
|
|
|
|
|
2021-09-15 11:38:21 +00:00
|
|
|
async with (
|
|
|
|
trio.open_nursery() as root_n,
|
|
|
|
):
|
|
|
|
# set root nursery and task stack for spawning other charts/feeds
|
|
|
|
# that run cached in the bg
|
|
|
|
godwidget._root_n = root_n
|
|
|
|
|
|
|
|
# setup search widget and focus main chart view at startup
|
|
|
|
# search widget is a singleton alongside the godwidget
|
|
|
|
search = _search.SearchWidget(godwidget=godwidget)
|
2022-09-07 21:50:10 +00:00
|
|
|
# search.bar.unfocus()
|
|
|
|
# godwidget.hbox.addWidget(search)
|
2021-09-15 11:38:21 +00:00
|
|
|
godwidget.search = search
|
|
|
|
|
2022-11-07 20:33:52 +00:00
|
|
|
symbols: list[str] = []
|
|
|
|
|
|
|
|
for sym in syms:
|
|
|
|
symbol, _, provider = sym.rpartition('.')
|
|
|
|
symbols.append(symbol)
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
# this internally starts a ``display_symbol_data()`` task above
|
2022-11-07 20:33:52 +00:00
|
|
|
order_mode_ready = await godwidget.load_symbols(
|
2021-09-15 11:38:21 +00:00
|
|
|
provider,
|
2022-11-07 20:33:52 +00:00
|
|
|
symbols,
|
2021-09-15 11:38:21 +00:00
|
|
|
loglevel
|
|
|
|
)
|
|
|
|
|
|
|
|
# spin up a search engine for the local cached symbol set
|
|
|
|
async with _search.register_symbol_search(
|
|
|
|
|
|
|
|
provider_name='cache',
|
|
|
|
search_routine=partial(
|
|
|
|
_search.search_simple_dict,
|
|
|
|
source=godwidget._chart_cache,
|
|
|
|
),
|
|
|
|
# cache is super fast so debounce on super short period
|
|
|
|
pause_period=0.01,
|
|
|
|
|
|
|
|
):
|
|
|
|
# load other providers into search **after**
|
|
|
|
# the chart's select cache
|
2022-11-15 23:07:02 +00:00
|
|
|
for brokername, mod in needed_brokermods.items():
|
|
|
|
root_n.start_soon(
|
|
|
|
load_provider_search,
|
|
|
|
mod,
|
|
|
|
loglevel,
|
|
|
|
)
|
2021-09-15 11:38:21 +00:00
|
|
|
|
|
|
|
await order_mode_ready.wait()
|
|
|
|
|
|
|
|
# start handling peripherals input for top level widgets
|
|
|
|
async with (
|
|
|
|
|
|
|
|
# search bar kb input handling
|
|
|
|
_event.open_handlers(
|
|
|
|
[search.bar],
|
|
|
|
event_types={
|
|
|
|
QEvent.KeyPress,
|
|
|
|
},
|
|
|
|
async_handler=_search.handle_keyboard_input,
|
|
|
|
filter_auto_repeats=False, # let repeats passthrough
|
|
|
|
),
|
|
|
|
|
|
|
|
# completer view mouse click signal handling
|
|
|
|
_event.open_signal_handler(
|
|
|
|
search.view.pressed,
|
|
|
|
search.view.on_pressed,
|
|
|
|
),
|
|
|
|
):
|
|
|
|
# remove startup status text
|
|
|
|
starting_done()
|
|
|
|
await trio.sleep_forever()
|
|
|
|
|
|
|
|
|
|
|
|
def _main(
|
2022-11-07 20:33:52 +00:00
|
|
|
syms: list[str],
|
2022-11-15 23:07:02 +00:00
|
|
|
brokermods: list[ModuleType],
|
2021-09-15 11:38:21 +00:00
|
|
|
piker_loglevel: str,
|
|
|
|
tractor_kwargs,
|
|
|
|
) -> None:
|
2021-12-07 20:10:37 +00:00
|
|
|
'''
|
|
|
|
Sync entry point to start a chart: a ``tractor`` + Qt runtime
|
|
|
|
entry point
|
2021-09-15 11:38:21 +00:00
|
|
|
|
2021-12-07 20:10:37 +00:00
|
|
|
'''
|
2021-09-15 11:38:21 +00:00
|
|
|
run_qtractor(
|
|
|
|
func=_async_main,
|
2022-11-15 23:07:02 +00:00
|
|
|
args=(
|
|
|
|
syms,
|
|
|
|
{mod.name: mod for mod in brokermods},
|
|
|
|
piker_loglevel,
|
|
|
|
),
|
2022-09-09 00:00:50 +00:00
|
|
|
main_widget_type=GodWidget,
|
2021-09-15 11:38:21 +00:00
|
|
|
tractor_kwargs=tractor_kwargs,
|
|
|
|
)
|