def __init__(self, parent=None):
     super(PosEditor, self).__init__(parent)
     self.setupUi(self)
     self.setModal(True)
     #signal&slot
     self.connect(self.cancel_button, SIGNAL("clicked()"),
                  self.onCancelBtClicked)
     self.connect(self.save_button, SIGNAL("clicked()"),
                  self.onSaveAllBtClicked)
     self.connect(self.reload_button, SIGNAL("clicked()"),
                  self.onReloadBtClicked)
     self.connect(self.save_csv_button, SIGNAL("clicked()"),
                  self.onSaveCsvBtClicked)
     self.connect(self.addrow_button, SIGNAL("clicked()"),
                  self.onAddrowBtClicked)
     self.connect(self.delrows_button, SIGNAL("clicked()"),
                  self.onDelRowBtClicked)
     #init mvc impl
     self.model = MatrixModel(self)
     self.delegate = AutoFormDelegate(self)
     self.position_edit_vtable.setItemDelegate(self.delegate)
     self.position_edit_vtable.setModel(self.model)
     #init data
     self.controler = None
     self.model.setSize(0, PosEditor.EDIT_TABLE_HEADERS)
 def __init__(self, parent=None):
     super(OptionCalculator, self).__init__(parent)
     self.setupUi(self)
     #show
     self.show()
     #define signal&slot
     self.connect(self.fresh_quotes_button, SIGNAL('clicked()'), self.__onRefreshQuoteBtClicked)
     self.connect(self.edit_position_button, SIGNAL('clicked()'), self.__onEditPosBtClicked)
     self.connect(self.plot_button, SIGNAL('clicked()'), self.__onPlotBtClicked)
     self.connect(self, SIGNAL('PLOT_SENSIBILITY'), self.__plotGreeksSensibility)
     self.connect(self, SIGNAL('PLOT_EXERCISE_CURVE'), self.__plotExerciseCurve)
     self.connect(self, SIGNAL('SET_ETF_DISPLAY'), self.__setEtfDataDisplay)
     self.connect(self, SIGNAL('SET_CENTRAL_DISPLAY'), self.__setCentralTableDisplay)
     self.connect(self, SIGNAL('ENGINE_ERROR'), self.__notifyErrorOccur)
     #init position vtable
     self.option_data = MatrixModel(self)
     self.pos_deleg = AutoFormDelegate(self)
     self.position_vtable.setItemDelegate(self.pos_deleg)
     self.position_vtable.setModel(self.option_data)
     self.option_data.setSize(0, OPTION_DF_HEADERS)
     #init stock_position vtable
     self.stock_data = MatrixModel(self)
     self.stpos_deleg = AutoFormDelegate(self)
     self.stock_position_vtable.setItemDelegate(self.stpos_deleg)
     self.stock_position_vtable.setModel(self.stock_data)
     self.stock_data.setSize(0, STOCK_DF_HEADERS)
     #init portfolio vtable
     self.portfolio_data = MatrixModel(self)
     self.ptf_deleg = AutoFormDelegate(self)
     self.portfolio_vtable.setItemDelegate(self.ptf_deleg)
     self.portfolio_vtable.setModel(self.portfolio_data)
     self.portfolio_data.setSize(0, PORTFOLIO_DF_HEADERS)
     #gui communication
     self.msg = None
     self.msg_event = None
     self.msg_thread = None
     #data engine
     self.engine = None
     #flow control
     self.is_updating = False
     self.auto_refresh_timer = None
     #qt child
     self.edit_dialog = PosEditor(self)
     self.edit_dialog.setControler(self)
     return
 def __init__(self, parent=None):
     super(PosEditor, self).__init__(parent)
     self.setupUi(self)
     self.setModal(True)
     #signal&slot
     self.connect(self.cancel_button, SIGNAL("clicked()"), self.onCancelBtClicked)
     self.connect(self.save_button, SIGNAL("clicked()"), self.onSaveBtClicked)
     self.connect(self.reload_button, SIGNAL("clicked()"), self.onReloadBtClicked)
     self.connect(self.addrow_button, SIGNAL("clicked()"), self.onAddrowBtClicked)
     self.connect(self.delrows_button, SIGNAL("clicked()"), self.onDelRowBtClicked)
     #init mvc impl
     self.model = MatrixModel(self)
     self.delegate = AutoFormDelegate(self)
     self.position_edit_vtable.setItemDelegate(self.delegate)
     self.position_edit_vtable.setModel(self.model)
     #init data
     self.controler = None
     self.model.setSize(0, PosEditor.EDIT_TABLE_HEADERS)
