0

I want to build a program where we get updated data from interactive brokers (a popular online broker) and I want to update a plot in a simple pyqt5 interface.

The program sequence is the following:

We start the Ui_MainWindow interface. If we click on pushbutton2 we initiate a thread with the function GetDataBackground. This function uses the class GetDataand every time there is an update of the data to plot, the function tickPrice and tickSize is executed. In this step, I want to update the plot (for the moment it can be with random numbers like codded in the update_graph).

When I run the program it returns the error:

AttributeError: 'GetData' object has no attribute 'MplWidget'

Which seams that I do not have access to the main window.

The code is the following:

from PyQt5 import QtCore, QtGui, QtWidgets   
from mplwidget import MplWidget
import threading    
import sys
sys.path.insert(0, "/Users/nuno/Desktop/IB_API/source/pythonclient/")   
from ibapi.client import EClient
from ibapi.wrapper import  EWrapper
from ibapi.contract import Contract
from ibapi.ticktype import TickTypeEnum
import numpy as np
import sys


class GetData(EWrapper, EClient):

    outrights = []
    calendars = []
    flies = []

    def __init__(self):
        EClient.__init__(self, self)

    def error(self, reqId, errorCode, errorString):
        print("Error: ", reqId, " ", errorCode, " ", errorString)

    def tickPrice(self, reqId , tickType, price, attrib):
        print("Tick Price. Ticker Id: ", reqId, "tickType: ", TickTypeEnum.to_str(tickType), " Price: ", price, end='\n')
        self.outrights[reqId][TickTypeEnum.to_str(tickType)] = price
        price = [x['DELAYED_LAST'] for x in self.outrights]
        print('Push button')
        self.testplot()
        self.update_graph()
        print(price)

    def tickSize(self, reqId, tickType, size):
        print("Tick Size. Ticker Id: ", reqId, "tickType: ", TickTypeEnum.to_str(tickType), 'Size: ', size)
        self.outrights[reqId][TickTypeEnum.to_str(tickType)] = size
        self.testplot()


    def testplot(self):
        print('Function correctly called')

    def update_graph(self):

        print('Push button')

        x = np.random.rand(30)
        y = np.random.rand(30)

        self.MplWidget.canvas.axes.clear()
        self.MplWidget.canvas.axes.plot(x, y)
        self.MplWidget.canvas.axes.legend(('random'), loc='upper right')
        self.MplWidget.canvas.draw()


def GetDataBackground():
    """
    This function gets the data in the background.

    :param PlotData:
    :return:
    """

    print('Interactive Brokers get data has started.')

    app = GetData()

    app.connect("127.0.0.1", 4002, 0)
    print("serverVersion: {} connectionTime: {}".format(app.serverVersion(), app.twsConnectionTime()))

    contract_list = ['GEZ0', 'GEH1', 'GEM1', 'GEU1', 'GEZ1', 'GEH2', 'GEM2', 'GEU2', 'GEZ2', 'GEH3', 'GEM3', 'GEU3',
                     'GEZ3', 'GEH4', 'GEM4', 'GEU4', 'GEZ4']

    # This for loop generates a list of dictionaries that live inside the class TestApp
    for i, contract in enumerate(contract_list):
        temp_dict = {}
        print(contract)
        temp_dict['localSymbol'] = contract
        temp_dict['tickerID'] = i
        temp_dict['DELAYED_ASK'] = None
        temp_dict['DELAYED_BID'] = None
        temp_dict['DELAYED_OPEN'] = None
        temp_dict['DELAYED_HIGH'] = None
        temp_dict['DELAYED_LOW'] = None
        temp_dict['DELAYED_CLOSE'] = None
        temp_dict['DELAYED_ASK_SIZE'] = None
        temp_dict['DELAYED_BID_SIZE'] = None
        temp_dict['DELAYED_VOLUME'] = None
        temp_dict['DELAYED_LAST'] = None
        temp_dict['DELAYED_LAST_SIZE'] = None
        app.outrights.append(temp_dict)

    contracts = [Contract() for x in contract_list]  # _

    for i in range(len(contract_list)):
        contracts[i].secType = 'FUT'
        contracts[i].exchange = 'GLOBEX'
        contracts[i].currency = 'USD'
        contracts[i].localSymbol = contract_list[i]

    app.reqMarketDataType(3)

    for i in range(len(contract_list)):
        print(contracts[i].localSymbol)
        app.reqMktData(i, contracts[i], "", False, False, [])

    app.run()

class Ui_MainWindow(GetData):

    def __init__(self):
        super().__init__()


    def start_download(self):
        download_info = threading.Thread(target = GetDataBackground)
        download_info.start()

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1280, 1024)

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(880, 80, 221, 32))
        self.pushButton.setObjectName("pushButton")

        self.pushButton2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton2.setGeometry(QtCore.QRect(880, 45, 221, 32))
        self.pushButton2.setObjectName("Get data")

        self.MplWidget = MplWidget(self.centralwidget)
        self.MplWidget.setGeometry(QtCore.QRect(49, 39, 771, 551))
        self.MplWidget.setObjectName("MplWidget")

        MainWindow.setCentralWidget(self.centralwidget)

        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1148, 22))
        self.menubar.setObjectName("menubar")

        self.menuFile = QtWidgets.QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")

        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionOpen = QtWidgets.QAction(MainWindow)
        self.actionOpen.setObjectName("actionOpen")
        self.actionSave = QtWidgets.QAction(MainWindow)
        self.actionSave.setObjectName("actionSave")
        self.actionClose = QtWidgets.QAction(MainWindow)
        self.actionClose.setObjectName("actionClose")
        self.actionSave_as = QtWidgets.QAction(MainWindow)
        self.actionSave_as.setObjectName("actionSave_as")
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionOpen)
        self.menuFile.addAction(self.actionSave)
        self.menuFile.addAction(self.actionSave_as)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionClose)
        self.menubar.addAction(self.menuFile.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.pushButton2.setText(_translate("MainWindow", "GetData"))
        self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionOpen.setText(_translate("MainWindow", "Open..."))
        self.actionSave.setText(_translate("MainWindow", "Save"))
        self.actionClose.setText(_translate("MainWindow", "Close"))
        self.actionSave_as.setText(_translate("MainWindow", "Save As..."))

        self.pushButton.clicked.connect(self.update_graph)
        self.pushButton2.clicked.connect(self.start_download)

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
nunodsousa
  • 2,635
  • 4
  • 27
  • 49

1 Answers1

0

Please refer to: https://eli.thegreenplace.net/2009/01/20/matplotlib-with-pyqt-guis

This is an excellent example for matplotlib with PyQt GUIs

Refer here too for more detailed example: https://github.com/eliben/code-for-blog/blob/master/2008/wx_mpl_dynamic_graph.py

smitkpatel
  • 722
  • 6
  • 21
  • It is related, but it isn't the same problem (or similar). I have a very clear condition, which is the updating function is inside a new class. – nunodsousa Aug 19 '19 at 17:33