[profitpy commit] r315 - in trunk: . profit/lib profit/lib/widgets profit/workbench profit/workbench/widgets

0 views
Skip to first unread message

codesite...@google.com

unread,
Jul 29, 2008, 4:45:03 AM7/29/08
to profitp...@googlegroups.com
Author: troy.melhase
Date: Tue Jul 29 01:44:30 2008
New Revision: 315

Added:
trunk/profit/lib/widgets/propertyeditor.py (contents, props changed)
trunk/profit/lib/widgets/tickfieldselect.py (contents, props changed)
trunk/profit/lib/widgets/ui_propertyeditor.ui (contents, props changed)
trunk/profit/lib/widgets/ui_tickfieldselect.ui (contents, props changed)
Modified:
trunk/README
trunk/profit/lib/__init__.py
trunk/profit/lib/defaults.py
trunk/profit/lib/gui.py
trunk/profit/lib/widgets/localtable.py
trunk/profit/workbench/main.py
trunk/profit/workbench/tickerdisplay.py
trunk/profit/workbench/tickerplotdisplay.py
trunk/profit/workbench/widgets/ui_tickerdisplay.ui

Log:
Initial implementation of ticker display field selector.

Modified: trunk/README
==============================================================================
--- trunk/README (original)
+++ trunk/README Tue Jul 29 01:44:30 2008
@@ -1,5 +1,14 @@
== To Do for 0.2 ==

+1. add buffer editor to shell panel. perhaps update shell w/ code
from eric4
+
+2. add ticker field select widget to ticker display; make splitter like
+ the message display
+
+3. fix method request/tickerId/contract handling. allow for display
+ of tickerIds with symbol. extend tickers display with contract
+ details.
+
4. add viewable historical data requests and plots

5. finish strategy design tool and its integration with the workbench

Modified: trunk/profit/lib/__init__.py
==============================================================================
--- trunk/profit/lib/__init__.py (original)
+++ trunk/profit/lib/__init__.py Tue Jul 29 01:44:30 2008
@@ -180,6 +180,7 @@
winstate = 'State'
ctabstate = 'CentralTabState'
externalbrowser = 'ExternalBrowser'
+ tickerdisplay = 'TickerDisplay'

def __init__(self):
""" Initializer.
@@ -204,7 +205,8 @@
if v:
try:
v = loads(str(v.toString()))
- except:
+ except (Exception, ), exc:
+ logging.debug('Exception valueLoad: %s, %r', exc, exc)
v = default
return v

@@ -238,6 +240,7 @@
urlTitle = nextUserRole()
strategyName = nextUserRole()
displayImportName = nextUserRole()
+ tickerField = nextUserRole()


class SessionHandler(object):
@@ -317,3 +320,7 @@
self.settingsRef = value

settings = property(settingsGetter, settingsSetter)
+
+
+class BasicHandler(SessionHandler, SettingsHandler):
+ pass

Modified: trunk/profit/lib/defaults.py
==============================================================================
--- trunk/profit/lib/defaults.py (original)
+++ trunk/profit/lib/defaults.py Tue Jul 29 01:44:30 2008
@@ -68,3 +68,7 @@
@return QByteArray suitable for use with QSplitter.restoreState
"""
return QByteArray.fromBase64('AAAA/wAAAAAAAAACAAAAiQAAAm8BAAAABgEAAAAB')
+
+
+def tickerDisplayFields():
+ return range(-3, 5)

Modified: trunk/profit/lib/gui.py
==============================================================================
--- trunk/profit/lib/gui.py (original)
+++ trunk/profit/lib/gui.py Tue Jul 29 01:44:30 2008
@@ -12,76 +12,42 @@
from profit.lib import DataRoles, Signals, valueAlign


-class ValueColorItem(object):
- increase = QBrush(QColor(Qt.darkGreen))
- neutral = QBrush(QColor(Qt.blue))
- decrease = QBrush(QColor(Qt.red))
- compMap = {1:increase, -1:decrease, 0:neutral}
-
- @classmethod
- def setColors(cls, increase, neutral, decrease):
- cls.increase = QBrush(increase)
- cls.neutral = QBrush(neutral)
- cls.decrease = QBrush(decrease)
-
-
-class ValueTableItem(QTableWidgetItem, ValueColorItem):
- """ Table item that changes colors based on value changes.
+def addCloseAction(widget):
+ """ Adds a close action and connects it to the widget close slot.

