commit
be7c4e70f0
|
@ -12,16 +12,34 @@ api_key = ""
|
||||||
secret = ""
|
secret = ""
|
||||||
|
|
||||||
[ib]
|
[ib]
|
||||||
host = "127.0.0.1"
|
hosts = [
|
||||||
|
"127.0.0.1",
|
||||||
|
]
|
||||||
|
# XXX: the order in which ports will be scanned
|
||||||
|
# (by the `brokerd` daemon-actor)
|
||||||
|
# is determined # by the line order here.
|
||||||
|
# TODO: when we eventually spawn gateways in our
|
||||||
|
# container, we can just dynamically allocate these
|
||||||
|
# using IBC.
|
||||||
|
ports = [
|
||||||
|
4002, # gw
|
||||||
|
7497, # tws
|
||||||
|
]
|
||||||
|
|
||||||
ports.gw = 4002
|
# when clients are being scanned this determines
|
||||||
ports.tws = 7497
|
# which clients are preferred to be used for data
|
||||||
ports.order = ["gw", "tws",]
|
# feeds based on the order of account names, if
|
||||||
|
# detected as active on an API client.
|
||||||
|
prefer_data_account = [
|
||||||
|
'paper',
|
||||||
|
'margin',
|
||||||
|
'ira',
|
||||||
|
]
|
||||||
|
|
||||||
accounts.margin = "X0000000"
|
[ib.accounts]
|
||||||
accounts.ira = "X0000000"
|
# the order in which accounts will be selectable
|
||||||
accounts.paper = "XX0000000"
|
# in the order mode UI (if found via clients during
|
||||||
|
# API-app scanning)when a new symbol is loaded.
|
||||||
# the order in which accounts will be selected (if found through
|
paper = "XX0000000"
|
||||||
# `brokerd`) when a new symbol is loaded
|
margin = "X0000000"
|
||||||
accounts_order = ['paper', 'margin', 'ira']
|
ira = "X0000000"
|
||||||
|
|
|
@ -13,4 +13,4 @@ x11vnc \
|
||||||
-autoport 3003 \
|
-autoport 3003 \
|
||||||
# can't use this because of ``asyncvnc`` issue:
|
# can't use this because of ``asyncvnc`` issue:
|
||||||
# https://github.com/barneygale/asyncvnc/issues/1
|
# https://github.com/barneygale/asyncvnc/issues/1
|
||||||
# -passwd "$VNC_SERVER_PASSWORD"
|
# -passwd 'ibcansmbz'
|
||||||
|
|
1054
piker/brokers/ib.py
1054
piker/brokers/ib.py
File diff suppressed because it is too large
Load Diff
|
@ -46,6 +46,7 @@ import numpy as np
|
||||||
|
|
||||||
from ..brokers import get_brokermod
|
from ..brokers import get_brokermod
|
||||||
from .._cacheables import maybe_open_context
|
from .._cacheables import maybe_open_context
|
||||||
|
from ..calc import humanize
|
||||||
from ..log import get_logger, get_console_log
|
from ..log import get_logger, get_console_log
|
||||||
from .._daemon import (
|
from .._daemon import (
|
||||||
maybe_spawn_brokerd,
|
maybe_spawn_brokerd,
|
||||||
|
@ -1183,10 +1184,10 @@ class Feed:
|
||||||
shm: ShmArray
|
shm: ShmArray
|
||||||
mod: ModuleType
|
mod: ModuleType
|
||||||
first_quotes: dict # symbol names to first quote dicts
|
first_quotes: dict # symbol names to first quote dicts
|
||||||
|
|
||||||
_portal: tractor.Portal
|
_portal: tractor.Portal
|
||||||
|
|
||||||
stream: trio.abc.ReceiveChannel[dict[str, Any]]
|
stream: trio.abc.ReceiveChannel[dict[str, Any]]
|
||||||
|
status: dict[str, Any]
|
||||||
|
|
||||||
throttle_rate: Optional[int] = None
|
throttle_rate: Optional[int] = None
|
||||||
|
|
||||||
_trade_stream: Optional[AsyncIterator[dict[str, Any]]] = None
|
_trade_stream: Optional[AsyncIterator[dict[str, Any]]] = None
|
||||||
|
@ -1327,9 +1328,24 @@ async def open_feed(
|
||||||
first_quotes=first_quotes,
|
first_quotes=first_quotes,
|
||||||
stream=stream,
|
stream=stream,
|
||||||
_portal=portal,
|
_portal=portal,
|
||||||
|
status={},
|
||||||
throttle_rate=tick_throttle,
|
throttle_rate=tick_throttle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# fill out "status info" that the UI can show
|
||||||
|
host, port = feed.portal.channel.raddr
|
||||||
|
if host == '127.0.0.1':
|
||||||
|
host = 'localhost'
|
||||||
|
|
||||||
|
feed.status.update({
|
||||||
|
'actor_name': feed.portal.channel.uid[0],
|
||||||
|
'host': host,
|
||||||
|
'port': port,
|
||||||
|
'shm': f'{humanize(feed.shm._shm.size)}',
|
||||||
|
'throttle_rate': feed.throttle_rate,
|
||||||
|
})
|
||||||
|
feed.status.update(init_msg.pop('status', {}))
|
||||||
|
|
||||||
for sym, data in init_msg.items():
|
for sym, data in init_msg.items():
|
||||||
si = data['symbol_info']
|
si = data['symbol_info']
|
||||||
fqsn = data['fqsn'] + f'.{brokername}'
|
fqsn = data['fqsn'] + f'.{brokername}'
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
# piker: trading gear for hackers
|
||||||
|
# Copyright (C) Tyler Goodlet (in stewardship for piker0)
|
||||||
|
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Feed status and controls widget(s) for embedding in a UI-pane.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
from textwrap import dedent
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
# from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
from ._style import _font, _font_small
|
||||||
|
# from ..calc import humanize
|
||||||
|
from ._label import FormatLabel
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ._chart import ChartPlotWidget
|
||||||
|
from ..data.feed import Feed
|
||||||
|
from ._forms import FieldsForm
|
||||||
|
|
||||||
|
|
||||||
|
def mk_feed_label(
|
||||||
|
form: FieldsForm,
|
||||||
|
feed: Feed,
|
||||||
|
chart: ChartPlotWidget,
|
||||||
|
|
||||||
|
) -> FormatLabel:
|
||||||
|
'''
|
||||||
|
Generate a label from feed meta-data to be displayed
|
||||||
|
in a UI sidepane.
|
||||||
|
|
||||||
|
TODO: eventually buttons for changing settings over
|
||||||
|
a feed control protocol.
|
||||||
|
|
||||||
|
'''
|
||||||
|
status = feed.status
|
||||||
|
assert status
|
||||||
|
|
||||||
|
msg = dedent("""
|
||||||
|
actor: **{actor_name}**\n
|
||||||
|
|_ @**{host}:{port}**\n
|
||||||
|
""")
|
||||||
|
|
||||||
|
for key, val in status.items():
|
||||||
|
if key in ('host', 'port', 'actor_name'):
|
||||||
|
continue
|
||||||
|
msg += f'\n|_ {key}: **{{{key}}}**\n'
|
||||||
|
|
||||||
|
feed_label = FormatLabel(
|
||||||
|
fmt_str=msg,
|
||||||
|
# |_ streams: **{symbols}**\n
|
||||||
|
font=_font.font,
|
||||||
|
font_size=_font_small.px_size,
|
||||||
|
font_color='default_lightest',
|
||||||
|
)
|
||||||
|
|
||||||
|
# form.vbox.setAlignment(feed_label, Qt.AlignBottom)
|
||||||
|
# form.vbox.setAlignment(Qt.AlignBottom)
|
||||||
|
_ = chart.height() - (
|
||||||
|
form.height() +
|
||||||
|
form.fill_bar.height()
|
||||||
|
# feed_label.height()
|
||||||
|
)
|
||||||
|
|
||||||
|
feed_label.format(**feed.status)
|
||||||
|
|
||||||
|
return feed_label
|
|
@ -750,12 +750,12 @@ def mk_order_pane_layout(
|
||||||
parent=parent,
|
parent=parent,
|
||||||
fields_schema={
|
fields_schema={
|
||||||
'account': {
|
'account': {
|
||||||
'label': '**account**:',
|
'label': '**accnt**:',
|
||||||
'type': 'select',
|
'type': 'select',
|
||||||
'default_value': ['paper'],
|
'default_value': ['paper'],
|
||||||
},
|
},
|
||||||
'size_unit': {
|
'size_unit': {
|
||||||
'label': '**allocate**:',
|
'label': '**alloc**:',
|
||||||
'type': 'select',
|
'type': 'select',
|
||||||
'default_value': [
|
'default_value': [
|
||||||
'$ size',
|
'$ size',
|
||||||
|
|
|
@ -30,6 +30,7 @@ import uuid
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from .. import config
|
from .. import config
|
||||||
from ..clearing._client import open_ems, OrderBook
|
from ..clearing._client import open_ems, OrderBook
|
||||||
|
@ -37,6 +38,7 @@ from ..clearing._allocate import (
|
||||||
mk_allocator,
|
mk_allocator,
|
||||||
Position,
|
Position,
|
||||||
)
|
)
|
||||||
|
from ._style import _font
|
||||||
from ..data._source import Symbol
|
from ..data._source import Symbol
|
||||||
from ..data.feed import Feed
|
from ..data.feed import Feed
|
||||||
from ..log import get_logger
|
from ..log import get_logger
|
||||||
|
@ -46,7 +48,8 @@ from ._position import (
|
||||||
PositionTracker,
|
PositionTracker,
|
||||||
SettingsPane,
|
SettingsPane,
|
||||||
)
|
)
|
||||||
from ._label import FormatLabel
|
from ._forms import FieldsForm
|
||||||
|
# from ._label import FormatLabel
|
||||||
from ._window import MultiStatus
|
from ._window import MultiStatus
|
||||||
from ..clearing._messages import Order, BrokerdPosition
|
from ..clearing._messages import Order, BrokerdPosition
|
||||||
from ._forms import open_form_input_handling
|
from ._forms import open_form_input_handling
|
||||||
|
@ -639,63 +642,21 @@ async def open_order_mode(
|
||||||
pp_tracker.hide_info()
|
pp_tracker.hide_info()
|
||||||
|
|
||||||
# setup order mode sidepane widgets
|
# setup order mode sidepane widgets
|
||||||
form = chart.sidepane
|
form: FieldsForm = chart.sidepane
|
||||||
vbox = form.vbox
|
form.vbox.setSpacing(
|
||||||
|
|
||||||
from textwrap import dedent
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
|
|
||||||
from ._style import _font, _font_small
|
|
||||||
from ..calc import humanize
|
|
||||||
|
|
||||||
feed_label = FormatLabel(
|
|
||||||
fmt_str=dedent("""
|
|
||||||
actor: **{actor_name}**\n
|
|
||||||
|_ @**{host}:{port}**\n
|
|
||||||
|_ throttle_hz: **{throttle_rate}**\n
|
|
||||||
|_ streams: **{symbols}**\n
|
|
||||||
|_ shm: **{shm}**\n
|
|
||||||
"""),
|
|
||||||
font=_font.font,
|
|
||||||
font_size=_font_small.px_size,
|
|
||||||
font_color='default_lightest',
|
|
||||||
)
|
|
||||||
|
|
||||||
form.feed_label = feed_label
|
|
||||||
|
|
||||||
# add feed info label to top
|
|
||||||
vbox.insertWidget(
|
|
||||||
0,
|
|
||||||
feed_label,
|
|
||||||
alignment=Qt.AlignBottom,
|
|
||||||
)
|
|
||||||
# vbox.setAlignment(feed_label, Qt.AlignBottom)
|
|
||||||
# vbox.setAlignment(Qt.AlignBottom)
|
|
||||||
_ = chart.height() - (
|
|
||||||
form.height() +
|
|
||||||
form.fill_bar.height()
|
|
||||||
# feed_label.height()
|
|
||||||
)
|
|
||||||
vbox.setSpacing(
|
|
||||||
int((1 + 5/8)*_font.px_size)
|
int((1 + 5/8)*_font.px_size)
|
||||||
)
|
)
|
||||||
|
|
||||||
# fill in brokerd feed info
|
from ._feedstatus import mk_feed_label
|
||||||
host, port = feed.portal.channel.raddr
|
|
||||||
if host == '127.0.0.1':
|
feed_label = mk_feed_label(
|
||||||
host = 'localhost'
|
form,
|
||||||
mpshm = feed.shm._shm
|
feed,
|
||||||
shmstr = f'{humanize(mpshm.size)}'
|
chart,
|
||||||
form.feed_label.format(
|
|
||||||
actor_name=feed.portal.channel.uid[0],
|
|
||||||
host=host,
|
|
||||||
port=port,
|
|
||||||
symbols=len(feed.symbols),
|
|
||||||
shm=shmstr,
|
|
||||||
throttle_rate=feed.throttle_rate,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# XXX: we set this because?
|
||||||
|
form.feed_label = feed_label
|
||||||
order_pane = SettingsPane(
|
order_pane = SettingsPane(
|
||||||
form=form,
|
form=form,
|
||||||
# XXX: ugh, so hideous...
|
# XXX: ugh, so hideous...
|
||||||
|
@ -706,6 +667,11 @@ async def open_order_mode(
|
||||||
)
|
)
|
||||||
order_pane.set_accounts(list(trackers.keys()))
|
order_pane.set_accounts(list(trackers.keys()))
|
||||||
|
|
||||||
|
form.vbox.addWidget(
|
||||||
|
feed_label,
|
||||||
|
alignment=Qt.AlignBottom,
|
||||||
|
)
|
||||||
|
|
||||||
# update pp icons
|
# update pp icons
|
||||||
for name, tracker in trackers.items():
|
for name, tracker in trackers.items():
|
||||||
order_pane.update_account_icons({name: tracker.live_pp})
|
order_pane.update_account_icons({name: tracker.live_pp})
|
||||||
|
|
|
@ -15,3 +15,7 @@
|
||||||
|
|
||||||
# ``trimeter`` for asysnc history fetching
|
# ``trimeter`` for asysnc history fetching
|
||||||
-e git+https://github.com/python-trio/trimeter.git@master#egg=trimeter
|
-e git+https://github.com/python-trio/trimeter.git@master#egg=trimeter
|
||||||
|
|
||||||
|
|
||||||
|
# ``asyncvnc`` for sending interactions to ib-gw inside docker
|
||||||
|
-e git+https://github.com/pikers/asyncvnc.git@vid_passthrough#egg=asyncvnc
|
||||||
|
|
Loading…
Reference in New Issue