Beispiel #4
0
 def __init__(self, parent=None):
     super(OptionCalculator, self).__init__(parent)
     self.setupUi(self)
     #show
     self.show()
     #define signal&slot
     self.connect(self.fresh_quotes_button, SIGNAL('clicked()'),
                  self.__onRefreshQuoteBtClicked)
     self.connect(self.edit_position_button, SIGNAL('clicked()'),
                  self.__onEditPosBtClicked)
     self.connect(self.plot_button, SIGNAL('clicked()'),
                  self.__onPlotBtClicked)
     self.connect(self, SIGNAL('PLOT_SENSIBILITY'),
                  self.__plotGreeksSensibility)
     self.connect(self, SIGNAL('PLOT_EXERCISE_CURVE'),
                  self.__plotExerciseCurve)
     self.connect(self, SIGNAL('SET_ETF_DISPLAY'), self.__setEtfDataDisplay)
     self.connect(self, SIGNAL('SET_CENTRAL_DISPLAY'),
                  self.__setCentralTableDisplay)
     self.connect(self, SIGNAL('ENGINE_ERROR'), self.__notifyErrorOccur)
     #init position vtable
     self.option_data = MatrixModel(self)
     self.pos_deleg = AutoFormDelegate(self)
     self.position_vtable.setItemDelegate(self.pos_deleg)
     self.position_vtable.setModel(self.option_data)
     self.option_data.setSize(0, OPTION_DF_HEADERS)
     #init stock_position vtable
     self.stock_data = MatrixModel(self)
     self.stpos_deleg = AutoFormDelegate(self)
     self.stock_position_vtable.setItemDelegate(self.stpos_deleg)
     self.stock_position_vtable.setModel(self.stock_data)
     self.stock_data.setSize(0, STOCK_DF_HEADERS)
     #init portfolio vtable
     self.portfolio_data = MatrixModel(self)
     self.ptf_deleg = AutoFormDelegate(self)
     self.portfolio_vtable.setItemDelegate(self.ptf_deleg)
     self.portfolio_vtable.setModel(self.portfolio_data)
     self.portfolio_data.setSize(0, PORTFOLIO_DF_HEADERS)
     #gui communication
     self.msg = None
     self.msg_event = None
     self.msg_thread = None
     #data engine
     self.engine = None
     #flow control
     self.is_updating = False
     self.auto_refresh_timer = None
     #qt child
     self.edit_dialog = PosEditor(self)
     self.edit_dialog.setControler(self)
     return