+ @param widget any QWidget instance
+ @return new QAction instance
"""
- def __init__(self):
- """ Constructor.
+ action = QAction('Close', widget)
+ action.setShortcut('Ctrl+W')
+ widget.addAction(action)
+ widget.connect(action, Signals.triggered, widget.close)
+ return action

- """
- QTableWidgetItem.__init__(self, self.UserType)
- self.setFlags(self.flags() & ~Qt.ItemIsEditable)
- self.value = None

- def setValue(self, value):
- """ Sets value of item and updates text color (if possible).
+def complementColor(color):
+ """ Generates a complementary color for the given string.

- @param string or number to set
- @return None
- """
- try:
- value = float(value)
- except (ValueError, ):
- self.setText(value)
- return
- current = self.value
- if current is None:
- self.value = value
- self.setText(str(value))
- return
- if value < current:
- self.setForeground(self.decrease)
- elif value > current:
- self.setForeground(self.increase)
- else:
- self.setForeground(self.neutral)
- self.value = value
- self.setText(str(value))
-
- def setSymbol(self, symbol):
- """ Sets the text and icon for a symbol-based item.
+ @param color QColor instance
+ @return QColor with complementary value
+ """
+ hx = str(color.name())[1:]
+ comp = ['%.2X' % (255 - int(a, 16)) for a in (hx[0:2], hx[2:4], hx[4:6])]
+ return QColor('#' + str.join('', comp))

- @param symbol ticker symbol as string
- @return None
- """
- icon = symbolIcon(symbol)
- self.setIcon(icon)
- self.setText(symbol)

- def setValueAlign(self, alignment=valueAlign):
- """ Sets the text alignment of this item.
+def makeUrlAction(text, url, toolTip='', parent=None):
+ action = QAction(text + '...', parent)
+ action.setData(QVariant(url))
+ action.setToolTip(toolTip)
+ return action

- @param alignment Qt alignment flags
- @return None
- """
- self.setTextAlignment(alignment)

- def setText(self, text):
- QTableWidgetItem.setText(self, str(text))
+def makeUrlItem(v):
+ item = QStandardItem(v)
+ item.setData(QVariant(v), DataRoles.url)
+ item.setData(QVariant(''), DataRoles.urlTitle)
+ return item


def colorIcon(color, width=10, height=10):
@@ -97,6 +63,12 @@
return QIcon(pixmap)


+def separator():
+ sep = QAction(None)
+ sep.setSeparator(True)
+ return sep
+
+
def symbolIcon(symbol):
""" Icon for a symbol.

@@ -115,10 +87,24 @@
return QMessageBox.warning(None, title, text, QMessageBox.Close)


-def complementColor(c):
- hx = str(c.name())[1:]
- comp = ['%.2X' % (255 - int(a, 16)) for a in (hx[0:2], hx[2:4], hx[4:6])]
- return QColor('#' + str.join('', comp))
+class StandardItem(QStandardItem):
+ """ Convenience QStandardItem subclass with many init keywords.
+
+ """
+
+ def __init__(self, text='', editable=False,
+ checkState=Qt.Unchecked, checkable=False,
+ enabled=False, icon=None, alignment=None):
+ QStandardItem.__init__(self, text)
+ self.setEditable(editable)
+ self.setEnabled(enabled)
+ self.setCheckable(checkable)
+ if checkable:
+ self.setCheckState(checkState)
+ if icon:
+ self.setIcon(icon)
+ if alignment is not None:
+ self.setTextAlignment(alignment)


class UrlRequestor(object):
@@ -142,50 +128,73 @@
self.emit(Signals.openUrl, item)


-class StandardItem(QStandardItem):
- """ Convenience QStandardItem subclass with many init keywords.
+class ValueColorItem(object):
+ increase = QBrush(QColor(Qt.darkGreen))
+ neutral = QBrush(QColor(Qt.blue))
+ decrease = QBrush(QColor(Qt.red))
+ compMap = {1:increase, -1:decrease, 0:neutral}

- """
+ @classmethod
+ def setColors(cls, increase, neutral, decrease):
+ cls.increase = QBrush(increase)
+ cls.neutral = QBrush(neutral)
+ cls.decrease = QBrush(decrease)

- def __init__(self, text='', editable=False,
- checkState=Qt.Unchecked, checkable=False,
- enabled=False, icon=None, alignment=None):
- QStandardItem.__init__(self, text)
- self.setEditable(editable)
- self.setEnabled(enabled)
- self.setCheckable(checkable)
- if checkable:
- self.setCheckState(checkState)
- if icon:
- self.setIcon(icon)
- if alignment is not None:
- self.setTextAlignment(alignment)

+class ValueTableItem(QTableWidgetItem, ValueColorItem):
+ """ Table item that changes colors based on value changes.

-def separator():
- sep = QAction(None)
- sep.setSeparator(True)
- return sep
+ """
+ def __init__(self):
+ """ Constructor.

+ """
+ QTableWidgetItem.__init__(self, self.UserType)
+ self.setFlags(self.flags() & ~Qt.ItemIsEditable)
+ self.value = None

-def addCloseAction(parent):
- action = QAction('Close', parent)
- action.setShortcut('Ctrl+W')
- parent.addAction(action)
- parent.connect(action, Signals.triggered, parent.close)
- return action
+ def setValue(self, value):
+ """ Sets value of item and updates text color (if possible).

+ @param string or number to set
+ @return None
+ """
+ try:
+ value = float(value)
+ except (ValueError, ):
+ self.setText(value)
+ return
+ current = self.value
+ if current is None:
+ self.value = value
+ self.setText(str(value))
+ return
+ if value < current:
+ self.setForeground(self.decrease)
+ elif value > current:
+ self.setForeground(self.increase)
+ else:
+ self.setForeground(self.neutral)
+ self.value = value
+ self.setText(str(value))

-def makeUrlAction(text, url, toolTip='', parent=None):
- action = QAction(text + '...', parent)
- action.setData(QVariant(url))
- action.setToolTip(toolTip)
- return action
+ def setSymbol(self, symbol):
+ """ Sets the text and icon for a symbol-based item.

+ @param symbol ticker symbol as string
+ @return None
+ """
+ icon = symbolIcon(symbol)
+ self.setIcon(icon)
+ self.setText(symbol)

-def makeUrlItem(v):
- item = QStandardItem(v)
- item.setData(QVariant(v), DataRoles.url)
- item.setData(QVariant(''), DataRoles.urlTitle)
- return item
+ def setValueAlign(self, alignment=valueAlign):
+ """ Sets the text alignment of this item.
+
+ @param alignment Qt alignment flags
+ @return None
+ """
+ self.setTextAlignment(alignment)

+ def setText(self, text):
+ QTableWidgetItem.setText(self, str(text))

Modified: trunk/profit/lib/widgets/localtable.py
==============================================================================
--- trunk/profit/lib/widgets/localtable.py (original)
+++ trunk/profit/lib/widgets/localtable.py Tue Jul 29 01:44:30 2008
@@ -14,7 +14,7 @@
QTableWidget.__init__(self, parent)
self.resizedColumns = []

- def resizeColumnToContents(self, column):
+ def __resizeColumnToContents(self, column):
if column not in self.resizedColumns:
self.resizedColumns.append(column)
QTableWidget.resizeColumnToContents(self, column)

Added: trunk/profit/lib/widgets/propertyeditor.py
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/propertyeditor.py Tue Jul 29 01:44:30 2008
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2007 Troy Melhase <tr...@gci.net>
+# Distributed under the terms of the GNU General Public License v2
+
+from PyQt4.QtCore import Qt, pyqtSignature
+from PyQt4.QtGui import QFrame, QStandardItemModel
+
+from ib.opt.message import messageTypeNames
+
+from profit.lib.gui import StandardItem
+from profit.lib.widgets.ui_propertyeditor import Ui_PropertyEditor
+
+
+class PropertyEditorModel(QStandardItemModel):
+ labels = ['Property', 'Value', ]
+
+ def __init__(self, widget, parent=None):
+ QStandardItemModel.__init__(self, parent)
+ self.setHorizontalHeaderLabels(self.labels)
+ items = [(name, getattr(widget, name)) for name in dir(widget)
+ if not name.startswith('_')]
+ for name, value in sorted(items):
+ self.appendRow(self.makeRowItems(name, value))
+
+ def makeRowItems(self, key, value):
+ return [StandardItem(key, enabled=True),
+ StandardItem(str(value), enabled=True), ]
+
+
+class PropertyEditor(QFrame, Ui_PropertyEditor):
+ """ PropertyEditor -> just a viewer right now.
+
+ """
+ def __init__(self, parent=None):
+ """ Initializer.
+
+ @param parent ancestor object
+ """
+ QFrame.__init__(self, parent)
+ self.setupUi(self)
+
+ def setFromWidget(self, widget):
+ widgetType = type(widget)
+ widgetName = widget.objectName()
+ self.nameLabel.setText('Name: ' + widgetName)
+ self.classLabel.setText('Type: ' + widgetType.__name__)
+ self.model = PropertyEditorModel(widget, self)
+
+ view = self.propertyTableView
+ view.reset()
+ view.setModel(self.model)
+ view.verticalHeader().hide()
+ view.resizeColumnsToContents()
+