class OptionCalculator(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(OptionCalculator, self).__init__(parent)
        self.setupUi(self)
        #show
        self.show()
        #define signal&slot
        self.connect(self.fresh_quotes_button, SIGNAL('clicked()'), self.__onRefreshQuoteBtClicked)
        self.connect(self.edit_position_button, SIGNAL('clicked()'), self.__onEditPosBtClicked)
        self.connect(self.plot_button, SIGNAL('clicked()'), self.__onPlotBtClicked)
        self.connect(self, SIGNAL('PLOT_SENSIBILITY'), self.__plotGreeksSensibility)
        self.connect(self, SIGNAL('PLOT_EXERCISE_CURVE'), self.__plotExerciseCurve)
        self.connect(self, SIGNAL('SET_ETF_DISPLAY'), self.__setEtfDataDisplay)
        self.connect(self, SIGNAL('SET_CENTRAL_DISPLAY'), self.__setCentralTableDisplay)
        self.connect(self, SIGNAL('ENGINE_ERROR'), self.__notifyErrorOccur)
        #init position vtable
        self.option_data = MatrixModel(self)
        self.pos_deleg = AutoFormDelegate(self)
        self.position_vtable.setItemDelegate(self.pos_deleg)
        self.position_vtable.setModel(self.option_data)
        self.option_data.setSize(0, OPTION_DF_HEADERS)
        #init stock_position vtable
        self.stock_data = MatrixModel(self)
        self.stpos_deleg = AutoFormDelegate(self)
        self.stock_position_vtable.setItemDelegate(self.stpos_deleg)
        self.stock_position_vtable.setModel(self.stock_data)
        self.stock_data.setSize(0, STOCK_DF_HEADERS)
        #init portfolio vtable
        self.portfolio_data = MatrixModel(self)
        self.ptf_deleg = AutoFormDelegate(self)
        self.portfolio_vtable.setItemDelegate(self.ptf_deleg)
        self.portfolio_vtable.setModel(self.portfolio_data)
        self.portfolio_data.setSize(0, PORTFOLIO_DF_HEADERS)
        #gui communication
        self.msg = None
        self.msg_event = None
        self.msg_thread = None
        #data engine
        self.engine = None
        #flow control
        self.is_updating = False
        self.auto_refresh_timer = None
        #qt child
        self.edit_dialog = PosEditor(self)
        self.edit_dialog.setControler(self)
        return

    def start(self):
        #gui communication
        self.msg = MessageQueue()
        self.msg_event = THD.Event()
        self.msg_thread = THD.Thread(target=self.__handleMessage)
        self.msg_thread.start()
        #data engine
        self.engine = Engine(self)
        self.__startAutoRefresh(True)
        self.engine.qryEtfQuoteFeed()
        self.engine.qryTableDataFeed()

    def quit(self):
        if not self.auto_refresh_timer is None:
            self.auto_refresh_timer.cancel()
        if not self.engine is None:
            self.engine.quit()
        if not self.msg_thread is None:
            self.__pushMsg(MessageTypes.QUIT)
            self.msg_thread.join()
        return

    def closeEvent(self, event):
        rtn = QMessageBox.question(self, 'Save & exit', 'Save positions to csv?',
                                   QMessageBox.Save, QMessageBox.No, QMessageBox.Cancel)
        if rtn == QMessageBox.Cancel:
            event.ignore()
            return
        if rtn == QMessageBox.Save:
            self.onSavePosition2Csv()
        self.quit()
        #close
        super(OptionCalculator, self).closeEvent(event)
        return

    #-------------------------------------------------------------------------
    def onEngineError(self, err):
        with open(r'./logs.txt', 'a') as fid:
            err_info = '\n>>%s\n%s' % (str(DT.datetime.now()), str(err))
            fid.write(err_info)
        self.emit(SIGNAL('ENGINE_ERROR'))
        return

    def onRepTableFeed(self, option_data, stock_data, ptf_data):
        self.__pushMsg(MessageTypes.REPLY_TABLE_FEED, (option_data, stock_data, ptf_data))

    def onRepEtfQuoteFeed(self, etf_data):
        self.__pushMsg(MessageTypes.REPLY_ETF_QUOTE_FEED, etf_data)

    def onRepCalGreeksSensibility(self, plot_data, x_axis_type):
        self.__pushMsg(MessageTypes.REPLY_CAL_SENSI, (plot_data, x_axis_type))

    def onRepCalExerciseCurve(self, plot_data):
        self.__pushMsg(MessageTypes.REPLY_EXERCISE_CURVE, plot_data)

    def onRepPositionBasedataFeed(self, positions):
        self.__pushMsg(MessageTypes.REPLY_POSITION_BASEDATA_FEED, positions)

    def __handleMessage(self):
        while True:
            msg = self.msg.getMsg()
            if msg is None:
              self.msg_event.wait()
              self.msg_event.clear()
            #received data for display
            elif msg.type is MessageTypes.REPLY_TABLE_FEED:
                self.emit(SIGNAL('SET_CENTRAL_DISPLAY'),
                          msg.content[0], msg.content[1], msg.content[2])

            elif msg.type is MessageTypes.REPLY_ETF_QUOTE_FEED:
                self.emit(SIGNAL('SET_ETF_DISPLAY'), msg.content)

            elif msg.type is MessageTypes.REPLY_CAL_SENSI:
                self.emit(SIGNAL('PLOT_SENSIBILITY'), msg.content[0], msg.content[1])

            elif msg.type is MessageTypes.REPLY_EXERCISE_CURVE:
                self.emit(SIGNAL('PLOT_EXERCISE_CURVE'), msg.content)

            elif msg.type is MessageTypes.REPLY_POSITION_BASEDATA_FEED:
                self.__updatePosEditorData(msg.content)

            elif msg.type is MessageTypes.QUIT:
                break
        return

    def __pushMsg(self, msg_type, content=None):
        self.msg.pushMsg(msg_type, content)
        self.msg_event.set()
    #----------------------------------------------------------------------
    def onEditorClickBtSaveAll(self, position_data):
        self.engine.qryReloadPositions(position_data)
        self.__queryUpdateData()

    def onEditorClickBtReloadPosition(self):
        self.engine.qryReloadPositions()
        self.engine.qryPositionBasedata()
        self.__queryUpdateData()

    def onSavePosition2Csv(self):
        self.engine.qrySavePositionCsv()

    #----------------------------------------------------------------------
    def __onRefreshQuoteBtClicked(self):
        self.__queryUpdateData()

    def __onEditPosBtClicked(self):
        self.edit_dialog.wakeupEditor()
        self.engine.qryPositionBasedata()

    def __onPlotBtClicked(self):
        x_axis_type = self.greeks_x_axis_combobox.currentIndex()
        #pass group id list
        if self.portfolio_checkBox.isChecked():
            #collect group id
            group_ids = list()
            for r in getSelectedRows(self.portfolio_vtable):
                item = self.portfolio_data.getValueByHeader(r, 'group')
                try:
                    group_ids.append(int(item))
                except:
                    pass
            if group_ids:
                if x_axis_type == 0:
                    self.engine.qryCalGreeksSensibilityByGroup(group_ids, group_ids, XAxisType.PRICE)
                elif x_axis_type == 1:
                    self.engine.qryCalGreeksSensibilityByGroup(group_ids, group_ids, XAxisType.VOLATILITY)
                elif x_axis_type == 2:
                    self.engine.qryCalGreeksSensibilityByGroup(group_ids, group_ids, XAxisType.TIME)
                elif x_axis_type == 3:
                    self.engine.qryExerciseCurveByGroup(group_ids, group_ids)
        #pass row numbers list
        else:
            option_idx = getSelectedRows(self.position_vtable)
            stock_idx  = getSelectedRows(self.stock_position_vtable)
            if option_idx or stock_idx:
                if x_axis_type == 0:
                    self.engine.qryCalGreeksSensibilityByPosition(option_idx, stock_idx, XAxisType.PRICE)
                elif x_axis_type == 1:
                    self.engine.qryCalGreeksSensibilityByPosition(option_idx, stock_idx, XAxisType.VOLATILITY)
                elif x_axis_type == 2:
                    self.engine.qryCalGreeksSensibilityByPosition(option_idx, stock_idx, XAxisType.TIME)
                elif x_axis_type == 3:
                    self.engine.qryExerciseCurveByPosition(option_idx, stock_idx)
        return

    #-------------------------------------------------------------------
    def __startAutoRefresh(self, onInit=False):
        self.auto_refresh_timer = THD.Timer(300, self.__startAutoRefresh)
        self.auto_refresh_timer.start()
        if not onInit:
            self.__queryUpdateData()
        return

    def __queryUpdateData(self):
        if not self.is_updating:
            self.is_updating = True
            self.engine.qryUpdateData()
            self.engine.qryEtfQuoteFeed()
            self.engine.qryTableDataFeed()

    def __setEtfDataDisplay(self, etf_data):
        self.update_time_label.setText('%s' % etf_data.getByHeader(0, 'update_time').strftime(r'%H:%M:%S'))
        self.etf_openprice_label.setText('open: %.3f' % etf_data.getByHeader(0, 'open_price'))
        self.etf_highprice_label.setText('high: %.3f' % etf_data.getByHeader(0, 'high_price'))
        self.etf_lowprice_label.setText('low: %.3f' % etf_data.getByHeader(0, 'low_price'))
        self.etf_lastprice_label.setText('last: %.3f' % etf_data.getByHeader(0, 'last_price'))

    def __setCentralTableDisplay(self, option_data, stock_data, portfolio_data):
        self.option_data.setTableContent(option_data)
        self.stock_data.setTableContent(stock_data)
        self.portfolio_data.setTableContent(portfolio_data)
        #notify_updating_completed
        self.is_updating = False
        return

    def __updatePosEditorData(self, pos_table_handler):
        self.edit_dialog.setEditTableContent(pos_table_handler)

    def __plotGreeksSensibility(self, p_data, x_axis_type):
        if x_axis_type == XAxisType.PRICE:
            figure_name = 'by price'
        elif x_axis_type == XAxisType.VOLATILITY:
            figure_name = 'by volatility'
        elif x_axis_type == XAxisType.TIME:
            figure_name = 'by time'
        else:
            figure_name = ''

        fig = PLT.figure()
        fig.suptitle(figure_name)

        sp = fig.add_subplot(2, 2, 1)
        decorateAndPlot(sp, p_data['ax_x'], p_data['delta'],
                        title='delta', central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 2)
        decorateAndPlot(sp, p_data['ax_x'], p_data['gamma'],
                        title='gamma', central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 3)
        decorateAndPlot(sp, p_data['ax_x'], p_data['vega'],
                        title='vega', central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 4)
        decorateAndPlot(sp, p_data['ax_x'], p_data['theta'],
                        title='theta', central_x=p_data['central_x'])

        PLT.show()
        return

    def __plotExerciseCurve(self, plot_data):
        fig = PLT.figure()
        fig.suptitle('Theoretical earnings curve')

        sp = fig.add_subplot(1, 1, 1)
        decorateAndPlot(sp, plot_data['ax_x'], plot_data['exercise_profit'],
                        central_x=plot_data['central_x'])
        plotZeroLine(sp)

        PLT.show()
        return

    def __notifyErrorOccur(self):
        QMessageBox.question(self, 'Error', 'engine error occurs, restart manually ...',
                             QMessageBox.Yes)
Beispiel #6
0
class OptionCalculator(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(OptionCalculator, self).__init__(parent)
        self.setupUi(self)
        #show
        self.show()
        #define signal&slot
        self.connect(self.fresh_quotes_button, SIGNAL('clicked()'),
                     self.__onRefreshQuoteBtClicked)
        self.connect(self.edit_position_button, SIGNAL('clicked()'),
                     self.__onEditPosBtClicked)
        self.connect(self.plot_button, SIGNAL('clicked()'),
                     self.__onPlotBtClicked)
        self.connect(self, SIGNAL('PLOT_SENSIBILITY'),
                     self.__plotGreeksSensibility)
        self.connect(self, SIGNAL('PLOT_EXERCISE_CURVE'),
                     self.__plotExerciseCurve)
        self.connect(self, SIGNAL('SET_ETF_DISPLAY'), self.__setEtfDataDisplay)
        self.connect(self, SIGNAL('SET_CENTRAL_DISPLAY'),
                     self.__setCentralTableDisplay)
        self.connect(self, SIGNAL('ENGINE_ERROR'), self.__notifyErrorOccur)
        #init position vtable
        self.option_data = MatrixModel(self)
        self.pos_deleg = AutoFormDelegate(self)
        self.position_vtable.setItemDelegate(self.pos_deleg)
        self.position_vtable.setModel(self.option_data)
        self.option_data.setSize(0, OPTION_DF_HEADERS)
        #init stock_position vtable
        self.stock_data = MatrixModel(self)
        self.stpos_deleg = AutoFormDelegate(self)
        self.stock_position_vtable.setItemDelegate(self.stpos_deleg)
        self.stock_position_vtable.setModel(self.stock_data)
        self.stock_data.setSize(0, STOCK_DF_HEADERS)
        #init portfolio vtable
        self.portfolio_data = MatrixModel(self)
        self.ptf_deleg = AutoFormDelegate(self)
        self.portfolio_vtable.setItemDelegate(self.ptf_deleg)
        self.portfolio_vtable.setModel(self.portfolio_data)
        self.portfolio_data.setSize(0, PORTFOLIO_DF_HEADERS)
        #gui communication
        self.msg = None
        self.msg_event = None
        self.msg_thread = None
        #data engine
        self.engine = None
        #flow control
        self.is_updating = False
        self.auto_refresh_timer = None
        #qt child
        self.edit_dialog = PosEditor(self)
        self.edit_dialog.setControler(self)
        return

    def start(self):
        #gui communication
        self.msg = MessageQueue()
        self.msg_event = THD.Event()
        self.msg_thread = THD.Thread(target=self.__handleMessage)
        self.msg_thread.start()
        #data engine
        self.engine = Engine(self)
        self.__startAutoRefresh(True)
        self.engine.qryEtfQuoteFeed()
        self.engine.qryTableDataFeed()

    def quit(self):
        if not self.auto_refresh_timer is None:
            self.auto_refresh_timer.cancel()
        if not self.engine is None:
            self.engine.quit()
        if not self.msg_thread is None:
            self.__pushMsg(MessageTypes.QUIT)
            self.msg_thread.join()
        return

    def closeEvent(self, event):
        rtn = QMessageBox.question(self, 'Save & exit',
                                   'Save positions to csv?', QMessageBox.Save,
                                   QMessageBox.No, QMessageBox.Cancel)
        if rtn == QMessageBox.Cancel:
            event.ignore()
            return
        if rtn == QMessageBox.Save:
            self.onSavePosition2Csv()
        self.quit()
        #close
        super(OptionCalculator, self).closeEvent(event)
        return

    #-------------------------------------------------------------------------
    def onEngineError(self, err):
        with open(r'./logs.txt', 'a') as fid:
            err_info = '\n>>%s\n%s' % (str(DT.datetime.now()), str(err))
            fid.write(err_info)
        self.emit(SIGNAL('ENGINE_ERROR'))
        return

    def onRepTableFeed(self, option_data, stock_data, ptf_data):
        self.__pushMsg(MessageTypes.REPLY_TABLE_FEED,
                       (option_data, stock_data, ptf_data))

    def onRepEtfQuoteFeed(self, etf_data):
        self.__pushMsg(MessageTypes.REPLY_ETF_QUOTE_FEED, etf_data)

    def onRepCalGreeksSensibility(self, plot_data, x_axis_type):
        self.__pushMsg(MessageTypes.REPLY_CAL_SENSI, (plot_data, x_axis_type))

    def onRepCalExerciseCurve(self, plot_data):
        self.__pushMsg(MessageTypes.REPLY_EXERCISE_CURVE, plot_data)

    def onRepPositionBasedataFeed(self, positions):
        self.__pushMsg(MessageTypes.REPLY_POSITION_BASEDATA_FEED, positions)

    def __handleMessage(self):
        while True:
            msg = self.msg.getMsg()
            if msg is None:
                self.msg_event.wait()
                self.msg_event.clear()
            #received data for display
            elif msg.type is MessageTypes.REPLY_TABLE_FEED:
                self.emit(SIGNAL('SET_CENTRAL_DISPLAY'), msg.content[0],
                          msg.content[1], msg.content[2])

            elif msg.type is MessageTypes.REPLY_ETF_QUOTE_FEED:
                self.emit(SIGNAL('SET_ETF_DISPLAY'), msg.content)

            elif msg.type is MessageTypes.REPLY_CAL_SENSI:
                self.emit(SIGNAL('PLOT_SENSIBILITY'), msg.content[0],
                          msg.content[1])

            elif msg.type is MessageTypes.REPLY_EXERCISE_CURVE:
                self.emit(SIGNAL('PLOT_EXERCISE_CURVE'), msg.content)

            elif msg.type is MessageTypes.REPLY_POSITION_BASEDATA_FEED:
                self.__updatePosEditorData(msg.content)

            elif msg.type is MessageTypes.QUIT:
                break
        return

    def __pushMsg(self, msg_type, content=None):
        self.msg.pushMsg(msg_type, content)
        self.msg_event.set()

    #----------------------------------------------------------------------
    def onEditorClickBtSaveAll(self, position_data):
        self.engine.qryReloadPositions(position_data)
        self.__queryUpdateData()

    def onEditorClickBtReloadPosition(self):
        self.engine.qryReloadPositions()
        self.engine.qryPositionBasedata()
        self.__queryUpdateData()

    def onSavePosition2Csv(self):
        self.engine.qrySavePositionCsv()

    #----------------------------------------------------------------------
    def __onRefreshQuoteBtClicked(self):
        self.__queryUpdateData()

    def __onEditPosBtClicked(self):
        self.edit_dialog.wakeupEditor()
        self.engine.qryPositionBasedata()

    def __onPlotBtClicked(self):
        x_axis_type = self.greeks_x_axis_combobox.currentIndex()
        #pass group id list
        if self.portfolio_checkBox.isChecked():
            #collect group id
            group_ids = list()
            for r in getSelectedRows(self.portfolio_vtable):
                item = self.portfolio_data.getValueByHeader(r, 'group')
                try:
                    group_ids.append(int(item))
                except:
                    pass
            if group_ids:
                if x_axis_type == 0:
                    self.engine.qryCalGreeksSensibilityByGroup(
                        group_ids, group_ids, XAxisType.PRICE)
                elif x_axis_type == 1:
                    self.engine.qryCalGreeksSensibilityByGroup(
                        group_ids, group_ids, XAxisType.VOLATILITY)
                elif x_axis_type == 2:
                    self.engine.qryCalGreeksSensibilityByGroup(
                        group_ids, group_ids, XAxisType.TIME)
                elif x_axis_type == 3:
                    self.engine.qryExerciseCurveByGroup(group_ids, group_ids)
        #pass row numbers list
        else:
            option_idx = getSelectedRows(self.position_vtable)
            stock_idx = getSelectedRows(self.stock_position_vtable)
            if option_idx or stock_idx:
                if x_axis_type == 0:
                    self.engine.qryCalGreeksSensibilityByPosition(
                        option_idx, stock_idx, XAxisType.PRICE)
                elif x_axis_type == 1:
                    self.engine.qryCalGreeksSensibilityByPosition(
                        option_idx, stock_idx, XAxisType.VOLATILITY)
                elif x_axis_type == 2:
                    self.engine.qryCalGreeksSensibilityByPosition(
                        option_idx, stock_idx, XAxisType.TIME)
                elif x_axis_type == 3:
                    self.engine.qryExerciseCurveByPosition(
                        option_idx, stock_idx)
        return

    #-------------------------------------------------------------------
    def __startAutoRefresh(self, onInit=False):
        self.auto_refresh_timer = THD.Timer(300, self.__startAutoRefresh)
        self.auto_refresh_timer.start()
        if not onInit:
            self.__queryUpdateData()
        return

    def __queryUpdateData(self):
        if not self.is_updating:
            self.is_updating = True
            self.engine.qryUpdateData()
            self.engine.qryEtfQuoteFeed()
            self.engine.qryTableDataFeed()

    def __setEtfDataDisplay(self, etf_data):
        self.update_time_label.setText(
            '%s' %
            etf_data.getByHeader(0, 'update_time').strftime(r'%H:%M:%S'))
        self.etf_openprice_label.setText('open: %.3f' %
                                         etf_data.getByHeader(0, 'open_price'))
        self.etf_highprice_label.setText('high: %.3f' %
                                         etf_data.getByHeader(0, 'high_price'))
        self.etf_lowprice_label.setText('low: %.3f' %
                                        etf_data.getByHeader(0, 'low_price'))
        self.etf_lastprice_label.setText('last: %.3f' %
                                         etf_data.getByHeader(0, 'last_price'))

    def __setCentralTableDisplay(self, option_data, stock_data,
                                 portfolio_data):
        self.option_data.setTableContent(option_data)
        self.stock_data.setTableContent(stock_data)
        self.portfolio_data.setTableContent(portfolio_data)
        #notify_updating_completed
        self.is_updating = False
        return

    def __updatePosEditorData(self, pos_table_handler):
        self.edit_dialog.setEditTableContent(pos_table_handler)

    def __plotGreeksSensibility(self, p_data, x_axis_type):
        if x_axis_type == XAxisType.PRICE:
            figure_name = 'by price'
        elif x_axis_type == XAxisType.VOLATILITY:
            figure_name = 'by volatility'
        elif x_axis_type == XAxisType.TIME:
            figure_name = 'by time'
        else:
            figure_name = ''

        fig = PLT.figure()
        fig.suptitle(figure_name)

        sp = fig.add_subplot(2, 2, 1)
        decorateAndPlot(sp,
                        p_data['ax_x'],
                        p_data['delta'],
                        title='delta',
                        central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 2)
        decorateAndPlot(sp,
                        p_data['ax_x'],
                        p_data['gamma'],
                        title='gamma',
                        central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 3)
        decorateAndPlot(sp,
                        p_data['ax_x'],
                        p_data['vega'],
                        title='vega',
                        central_x=p_data['central_x'])

        sp = fig.add_subplot(2, 2, 4)
        decorateAndPlot(sp,
                        p_data['ax_x'],
                        p_data['theta'],
                        title='theta',
                        central_x=p_data['central_x'])

        PLT.show()
        return

    def __plotExerciseCurve(self, plot_data):
        fig = PLT.figure()
        fig.suptitle('Theoretical earnings curve')

        sp = fig.add_subplot(1, 1, 1)
        decorateAndPlot(sp,
                        plot_data['ax_x'],
                        plot_data['exercise_profit'],
                        central_x=plot_data['central_x'])
        plotZeroLine(sp)

        PLT.show()
        return

    def __notifyErrorOccur(self):
        QMessageBox.question(self, 'Error',
                             'engine error occurs, restart manually ...',
                             QMessageBox.Yes)
class PosEditor(QDialog, Ui_position_editor_dialog):
    EDIT_TABLE_HEADERS = ('group', 'code', 'dir', 'lots', 'open_price', 'margin', 'open_date')

    def __init__(self, parent=None):
        super(PosEditor, self).__init__(parent)
        self.setupUi(self)
        self.setModal(True)
        #signal&slot
        self.connect(self.cancel_button, SIGNAL("clicked()"), self.onCancelBtClicked)
        self.connect(self.save_button, SIGNAL("clicked()"), self.onSaveBtClicked)
        self.connect(self.reload_button, SIGNAL("clicked()"), self.onReloadBtClicked)
        self.connect(self.addrow_button, SIGNAL("clicked()"), self.onAddrowBtClicked)
        self.connect(self.delrows_button, SIGNAL("clicked()"), self.onDelRowBtClicked)
        #init mvc impl
        self.model = MatrixModel(self)
        self.delegate = AutoFormDelegate(self)
        self.position_edit_vtable.setItemDelegate(self.delegate)
        self.position_edit_vtable.setModel(self.model)
        #init data
        self.controler = None
        self.model.setSize(0, PosEditor.EDIT_TABLE_HEADERS)

    def setControler(self, ctl):
        self.controler = ctl

    #--------------------------------------------------
    def wakeupEditor(self):
        self.show()

    def setEditTableContent(self, table_hdl_inst):
        self.model.setTableContent(table_hdl_inst)

    #--------------------------------------------------
    def onAddrowBtClicked(self):
        self.model.appendRows()

    def onDelRowBtClicked(self):
        rows = getSelectedRows(self.position_edit_vtable)
        if rows:
            self.model.deleteRows(rows)

    def onCancelBtClicked(self):
        self.model.clearContent()
        self.close()

    @staticmethod
    def findInvalidRows(t_data=TableHandler()):
        invalid_rows = list()
        for r in range(0, t_data.rows):
            for h in ['group', 'code', 'dir', 'lots', 'open_price']:
                val = t_data.getByHeader(r, h)
                if val is None or val == '':
                    invalid_rows.append(r)
        return invalid_rows

    def onSaveBtClicked(self):
        rtn = QMessageBox.question(self, 'Confirm', 'Save position changes ?',
                                   QMessageBox.Yes, QMessageBox.No)
        if rtn == QMessageBox.Yes:
            data = TableHandler()
            data.copy(self.model.data)
            invalid_rows = PosEditor.findInvalidRows(data)
            if invalid_rows:
                data.delRows(invalid_rows)
            if data.rows > 0:
                self.controler.onEditorClickBtSaveAll(data)
                self.close()
            else:
                cf = QMessageBox.warning(self, 'Error',
                                         'position record invalid !', QMessageBox.Yes)
        return

    def onReloadBtClicked(self):
        rtn = QMessageBox.question(self, 'Confirm', 'Reload from position.csv ?',
                                   QMessageBox.Yes, QMessageBox.No)
        if rtn == QMessageBox.Yes:
            self.controler.onEditorClickBtReloadPosition()
        return
class PosEditor(QDialog, Ui_position_editor_dialog):
    EDIT_TABLE_HEADERS = ('group', 'code', 'dir', 'lots', 'open_price',
                          'margin', 'open_date')

    def __init__(self, parent=None):
        super(PosEditor, self).__init__(parent)
        self.setupUi(self)
        self.setModal(True)
        #signal&slot
        self.connect(self.cancel_button, SIGNAL("clicked()"),
                     self.onCancelBtClicked)
        self.connect(self.save_button, SIGNAL("clicked()"),
                     self.onSaveAllBtClicked)
        self.connect(self.reload_button, SIGNAL("clicked()"),
                     self.onReloadBtClicked)
        self.connect(self.save_csv_button, SIGNAL("clicked()"),
                     self.onSaveCsvBtClicked)
        self.connect(self.addrow_button, SIGNAL("clicked()"),
                     self.onAddrowBtClicked)
        self.connect(self.delrows_button, SIGNAL("clicked()"),
                     self.onDelRowBtClicked)
        #init mvc impl
        self.model = MatrixModel(self)
        self.delegate = AutoFormDelegate(self)
        self.position_edit_vtable.setItemDelegate(self.delegate)
        self.position_edit_vtable.setModel(self.model)
        #init data
        self.controler = None
        self.model.setSize(0, PosEditor.EDIT_TABLE_HEADERS)

    def setControler(self, ctl):
        self.controler = ctl

    #--------------------------------------------------
    def wakeupEditor(self):
        self.show()

    def setEditTableContent(self, table_hdl_inst):
        self.model.setTableContent(table_hdl_inst)

    #--------------------------------------------------
    def onAddrowBtClicked(self):
        self.model.appendRows()

    def onDelRowBtClicked(self):
        rows = getSelectedRows(self.position_edit_vtable)
        if rows:
            self.model.deleteRows(rows)

    def onCancelBtClicked(self):
        self.model.clearContent()
        self.close()

    @staticmethod
    def findInvalidRows(t_data=TableHandler()):
        invalid_rows = list()
        for r in range(0, t_data.rows):
            for h in ['group', 'code', 'dir', 'lots', 'open_price', 'margin']:
                val = t_data.getByHeader(r, h)
                if val is None or val == '':
                    invalid_rows.append(r)
        return invalid_rows

    def onSaveAllBtClicked(self):
        rtn = QMessageBox.question(self, 'Confirm', 'Save position changes?',
                                   QMessageBox.Yes, QMessageBox.No)
        if rtn == QMessageBox.Yes:
            data = TableHandler()
            data.copy(self.model.data)
            invalid_rows = PosEditor.findInvalidRows(data)
            if invalid_rows:
                data.delRows(invalid_rows)
            if data.rows > 0:
                self.controler.onEditorClickBtSaveAll(data)
            else:
                QMessageBox.warning(self, 'Error', 'None valid records!',
                                    QMessageBox.Yes)
            #notify
            if invalid_rows:
                info_str = 'Invalid rows deleted:\n%s' % str(
                    [i + 1 for i in invalid_rows])
                QMessageBox.warning(self, 'Warning', info_str, QMessageBox.Yes)
            else:
                self.close()
        return

    def onReloadBtClicked(self):
        rtn = QMessageBox.question(self, 'Confirm',
                                   'Reloading from position.csv?',
                                   QMessageBox.Yes, QMessageBox.No)
        if rtn == QMessageBox.Yes:
            self.controler.onEditorClickBtReloadPosition()
        return

    def onSaveCsvBtClicked(self):
        rtn = QMessageBox.question(self, 'Confirm',
                                   'Writing positions to position.csv?',
                                   QMessageBox.Yes, QMessageBox.No)
        if rtn == QMessageBox.Yes:
            self.controler.onSavePosition2Csv()
        return