Added: trunk/profit/lib/widgets/tickfieldselect.py
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/tickfieldselect.py Tue Jul 29 01:44:30 2008
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2007 Troy Melhase <tr...@gci.net>
+# Distributed under the terms of the GNU General Public License v2
+
+from re import split as rxsplit
+
+from PyQt4.QtCore import Qt, QVariant, pyqtSignature
+from PyQt4.QtGui import QFrame, QStandardItem
+
+from ib.ext.TickType import TickType
+from profit.lib import DataRoles
+from profit.lib.widgets.ui_tickfieldselect import Ui_TickFieldSelect
+
+
+def itemTickField(item):
+ """ Returns the tick field from the item's data
+
+ """
+ return item.data(DataRoles.tickerField).toInt()[0]
+
+
+def setItemTickField(item, field):
+ """ Sets the tick field role on the item.
+
+ """
+ item.setData(DataRoles.tickerField, QVariant(field))
+
+
+def fieldIds():
+ """ Generates sequence of tick field identifiers. Refer to the
+ TickType class for concrete list.
+
+ """
+ for field in fieldSpecs():
+ yield field['value']
+
+
+def fieldSpecs():
+ """ Yields one description dict for every TickType field.
+
+ """
+ values = [getattr(TickType, k) for k in dir(TickType)]
+ for value in [v for v in values if isinstance(v, int)]:
+ name = TickType.getField(value)
+ title = tickFieldTitle(name)
+ yield dict(sort=value, value=value, name=name, title=title)
+
+
+def tickFieldTitle(name):
+ """ Make title from name, aka UnCapCase.
+
+ """
+ words = rxsplit('([A-Z0-9][a-z]+)', name)
+ ## my rx fu isn't great enough. special case for when the split
+ ## does not work, e.g., bidEFP.
+ if len(words) == 1:
+ words = rxsplit('([a-z]+)', name)
+ ## title case each word in the word list if the word isn't already
+ ## all upper case.
+ words = [(word.title() if not word.upper()==word else word)
+ for word in words if word]
+ return str.join(' ', words)
+
+
+def extraFieldSpecs():
+ yield dict(sort=-4, value=-4, name='id', title='Id')
+ yield dict(sort=-3, value=-3, name='symbol', title='Symbol')
+ yield dict(sort=-2, value=-2, name='position', title='Position')
+ yield dict(sort=-1, value=-1, name='value', title='Value')
+
+
+class TickFieldSelect(QFrame, Ui_TickFieldSelect):
+ """ TickFieldSelect -> widget for selecting various tick fields.
+
+ """
+ def __init__(self, parent=None):
+ """ Initializer.
+
+ @param parent ancestor object
+ """
+ QFrame.__init__(self, parent)
+ self.setupUi(self)
+ self.setupFieldsList()
+
+ def setupFieldsList(self):
+ """ Clears and fills the fields list.
+
+ """
+ fieldsList = self.fieldsList
+ fieldsList.clear()
+ allFields = sorted(list(extraFieldSpecs()) + list(fieldSpecs()),
+ key=lambda d:d['sort'])
+ self.allTickFields = allFields
+
+ for rowId, fieldDesc in enumerate(allFields):
+ fieldsList.addItem(fieldDesc['title'])
+ item = fieldsList.item(rowId)
+ setItemTickField(item, fieldDesc['value'])
+ item.setCheckState(Qt.Unchecked)
+
+ def setCheckedFields(self, fields):
+ """
+
+ """
+ for item in self.listItems():
+ field = itemTickField(item)
+ if field in fields:
+ item.setCheckState(Qt.Checked)
+
+ def listItems(self):
+ """ Returns the QStandardItems in the fields list.
+
+ """
+ listWidget = self.fieldsList
+ return [listWidget.item(r) for r in range(listWidget.count())]
+
+ def checkedItems(self):
+ """ Returns list of seleected fields names (as strings)
+
+ """
+ return [i for i in self.listItems() if i.checkState()==Qt.Checked]
+
+
+ @pyqtSignature('')
+ def on_checkNoneButton_clicked(self):
+ """ Unchecks every item in the fields list.
+
+ """
+ for item in self.listItems():
+ item.setCheckState(Qt.Unchecked)
+
+ @pyqtSignature('')
+ def on_checkAllButton_clicked(self):
+ """ Checks every item in the fields list.
+
+ """
+ for item in self.listItems():
+ item.setCheckState(Qt.Checked)
+
+
+

Added: trunk/profit/lib/widgets/ui_propertyeditor.ui
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/ui_propertyeditor.ui Tue Jul 29 01:44:30 2008
@@ -0,0 +1,80 @@
+<ui version="4.0" >
+ <class>PropertyEditor</class>
+ <widget class="QWidget" name="PropertyEditor" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>401</width>
+ <height>429</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Property Editor</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="nameLabel" >
+ <property name="text" >
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="2" row="0" column="1" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item rowspan="2" row="1" column="0" >
+ <widget class="QLabel" name="classLabel" >
+ <property name="text" >
+ <string>Class:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <spacer name="horizontalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTableView" name="propertyTableView" >
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="gridStyle" >
+ <enum>Qt::DotLine</enum>
+ </property>
+ <property name="sortingEnabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

Added: trunk/profit/lib/widgets/ui_tickfieldselect.ui
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/ui_tickfieldselect.ui Tue Jul 29 01:44:30 2008
@@ -0,0 +1,77 @@
+<ui version="4.0" >
+ <class>TickFieldSelect</class>
+ <widget class="QWidget" name="TickFieldSelect" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>434</width>
+ <height>325</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Select Ticker Fields</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="fieldsListText" >
+ <property name="text" >
+ <string>Show these fields:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="fieldsList" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>16</width>
+ <height>26</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="checkAllButton" >
+ <property name="text" >
+ <string>Check All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="checkNoneButton" >
+ <property name="text" >
+ <string>Check None</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <zorder>fieldsList</zorder>
+ <zorder>fieldsListText</zorder>
+ <zorder></zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

Modified: trunk/profit/workbench/main.py
==============================================================================
--- trunk/profit/workbench/main.py (original)
+++ trunk/profit/workbench/main.py Tue Jul 29 01:44:30 2008
@@ -28,6 +28,7 @@

from profit.lib.widgets.dock import Dock
from profit.lib.widgets.output import OutputWidget
+from profit.lib.widgets.propertyeditor import PropertyEditor
from profit.lib.widgets.shell import PythonShell

from profit.workbench.widgets.ui_main import Ui_ProfitWorkbenchWindow
@@ -96,6 +97,27 @@
self.actionSaveSession.trigger()
return check

+ def on_inspectWidget(self, checked=False, widget=None):
+ objectType, objectName = type(widget), widget.objectName()
+ self.propertyEditor.widget().setFromWidget(widget)
+
+ def contextMenuActions(self, event):
+ app = instance()
+ widget = app.widgetAt(event.globalPos())
+ if widget is None:
+ return
+ inspectCall = partial(self.on_inspectWidget, widget=widget)
+ actionText = 'Inspect %s:%s' % (type(widget).__name__, widget.objectName())
+ inspectAction = QAction(actionText, self)
+ self.connect(inspectAction, Signals.triggered, inspectCall)
+ return [inspectAction, ]
+
+ def contextMenuEvent(self, event):
+ menu = QMenu()
+ actions = self.contextMenuActions(event)
+ QMenu.exec_(actions, event.globalPos())
+ event.accept()
+
def closeEvent(self, event):
if self.checkClose():
try:
@@ -387,8 +409,8 @@
bottom = Qt.BottomDockWidgetArea
tabify = self.tabifyDockWidget
self.sessionDock = Dock('Session', self, SessionTree)
- self.anyWidget = Dock('Empty', self, QFrame)
- tabify(self.anyWidget, self.sessionDock)
+ self.propertyEditor = Dock('Property Editor', self, PropertyEditor)
+ tabify(self.propertyEditor, self.sessionDock)
self.stdoutDock = Dock('Standard Output', self, OutputWidget, bottom)
self.stderrDock = Dock('Standard Error', self, OutputWidget, bottom)
makeShell = partial(

Modified: trunk/profit/workbench/tickerdisplay.py
==============================================================================
--- trunk/profit/workbench/tickerdisplay.py (original)
+++ trunk/profit/workbench/tickerdisplay.py Tue Jul 29 01:44:30 2008
@@ -4,6 +4,9 @@
# Copyright 2007 Troy Melhase <tr...@gci.net>
# Distributed under the terms of the GNU General Public License v2

+# TODO: cache previous values on column drop and reuse on add.
+# TODO: support id, symbol, position and value fields
+
from functools import partial
from itertools import ifilter
from string import Template
@@ -11,27 +14,19 @@
from PyQt4.QtCore import QVariant, Qt, pyqtSignature
from PyQt4.QtGui import QAction, QFrame, QIcon, QMenu

-from ib.ext.TickType import TickType
from ib.opt.message import TickPrice

-from profit.lib import (SessionHandler, SettingsHandler, Signals,
- makeCheckNames, DataRoles, defaults, instance, )
+from profit.lib import (BasicHandler, DataRoles, Signals, defaults,
+ instance, makeCheckNames, )
+
from profit.lib.gui import (UrlRequestor, ValueTableItem, separator,
makeUrlAction, )
-from profit.workbench.portfoliodisplay import replayPortfolio
-from profit.workbench.widgets.ui_tickerdisplay import Ui_TickerDisplay

+from profit.lib.widgets.tickfieldselect import (fieldIds, itemTickField,
+ setItemTickField, )

-##
-# Our map of TickType fields to column numbers
-fieldColumns = {
- TickType.ASK_SIZE : 3,
- TickType.ASK : 4,
- TickType.BID_SIZE : 5,
- TickType.BID : 6,
- TickType.LAST_SIZE : 7,
- TickType.LAST : 8,
- }
+from profit.workbench.portfoliodisplay import replayPortfolio
+from profit.workbench.widgets.ui_tickerdisplay import Ui_TickerDisplay


def replayTickerMessages(messages, symbols, callback):
@@ -44,7 +39,7 @@
"""
isMsg = makeCheckNames('TickSize', 'TickPrice')
for symbol, tickerId in symbols.items():
- for field in fieldColumns.keys():
+ for field in fieldIds():
def pred((t, m)):
return isMsg(m) and m.field==field and m.tickerId==tickerId
for time, message in ifilter(pred, reversed(messages)):
@@ -59,12 +54,11 @@
@return None
"""
tick = partial(TickPrice, tickerId=tickerId, price=0, canAutoExecute=False)
- for field in fieldColumns:
+ for field in fieldIds():
yield tick(field=field)


-class TickerDisplay(QFrame, Ui_TickerDisplay, SessionHandler,
- SettingsHandler, UrlRequestor):
+class TickerDisplay(QFrame, Ui_TickerDisplay, BasicHandler, UrlRequestor):
""" TickerDisplay -> shows ticker data in a nice table.

"""
@@ -76,13 +70,41 @@
"""
QFrame.__init__(self, parent)
self.setupUi(self)
- self.tickerItems = {}
- self.tickerTable.verticalHeader().hide()
+ self.headerItemColumnMap = {}
+ self.tickerIds = {}
+ self.setupWidgets()
+ self.requestSession()
+
+ def setupWidgets(self):
+ """ Make our widgets like we like.
+
+ """
+ settings = self.settings
+ settings.beginGroup(self.__class__.__name__)
+ defaultFields = defaults.tickerDisplayFields()
+ userFields = settings.valueLoad('selectedFields', defaultFields)
+ self.tickFieldSelect.setCheckedFields(userFields)
+ defaultState = defaults.rightMainSplitterState()
+ splitState = settings.value(settings.keys.splitstate, defaultState)
+ self.splitter.restoreState(splitState.toByteArray())
+ settings.endGroup()
app = instance()
connect = self.connect
connect(self, Signals.openUrl, app, Signals.openUrl)
connect(self, Signals.tickerClicked, app, Signals.tickerClicked)
- self.requestSession()
+ self.tickerTable.verticalHeader().hide()
+
+ def on_splitter_splitterMoved(self, pos, index):
+ """ Signal handler for splitter move; saves state to user settings.
+
+ @param pos ignored
+ @param index ignored
+ @return None
+ """
+ settings = self.settings
+ settings.beginGroup(self.__class__.__name__)
+ settings.setValue(settings.keys.splitstate, self.splitter.saveState())
+ settings.endGroup()

def setSession(self, session):
""" Configures this instance for a session.
@@ -93,7 +115,7 @@
self.session = session
symbols = session.strategy.symbols()
replayTickerMessages(session.messages, symbols,
- self.on_session_TickPrice_TickSize)
+ self.on_session_TickPrice_TickSize)
replayPortfolio(session.messages, self.on_session_UpdatePortfolio)
session.registerMeta(self)
if not session.messages:
@@ -189,6 +211,48 @@
"""
print '## order for ', self.actionOrder.data().toString()

+ def tickerTableColumns(self):
+ t = self.tickerTable
+ return [(c, t.horizontalHeaderItem(c))
+ for c in range(t.columnCount())]
+
+ def tickerTableColumnField(self, field):
+ t = self.tickerTable
+ for c in range(t.columnCount()):
+ i = t.horizontalHeaderItem(c)
+ if field == itemTickField(i):
+ return c
+
+ def on_fieldsList_itemChanged(self, item):
+ """ Add/drop a column when a field is checked/unchecked.
+
+ """
+ headerItemColumnMap = self.headerItemColumnMap
+ tickerTable = self.tickerTable
+ userItems = self.tickFieldSelect.checkedItems()
+ field = itemTickField(item)
+
+ if item.checkState():
+ col = tickerTable.columnCount()
+ tickerTable.insertColumn(col)
+ header = headerItemColumnMap[field] = ValueTableItem()
+ header.setText(item.text())
+ setItemTickField(header, field)
+ tickerTable.setHorizontalHeaderItem(col, header)
+ for r in range(tickerTable.rowCount()):
+ tickerTable.setItem(r, col, TickerTableItem())
+ else:
+ headers = self.tickerTableColumns()
+ col = [c for c, i in headers if itemTickField(i)==field][0]
+ tickerTable.removeColumn(col)
+ del(headerItemColumnMap[field])
+
+ settings = self.settings
+ settings.beginGroup(self.__class__.__name__)
+ saveFields = [itemTickField(i) for i in userItems]
+ settings.setValueDump('selectedFields', saveFields)
+ settings.endGroup()
+
def on_tickerTable_customContextMenuRequested(self, pos):
""" Display a context menu over the ticker table.

@@ -236,7 +300,7 @@
symbols = self.session.strategy.symbols()
try:
tid = symbols[sym]
- items = self.tickerItems[tid]
+ items = self.tickerIds[tid]
except (KeyError, ):
pass
else:
@@ -248,19 +312,50 @@
Creates rows as needed.

"""
- tid = message.tickerId
table = self.tickerTable
+ if not table.columnCount():
+ return
+ tickerId = message.tickerId
+ value = (message.price if hasattr(message, 'price') else message.size)
try:
- value = message.price
- except (AttributeError, ):
- value = message.size
- try:
- items = self.tickerItems[tid]
+ row = self.tickerIds[tickerId]
except (KeyError, ):
- items = self.tickerItems[tid] = table.newItemsRow()
+ items = table.newItemsRow()
+ #for item in items:
+ # item.setValueAlign()
+ row = self.tickerIds[tickerId] = items[0].row()
+ col = self.tickerTableColumnField(message.field)
+ if col is None:
+ return
+ item = table.item(row, col)
+ if not hasattr(item, 'setValue'):
+ return
+ if item:
+ item.setValue(value)
+
+
+class TickerTableItem(ValueTableItem):
+ """ Automatically aligned value table items.
+
+ """
+ def __init__(self):
+ ValueTableItem.__init__(self)
+ self.setValueAlign()
+
+
+
+
+
+
+ #table.resizeColumnsToContents()
+ #table.resizeRowsToContents()
+
+if 0:
+ if 0:
+ if 0:
symbols = self.session.strategy.symbols()
try:
- sym = dict([(b, a) for a, b in symbols.items()])[tid]
+ sym = dict([(b, a) for a, b in symbols.items()])[tickerId]
except (KeyError, ):
## something wrong -- we don't have data for the
## ticker symbol. this can happen if the connection
@@ -268,16 +363,15 @@
## loaded with the symbol (tickerId) defined. how can
## this be fixed?
return
- items[0].setSymbol(sym)
- items[0].tickerId = tid
- for item in items[1:]:
- item.setValueAlign()
- table.sortItems(0)
- table.resizeColumnsToContents()
- table.resizeRowsToContents()
- try:
- index = fieldColumns[message.field]
- except (KeyError, ):
- pass
- else:
- items[index].setValue(value)
+
+
+
+
+# items[0].setSymbol(sym)
+# items[0].tickerId = tid
+# for item in items[1:]:
+# item.setValueAlign()
+# table.sortItems(0)
+# table.resizeColumnsToContents()
+# table.resizeRowsToContents()
+

Modified: trunk/profit/workbench/tickerplotdisplay.py
==============================================================================
--- trunk/profit/workbench/tickerplotdisplay.py (original)
+++ trunk/profit/workbench/tickerplotdisplay.py Tue Jul 29 01:44:30 2008
@@ -93,7 +93,7 @@
def saveCount(self):
settings = Settings()
settings.beginGroup('Plots')
- settings.beginGroup('%s' % self.sessionArgs[1])
+ settings.beginGroup('%s' % self.sessionArgs[1].__class__.__name__)
settings.setValue('displaycount', len(self.plotWidgets))

def setActionsEnabled(self):

Modified: trunk/profit/workbench/widgets/ui_tickerdisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_tickerdisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_tickerdisplay.ui Tue Jul 29
01:44:30 2008
@@ -5,91 +5,58 @@
<rect>
<x>0</x>
<y>0</y>
- <width>500</width>
- <height>289</height>
+ <width>578</width>
+ <height>404</height>
</rect>
</property>
<property name="windowTitle" >
<string>Ticker Display</string>
</property>
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="margin" >
- <number>9</number>
- </property>
- <item>
- <widget class="FilterBar" native="1" name="widget" />
- </item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
<item>
- <widget class="LocalTable" name="tickerTable" >
- <property name="contextMenuPolicy" >
- <enum>Qt::CustomContextMenu</enum>
- </property>
- <property name="frameShape" >
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="frameShadow" >
- <enum>QFrame::Plain</enum>
- </property>
- <property name="alternatingRowColors" >
- <bool>true</bool>
- </property>
- <property name="selectionMode" >
- <enum>QAbstractItemView::SingleSelection</enum>
- </property>
- <property name="showGrid" >
- <bool>true</bool>
- </property>
- <property name="gridStyle" >
- <enum>Qt::DotLine</enum>
- </property>
- <column>
- <property name="text" >
- <string>Symbol</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Position</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Value</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Ask Size</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Ask Price</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Bid Size</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Bid Price</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Last Size</string>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Last Price</string>
- </property>
- </column>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="TickFieldSelect" native="1" name="tickFieldSelect" />
+ <widget class="QFrame" name="frame" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="FilterBar" native="1" name="filterBar" />
+ </item>
+ <item>
+ <widget class="LocalTable" name="tickerTable" >
+ <property name="contextMenuPolicy" >
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="showGrid" >
+ <bool>true</bool>
+ </property>
+ <property name="gridStyle" >
+ <enum>Qt::DotLine</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
</layout>
@@ -122,6 +89,12 @@
<class>LocalTable</class>
<extends>QTableWidget</extends>
<header location="global" >profit.lib.widgets.localtable.h</header>
+ </customwidget>
+ <customwidget>
+ <class>TickFieldSelect</class>
+ <extends>QWidget</extends>
+ <header location="global" >profit.lib.widgets.tickfieldselect</header>
+ <container>1</container>
</customwidget>
</customwidgets>
<resources/>

Reply all
Reply to author
Forward
0 new messages