Пример #1
0
    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret

        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        self.mainWindow.pushButtonApply.released.connect(self.save_credentials)
        self.mainWindow.pushButtonGo.released.connect(self.execute_trade)
        self.mainWindow.tableAsk.clicked.connect(self.update_price_from_asks)
        self.mainWindow.tableBid.clicked.connect(self.update_price_from_bids)
        self.mainWindow.pushButtonCancel.released.connect(self.cancel_order)
        self.mainWindow.textBrowserStatus.anchorClicked.connect(
            self.order_selected)
        self.mainWindow.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.mainWindow.pushButtonSize.released.connect(self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(
            self.update_price_best)
        self.mainWindow.pushButtonTotal.released.connect(
            self.recalculate_total)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.checkBoxLogTicker, 'tick'],
            [self.mainWindow.checkBoxLogTrade, 'TRADE'],
            [self.mainWindow.checkBoxLogDepth, 'depth'],
        ]

        # load credentials from configuration file
        self.load_credentials()

        self.show()
        self.raise_()
Пример #2
0
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.slot_update_price_from_asks)
        self.ui.tableBid.clicked.connect(self.slot_update_price_from_bids)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_price_best)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, "tick"],
            [self.ui.checkBoxLogTrade, "TRADE"],
            [self.ui.checkBoxLogDepth, "depth"],
        ]

        # resets dynamic ui elements
        self.reset()

        # activate market
        self.market.start()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()
Пример #3
0
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)
        self.market.signal_ticker.connect(self.update_titlebar)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.ui.tableBid.clicked.connect(self.update_edit_from_bid_book)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)
        #enable clicking of OrderID links in the Trading textBrowser
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, 'tick'],
            [self.ui.checkBoxLogTrade, 'trade'],
            [self.ui.checkBoxLogDepth, 'depth'],
        ]
        #connect the channel checkboxes to the handler that persists the
        #settings to the config file
        for x in self.logchannels:
            x[0].clicked.connect(self.set_ignorechan)
        #read the config file and re-apply previous settings
        self.get_ignorechan()

        # activate market
        self.market.start()

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        #User Orders TAB
        self.modelOwns = ModelOwns(self, self.market, preferences)
        self.ui.tableUserOrders.setModel(self.modelOwns)
        self.ui.tableUserOrders.resizeColumnsToContents()
        self.ui.tableUserOrders.clicked.connect(self.userorder_selected)

        #create the stop orders TAB.
        self.modelStops = ModelStops(self, self.market)
        self.ui.tableStopOrders.setModel(self.modelStops)
        self.ui.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.ui.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.ui.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.ui.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.ui.checkBoxActivateStopLossBot.clicked.connect(
            self.stopbot_act_deact)

        #for stuff in the Ticker TAB
        self.ui.pushButtonRefreshTicker.released.connect(
            self.refresh_and_display_ticker)
        self.ui.checkBoxAutoRefreshTicker.clicked.connect(
            self.autorefresh_ticker_selected)

        #populate the ticker tab fields.
        self.display_ticker()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()
Пример #4
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)
        self.market.signal_ticker.connect(self.update_titlebar)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.ui.tableBid.clicked.connect(self.update_edit_from_bid_book)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)
        #enable clicking of OrderID links in the Trading textBrowser
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, 'tick'],
            [self.ui.checkBoxLogTrade, 'trade'],
            [self.ui.checkBoxLogDepth, 'depth'],
        ]
        #connect the channel checkboxes to the handler that persists the
        #settings to the config file
        for x in self.logchannels:
            x[0].clicked.connect(self.set_ignorechan)
        #read the config file and re-apply previous settings
        self.get_ignorechan()

        # activate market
        self.market.start()

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        #User Orders TAB
        self.modelOwns = ModelOwns(self, self.market, preferences)
        self.ui.tableUserOrders.setModel(self.modelOwns)
        self.ui.tableUserOrders.resizeColumnsToContents()
        self.ui.tableUserOrders.clicked.connect(self.userorder_selected)

        #create the stop orders TAB.
        self.modelStops = ModelStops(self, self.market)
        self.ui.tableStopOrders.setModel(self.modelStops)
        self.ui.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.ui.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.ui.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.ui.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.ui.checkBoxActivateStopLossBot.clicked.connect(
            self.stopbot_act_deact)

        #for stuff in the Ticker TAB
        self.ui.pushButtonRefreshTicker.released.connect(
            self.refresh_and_display_ticker)
        self.ui.checkBoxAutoRefreshTicker.clicked.connect(
            self.autorefresh_ticker_selected)

        #populate the ticker tab fields.
        self.display_ticker()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()

    def get_ignorechan(self):
        for x in self.logchannels:
            for y in self.preferences.ignore_channels:
                if x[1] == y:
                    x[0].setChecked(False)

    def set_ignorechan(self):
        ignore_channels = ""
        for x in self.logchannels:
            if not x[0].isChecked():
                ignore_channels += (x[1] + ' ')
        self.preferences.set("ignore_channels", ignore_channels)
        self.preferences.save()

    def adjust_for_mac(self):
        '''
        Fixes some stuff that looks good on windows but bad on mac.
        '''
        # the default fixed font is unreadable on mac, so replace it
        font = QtGui.QFont('Monaco', 11)
        changes = [
            self.ui.tableAsk, self.ui.tableBid, self.ui.tableUserOrders,
            self.ui.tableStopOrders, self.ui.textBrowserLog,
            self.ui.textBrowserStatus, self.ui.lineEditOrder,
            self.ui.doubleSpinBoxBtc, self.ui.doubleSpinBoxPrice,
            self.ui.doubleSpinBoxTotal
        ]
        for x in changes:
            x.setFont(font)

        # the space between application title bar and
        # the ui elements is too small on mac
        margins = self.ui.widgetMain.layout().contentsMargins()
        margins.setTop(24)
        self.ui.widgetMain.layout().setContentsMargins(margins)

    def show_preferences(self):

        result = self.preferences.show()
        if result == True:
            self.status_message('Preferences changed, restarting market.')
            self.market.stop()
            self.preferences.apply()
            self.market.start()
            self.status_message('Market restarted successfully.')

    def display_ticker(self):
        if not self.market.ticker.ticker_fast.get("error"):
            self.ui.lineEdit1Buy.setText("$" + self.market.ticker.buy)
            self.ui.lineEdit2Sell.setText("$" + self.market.ticker.sell)
            self.ui.lineEdit3Last.setText("$" + self.market.ticker.last)
        else:
            self.ui.lineEdit1Buy.setText("Error")
            self.ui.lineEdit2Sell.setText("Error")
            self.ui.lineEdit3Last.setText("Error")

        if not self.market.ticker.ticker2.get("error"):
            self.ui.lineEdit4Volume.setText(self.market.ticker.volumestr)
            self.ui.lineEdit5High.setText("$" + self.market.ticker.high)
            self.ui.lineEdit6Low.setText("$" + self.market.ticker.low)
            self.ui.lineEdit7Avg.setText("$" + self.market.ticker.avg)
            self.ui.lineEdit8VWAP.setText("$" + self.market.ticker.vwap)
        else:
            self.ui.lineEdit4Volume.setText("Error")
            self.ui.lineEdit5High.setText("Error")
            self.ui.lineEdit6Low.setText("Error")
            self.ui.lineEdit7Avg.setText("Error")
            self.ui.lineEdit8VWAP.setText("Error")

    def refresh_and_display_ticker(self, dummy_1=None, dummy_2=None):
        self.market.ticker.refresh_both()
        self.display_ticker()

    def autorefresh_ticker_selected(self):
        if self.ui.checkBoxAutoRefreshTicker.isChecked():
            interval = self.ui.spinBoxAutoRefreshTicker.value()
            self.market.ticker_refresh_timer = Timer(interval)
            self.market.ticker_refresh_timer.connect(
                self.refresh_and_display_ticker)
        else:
            if self.market.ticker_refresh_timer:
                self.market.ticker_refresh_timer.cancel()

    def add_stopOrder(self):
        size = float(self.ui.lineEdit1StopSize.text())  #read from input boxes
        price = float(self.ui.lineEdit2StopPrice.text())
        self.ui.lineEdit1StopSize.setText('')  #set input boxes to blank again
        self.ui.lineEdit2StopPrice.setText('')
        oid = len(
            self.market.gox.stopOrders
        ) + 1  #set OID number to a human number(OID# is actually just for us humans)
        self.market.gox.stopOrders.append([oid, size,
                                           price])  #add order to the list
        self.modelStops.changed()  #trigger the changed function

    def stopOrder_selected(self, index):
        self.ui.lineEdit3StopID.setText(
            str(self.modelStops.get(index.row(), 0)))

    def remove_stopOrder(self):
        oid = self.ui.lineEdit3StopID.text()  #read OID from the input box
        oid = int(oid) - 1  #change human OID to internal
        self.ui.lineEdit3StopID.setText('')  #set input box to blank
        self.market.gox.stopOrders.remove(
            self.market.gox.stopOrders[oid])  #remove order from the list
        self.modelStops.changed()  #trigger the changed function

    def stopbot_act_deact(self):
        if self.ui.checkBoxActivateStopLossBot.isChecked(
        ):  #if the checkbox is active
            self.market.gox.stopbot_active = True  #enable stop-loss bot
        else:
            self.market.gox.stopbot_active = False  #or disable it.

    def update_titlebar(self, bid, ask):
        #change the title bar to match any updates from the ticker channel
        try:
            volstring = ", Vol: " + self.market.ticker.volumestr[:-4] + " BTC"  #has some strange unicode char in it.
        except:
            volstring = ""
        newtitle = "MtGox Trading UI - Bid: {0}, Ask: {1}{2}".format(
            bid / 1E5, ask / 1E5, volstring)
        self.setWindowTitle(
            QtGui.QApplication.translate("ui", newtitle, None,
                                         QtGui.QApplication.UnicodeUTF8))

    def get_selected_trade_type(self):
        if self.ui.radioButtonBuy.isChecked():
            return 'BUY'
        else:
            return 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.ui.radioButtonBuy.toggle()
        else:
            self.ui.radioButtonSell.toggle()

    def slot_log(self, text):

        doOutput = False

        if self.ui.checkBoxLogSystem.isChecked():
            doOutput = True

        for entry in self.logchannels:
            if entry[1] in text:
                doOutput = entry[0].isChecked()
                break

        if doOutput:
            logging.info(text)
            text = self.prepend_date(text)
            self.ui.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        logging.info(text)
        text = self.prepend_date(text)
        self.ui.textBrowserStatus.moveCursor(QTextCursor.End)
        self.ui.textBrowserStatus.append(text)

    def set_wallet_a(self, value):
        self.ui.pushButtonWalletA.setEnabled(value > 0)
        self.ui.pushButtonWalletA.setText(
            self.market.curr_base + ': ' +
            utilities.gox2str(value, self.market.curr_base))

    def set_wallet_b(self, value):
        self.ui.pushButtonWalletB.setEnabled(value > 0)
        self.ui.pushButtonWalletB.setText(
            self.market.curr_quote + ': ' +
            utilities.gox2str(value, self.market.curr_quote, 5))

    def get_trade_size(self):
        return self.ui.doubleSpinBoxBtc.value()

    def set_trade_size(self, value):
        value = utilities.gox2float(value, self.market.curr_base)
        self.ui.doubleSpinBoxBtc.setValue(value)

    def get_trade_price(self):
        return self.ui.doubleSpinBoxPrice.value()

    def set_trade_price(self, value):
        value = utilities.gox2float(value, self.market.curr_quote)
        self.ui.doubleSpinBoxPrice.setValue(value)

    def get_trade_total(self):
        return self.ui.doubleSpinBoxTotal.value()

    def set_trade_total(self, value):
        value = utilities.gox2float(value, self.market.curr_quote)
        self.ui.doubleSpinBoxTotal.setValue(value)

    def get_order_id(self):
        return str(self.ui.lineEditOrder.text())

    def set_order_id(self, text):
        self.ui.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def display_wallet(self):
        self.set_wallet_a(self.market.get_balance(self.market.curr_base))
        self.set_wallet_b(self.market.get_balance(self.market.curr_quote))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(self.market.get_balance(self.market.curr_base))
        self.set_selected_trade_type('SELL')

    def set_trade_total_from_wallet(self):
        self.set_trade_total(self.market.get_balance(self.market.curr_quote))
        self.set_selected_trade_type('BUY')

    def display_orderlag(self, ms, text):
        self.ui.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = price * size
        self.set_trade_total(utilities.float2gox(total,
                                                 self.market.curr_quote))

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message(
            'Placing order: {0} {1} {2} at {3} {4} (total {5} {4})...'.
            format(  # @IgnorePep8
                trade_name, utilities.float2str(size,
                                                8), self.market.curr_base,
                utilities.float2str(price, 5), self.market.curr_quote,
                utilities.float2str(total, 6)))

        priceGox = utilities.float2gox(price, self.market.curr_quote)
        sizeGox = utilities.float2gox(size, self.market.curr_base)
        if trade_type == 'BUY':
            self.market.buy(priceGox, sizeGox)
        else:
            self.market.sell(priceGox, sizeGox)

    def recalculate_size(self):
        #When the size button is clicked:
        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        #divide Total by Price and fill the size edit box in.
        size = total / price
        self.set_trade_size(utilities.float2gox(size, self.market.curr_base))

    def recalculate_total(self):
        #When the total button is clicked
        price = self.get_trade_price()
        size = self.get_trade_size()
        #Multiply Price by Size and fill the total edit box in
        total = price * size
        self.set_trade_total(utilities.float2gox(total,
                                                 self.market.curr_quote))

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2str(size, self.market.curr_base)
        price = utilities.gox2str(price, self.market.curr_quote, 5)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message(
                "{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}"
                .format(  # @IgnorePep8
                    str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)

    def userorder_selected(self, index):
        mapdict = {"ask": "SELL", "bid": "BUY"}
        self.set_selected_trade_type(mapdict[self.modelOwns.get_typ(
            index.row())])
        self.set_trade_price(self.modelOwns.get_price(index.row()))
        self.set_trade_size(self.modelOwns.get_size(index.row()))
        self.set_order_id(self.modelOwns.get_oid(index.row()))

    def cancel_order(self):
        if self.ui.checkBoxCancelAll.isChecked():
            self.market.cancel_by_type()
            self.ui.checkBoxCancelAll.setChecked(False)
        else:
            order_id = self.get_order_id()
            self.status_message(
                "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
            self.market.cancel(order_id)

    def update_edit_from_ask_book(self, index):
        #when a order on the ask side is clicked
        #set the radio button to the opposite (buy)
        self.set_trade_price(self.modelAsk.get_price(
            index.row()))  #set the price edit box
        self.set_trade_size(self.modelAsk.get_size(
            index.row()))  #set the size edit box
        self.set_selected_trade_type('BUY')  #set the BUY radiobutton

    def update_edit_from_bid_book(self, index):
        #when a order on the bids side is clicked
        #set the radio button to the opposite (sell)
        self.set_trade_price(self.modelBid.get_price(
            index.row()))  #set the price edit box
        self.set_trade_size(self.modelBid.get_size(
            index.row()))  #set the size edit box
        self.set_selected_trade_type('SELL')  #set the SELL radiobutton

    def update_edit_on_button(self):
        #When Price button is clicked, fill in the edit boxes,
        trade_type = self.get_selected_trade_type()
        #depending on which radiobutton "Buy" or "Sell" is selected at the time,
        #get the OPPOSITE side's current best price and the corresponding size
        mapdict = {"SELL": self.modelBid, "BUY": self.modelAsk}
        self.set_trade_price(mapdict[trade_type].get_price(0))
        self.set_trade_size(mapdict[trade_type].get_size(0))
        #so you can fulfill that person's current best offer just by clicking Go.
        #(This functionality is something I want, and I can understand it being confusing having it on this button)
        #because the size button behaves normally the original way still.
        #similarly confusing having it map to the opposite side (but necessary)
        #

    def stop(self):
        self.market.stop()
Пример #5
0
    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret

        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        self.mainWindow.pushButtonApply.released.connect(
            self.save_credentials)
        self.mainWindow.pushButtonGo.released.connect(
            self.execute_trade)
        self.mainWindow.tableAsk.clicked.connect(
            self.update_price_from_asks)
        self.mainWindow.tableBid.clicked.connect(
            self.update_price_from_bids)
        self.mainWindow.pushButtonCancel.released.connect(
            self.cancel_order)
        self.mainWindow.textBrowserStatus.anchorClicked.connect(
            self.order_selected)
        self.mainWindow.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.mainWindow.pushButtonSize.released.connect(
            self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(
            self.update_price_best)
        self.mainWindow.pushButtonTotal.released.connect(
            self.recalculate_total)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.checkBoxLogTicker, 'tick'],
            [self.mainWindow.checkBoxLogTrade, 'TRADE'],
            [self.mainWindow.checkBoxLogDepth, 'depth'],
        ]

        # load credentials from configuration file
        self.load_credentials()

        self.show()
        self.raise_()
Пример #6
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''

    # how the application-proposed bid will differ from the selected bid
    ADD_TO_BID = 1

    # how the application-proposed ask will differ from the selected ask
    SUB_FROM_ASK = 1

    PASSPHRASE = 'fffuuuuuuu'

    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret

        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        self.mainWindow.pushButtonApply.released.connect(
            self.save_credentials)
        self.mainWindow.pushButtonGo.released.connect(
            self.execute_trade)
        self.mainWindow.tableAsk.clicked.connect(
            self.update_price_from_asks)
        self.mainWindow.tableBid.clicked.connect(
            self.update_price_from_bids)
        self.mainWindow.pushButtonCancel.released.connect(
            self.cancel_order)
        self.mainWindow.textBrowserStatus.anchorClicked.connect(
            self.order_selected)
        self.mainWindow.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.mainWindow.pushButtonSize.released.connect(
            self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(
            self.update_price_best)
        self.mainWindow.pushButtonTotal.released.connect(
            self.recalculate_total)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.checkBoxLogTicker, 'tick'],
            [self.mainWindow.checkBoxLogTrade, 'TRADE'],
            [self.mainWindow.checkBoxLogDepth, 'depth'],
        ]

        # load credentials from configuration file
        self.load_credentials()

        self.show()
        self.raise_()

    def restart_gox(self):
        '''
        Restarts gox by closing the connection
        (recommended by prof7bit)
        '''
        if self.gox.client.socket:
            self.gox.client.socket.close()

    def get_selected_trade_type(self):
        if self.mainWindow.radioButtonBuy.isChecked():
            return 'BUY'
        else:
            return 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.mainWindow.radioButtonBuy.toggle()
        else:
            self.mainWindow.radioButtonSell.toggle()

    def log(self, text):

        text = self.prepend_date(text)
        self.log_to_file(text)

        doOutput = False

        if self.mainWindow.checkBoxLogSystem.isChecked():
            doOutput = True
        else:
            for entry in self.logchannels:
                if entry[0].isChecked() and entry[1] in text:
                    doOutput = True

        if doOutput:
            self.mainWindow.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def log_to_file(self, text):
        if not self.logfile.closed:
            self.logfile.write('{}{}'.format(text, os.linesep))

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        self.mainWindow.textBrowserStatus.moveCursor(QTextCursor.End)
        text = self.prepend_date(text)
        self.mainWindow.textBrowserStatus.append(text)
        self.log_to_file(text)

    def set_wallet_btc(self, value):
        self.mainWindow.pushButtonWalletA.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletA.setText(
            'BTC: ' + utilities.internal2str(value))

    def set_wallet_usd(self, value):
        self.mainWindow.pushButtonWalletB.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletB.setText(
            'USD: ' + utilities.internal2str(value, 5))

    def get_trade_size(self):
        value = self.mainWindow.doubleSpinBoxBtc.value()
        return utilities.float2internal(value)

    def set_trade_size(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxBtc.setValue(value_float)

    def get_trade_price(self):
        value = self.mainWindow.doubleSpinBoxPrice.value()
        return utilities.float2internal(value)

    def set_trade_price(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxPrice.setValue(value_float)

    def get_trade_total(self):
        value = self.mainWindow.doubleSpinBoxTotal.value()
        return utilities.float2internal(value)

    def set_trade_total(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxTotal.setValue(value_float)

    def get_order_id(self):
        return str(self.mainWindow.lineEditOrder.text())

    def set_order_id(self, text):
        self.mainWindow.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def save_credentials(self):
        '''
        Tries to encrypt the credentials entered by the user
        and save them to the configuration file.
        Incomplete or inplausible credentials will not be saved.
        '''

        key = str(format(self.mainWindow.lineEditKey.text()))
        secret = str(self.mainWindow.lineEditSecret.text())

        if key == '':
            self.status_message("Credentials not saved (empty key).")
            return

        if secret == '':
            self.status_message("Credentials not saved (empty secret).")
            return

        try:
            utilities.assert_valid_key(key)
        except Exception:
            self.status_message("Credentials not saved (invalid key).")
            return

        try:
            secret = utilities.encrypt(secret, View.PASSPHRASE)
        except Exception:
            self.status_message("Credentials not saved (invalid secret).")
            return

        self.gox.config.set("gox", "secret_key", key)
        self.gox.config.set("gox", "secret_secret", secret)
        self.gox.config.save()
        self.status_message("Credentials saved.")
        self.load_credentials()
        self.restart_gox()

    def load_credentials(self):
        '''
        Tries to load the credentials from the configuration file
        and display them to the user. If the credentials in the
        configuration file are invalid, they will not be loaded.
        '''

        key = self.gox.config.get_string("gox", "secret_key")
        secret = self.gox.config.get_string("gox", "secret_secret")

        try:
            utilities.assert_valid_key(key)
            secret = utilities.decrypt(secret, View.PASSPHRASE)
        except Exception:
            key = ''
            secret = ''

        self.secret.key = key
        self.mainWindow.lineEditKey.setText(key)
        self.secret.secret = secret
        self.mainWindow.lineEditSecret.setText(secret)

    def display_wallet(self):
        self.set_wallet_usd(
            utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_wallet_btc(
            utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(
            utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))
        self.set_selected_trade_type('SELL')

    def set_trade_total_from_wallet(self):
        self.set_trade_total(
            utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_selected_trade_type('BUY')

    def display_orderlag(self, ms, text):
        self.mainWindow.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = self.get_trade_total()

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message('Placing order: {0} {1} BTC at {2} USD (total {3} USD)...'.format(# @IgnorePep8
            trade_name,
            utilities.internal2str(size),
            utilities.internal2str(price, 5),
            utilities.internal2str(total, 5)))

        sizeGox = utilities.internal2gox(size, 'BTC')
        priceGox = utilities.internal2gox(price, 'USD')

        if trade_type == 'BUY':
            self.gox.buy(priceGox, sizeGox)
        else:
            self.gox.sell(priceGox, sizeGox)

    def recalculate_size(self):

        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        size = utilities.divide_internal(total, price)
        self.set_trade_size(size)

    def recalculate_total(self):

        price = self.get_trade_price()
        size = self.get_trade_size()
        total = utilities.multiply_internal(price, size)
        self.set_trade_total(total)

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2internal(size, 'BTC')
        price = utilities.gox2internal(price, 'USD')

        size = utilities.internal2str(size)
        price = utilities.internal2str(price)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message("{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}".format(# @IgnorePep8
                str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)

    def update_price_from_asks(self, index):
        self.set_trade_price(self.modelAsk.get_price(index.row())
            - self.SUB_FROM_ASK)

    def update_price_from_bids(self, index):
        self.set_trade_price(self.modelBid.get_price(index.row())
            + self.ADD_TO_BID)

    def cancel_order(self):
        order_id = self.get_order_id()
        self.status_message(
            "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
        self.gox.cancel(order_id)

    def update_price_best(self):

        trade_type = self.get_selected_trade_type()
        if trade_type == 'BUY':
            price = self.modelBid.get_price(0)
            price += self.ADD_TO_BID
            self.set_trade_price(price)
        elif trade_type == 'SELL':
            price = self.modelAsk.get_price(0)
            price -= self.SUB_FROM_ASK
            self.set_trade_price(price)
Пример #7
0
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)
        self.market.signal_ticker.connect(self.update_titlebar)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.ui.tableBid.clicked.connect(self.update_edit_from_bid_book)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)       
        #enable clicking of OrderID links in the Trading textBrowser
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, 'tick'],
            [self.ui.checkBoxLogTrade, 'trade'],
            [self.ui.checkBoxLogDepth, 'depth'],
        ]
        #connect the channel checkboxes to the handler that persists the
        #settings to the config file
        for x in self.logchannels:
            x[0].clicked.connect(self.set_ignorechan)
        #read the config file and re-apply previous settings
        self.get_ignorechan()
        
        # activate market
        self.market.start()
        
        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        #User Orders TAB
        self.modelOwns = ModelOwns(self, self.market, preferences)
        self.ui.tableUserOrders.setModel(self.modelOwns)
        self.ui.tableUserOrders.resizeColumnsToContents()
        self.ui.tableUserOrders.clicked.connect(self.userorder_selected)

        #create the stop orders TAB.
        self.modelStops = ModelStops(self, self.market)
        self.ui.tableStopOrders.setModel(self.modelStops)
        self.ui.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.ui.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.ui.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.ui.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.ui.checkBoxActivateStopLossBot.clicked.connect(self.stopbot_act_deact)
        
        #for stuff in the Ticker TAB
        self.ui.pushButtonRefreshTicker.released.connect(self.refresh_and_display_ticker)
        self.ui.checkBoxAutoRefreshTicker.clicked.connect(self.autorefresh_ticker_selected)

        #populate the ticker tab fields.
        self.display_ticker()
        
        # show main window
        self.adjustSize()
        self.show()
        self.raise_()
Пример #8
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)
        self.market.signal_ticker.connect(self.update_titlebar)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.ui.tableBid.clicked.connect(self.update_edit_from_bid_book)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)       
        #enable clicking of OrderID links in the Trading textBrowser
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, 'tick'],
            [self.ui.checkBoxLogTrade, 'trade'],
            [self.ui.checkBoxLogDepth, 'depth'],
        ]
        #connect the channel checkboxes to the handler that persists the
        #settings to the config file
        for x in self.logchannels:
            x[0].clicked.connect(self.set_ignorechan)
        #read the config file and re-apply previous settings
        self.get_ignorechan()
        
        # activate market
        self.market.start()
        
        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        #User Orders TAB
        self.modelOwns = ModelOwns(self, self.market, preferences)
        self.ui.tableUserOrders.setModel(self.modelOwns)
        self.ui.tableUserOrders.resizeColumnsToContents()
        self.ui.tableUserOrders.clicked.connect(self.userorder_selected)

        #create the stop orders TAB.
        self.modelStops = ModelStops(self, self.market)
        self.ui.tableStopOrders.setModel(self.modelStops)
        self.ui.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.ui.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.ui.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.ui.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.ui.checkBoxActivateStopLossBot.clicked.connect(self.stopbot_act_deact)
        
        #for stuff in the Ticker TAB
        self.ui.pushButtonRefreshTicker.released.connect(self.refresh_and_display_ticker)
        self.ui.checkBoxAutoRefreshTicker.clicked.connect(self.autorefresh_ticker_selected)

        #populate the ticker tab fields.
        self.display_ticker()
        
        # show main window
        self.adjustSize()
        self.show()
        self.raise_()
        

    def get_ignorechan(self):
        for x in self.logchannels:
            for y in self.preferences.ignore_channels:
                if x[1] == y:
                    x[0].setChecked(False)
            
    def set_ignorechan(self):
        ignore_channels = ""
        for x in self.logchannels:            
            if not x[0].isChecked():
                ignore_channels += (x[1] + ' ')
        self.preferences.set("ignore_channels",ignore_channels)
        self.preferences.save()
        
    def adjust_for_mac(self):
        '''
        Fixes some stuff that looks good on windows but bad on mac.
        '''
        # the default fixed font is unreadable on mac, so replace it
        font = QtGui.QFont('Monaco', 11)
        changes = [
            self.ui.tableAsk,
            self.ui.tableBid,
            self.ui.tableUserOrders,
            self.ui.tableStopOrders,
            self.ui.textBrowserLog,
            self.ui.textBrowserStatus,
            self.ui.lineEditOrder,
            self.ui.doubleSpinBoxBtc,
            self.ui.doubleSpinBoxPrice,
            self.ui.doubleSpinBoxTotal
            ]
        for x in changes:
            x.setFont(font)

        # the space between application title bar and
        # the ui elements is too small on mac
        margins = self.ui.widgetMain.layout().contentsMargins()
        margins.setTop(24)
        self.ui.widgetMain.layout().setContentsMargins(margins)

    def show_preferences(self):

        result = self.preferences.show()
        if result == True:
            self.status_message('Preferences changed, restarting market.')
            self.market.stop()
            self.preferences.apply()
            self.market.start()
            self.status_message('Market restarted successfully.')
        
        
    def display_ticker(self):
        if not self.market.ticker.ticker_fast.get("error"):
            self.ui.lineEdit1Buy.setText("$" + self.market.ticker.buy)
            self.ui.lineEdit2Sell.setText("$" + self.market.ticker.sell)
            self.ui.lineEdit3Last.setText("$" + self.market.ticker.last)
        else:
            self.ui.lineEdit1Buy.setText("Error")
            self.ui.lineEdit2Sell.setText("Error")
            self.ui.lineEdit3Last.setText("Error")

        if not self.market.ticker.ticker2.get("error"):
            self.ui.lineEdit4Volume.setText(self.market.ticker.volumestr)
            self.ui.lineEdit5High.setText("$" + self.market.ticker.high)
            self.ui.lineEdit6Low.setText("$" + self.market.ticker.low)
            self.ui.lineEdit7Avg.setText("$" + self.market.ticker.avg)
            self.ui.lineEdit8VWAP.setText("$" + self.market.ticker.vwap)
        else:
            self.ui.lineEdit4Volume.setText("Error")
            self.ui.lineEdit5High.setText("Error")
            self.ui.lineEdit6Low.setText("Error")
            self.ui.lineEdit7Avg.setText("Error")
            self.ui.lineEdit8VWAP.setText("Error")
            

    def refresh_and_display_ticker(self,dummy_1=None,dummy_2=None):
        self.market.ticker.refresh_both()
        self.display_ticker()
                    
    def autorefresh_ticker_selected(self):
        if self.ui.checkBoxAutoRefreshTicker.isChecked():
            interval = self.ui.spinBoxAutoRefreshTicker.value()
            self.market.ticker_refresh_timer = Timer(interval)
            self.market.ticker_refresh_timer.connect(self.refresh_and_display_ticker)
        else:
            if self.market.ticker_refresh_timer:
                self.market.ticker_refresh_timer.cancel()
        
        
    def add_stopOrder(self):
        size = float(self.ui.lineEdit1StopSize.text())  #read from input boxes
        price = float(self.ui.lineEdit2StopPrice.text())
        self.ui.lineEdit1StopSize.setText('')   #set input boxes to blank again
        self.ui.lineEdit2StopPrice.setText('')
        oid = len(self.market.gox.stopOrders)+1                #set OID number to a human number(OID# is actually just for us humans)
        self.market.gox.stopOrders.append([oid,size,price])    #add order to the list
        self.modelStops.changed()                       #trigger the changed function

    def stopOrder_selected(self, index):
        self.ui.lineEdit3StopID.setText(str(self.modelStops.get(index.row(),0)))        
        
    def remove_stopOrder(self):
        oid = self.ui.lineEdit3StopID.text()    #read OID from the input box
        oid = int(oid)-1                                #change human OID to internal
        self.ui.lineEdit3StopID.setText('')     #set input box to blank
        self.market.gox.stopOrders.remove(self.market.gox.stopOrders[oid])    #remove order from the list
        self.modelStops.changed()                       #trigger the changed function

    def stopbot_act_deact(self):
        if self.ui.checkBoxActivateStopLossBot.isChecked():     #if the checkbox is active
            self.market.gox.stopbot_active = True              #enable stop-loss bot
        else:
            self.market.gox.stopbot_active = False             #or disable it.

    def update_titlebar(self,bid,ask):
        #change the title bar to match any updates from the ticker channel
        try:
            volstring = ", Vol: " + self.market.ticker.volumestr[:-4] + " BTC" #has some strange unicode char in it.
        except:
            volstring = ""
        newtitle = "MtGox Trading UI - Bid: {0}, Ask: {1}{2}".format(bid/1E5,ask/1E5,volstring)
        self.setWindowTitle(QtGui.QApplication.translate("ui", newtitle, None, QtGui.QApplication.UnicodeUTF8))
        
    def get_selected_trade_type(self):
        if self.ui.radioButtonBuy.isChecked():
            return 'BUY'
        else:
            return 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.ui.radioButtonBuy.toggle()
        else:
            self.ui.radioButtonSell.toggle()

    def slot_log(self, text):

        doOutput = False

        if self.ui.checkBoxLogSystem.isChecked():
            doOutput = True

        for entry in self.logchannels:
            if entry[1] in text:
                doOutput = entry[0].isChecked()
                break

        if doOutput:
            logging.info(text)
            text = self.prepend_date(text)            
            self.ui.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        logging.info(text)
        text = self.prepend_date(text)
        self.ui.textBrowserStatus.moveCursor(QTextCursor.End)
        self.ui.textBrowserStatus.append(text)

    def set_wallet_a(self, value):
        self.ui.pushButtonWalletA.setEnabled(value > 0)
        self.ui.pushButtonWalletA.setText(
            self.market.curr_base + ': ' + utilities.gox2str(value, self.market.curr_base))

    def set_wallet_b(self, value):
        self.ui.pushButtonWalletB.setEnabled(value > 0)
        self.ui.pushButtonWalletB.setText(
            self.market.curr_quote + ': ' + utilities.gox2str(value, self.market.curr_quote, 5))

    def get_trade_size(self):
        return self.ui.doubleSpinBoxBtc.value()

    def set_trade_size(self, value):
        value = utilities.gox2float(value,self.market.curr_base)
        self.ui.doubleSpinBoxBtc.setValue(value)

    def get_trade_price(self):
        return self.ui.doubleSpinBoxPrice.value()

    def set_trade_price(self, value):
        value = utilities.gox2float(value,self.market.curr_quote)
        self.ui.doubleSpinBoxPrice.setValue(value)

    def get_trade_total(self):
        return self.ui.doubleSpinBoxTotal.value()

    def set_trade_total(self, value):
        value = utilities.gox2float(value,self.market.curr_quote)
        self.ui.doubleSpinBoxTotal.setValue(value)

    def get_order_id(self):
        return str(self.ui.lineEditOrder.text())

    def set_order_id(self, text):
        self.ui.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def display_wallet(self):
        self.set_wallet_a(self.market.get_balance(self.market.curr_base))
        self.set_wallet_b(self.market.get_balance(self.market.curr_quote))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(self.market.get_balance(self.market.curr_base))
        self.set_selected_trade_type('SELL')

    def set_trade_total_from_wallet(self):
        self.set_trade_total(self.market.get_balance(self.market.curr_quote))
        self.set_selected_trade_type('BUY')

    def display_orderlag(self, ms, text):
        self.ui.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = price * size
        self.set_trade_total(utilities.float2gox(total,self.market.curr_quote))

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message('Placing order: {0} {1} {2} at {3} {4} (total {5} {4})...'.format(# @IgnorePep8
            trade_name,
            utilities.float2str(size, 8),
            self.market.curr_base,
            utilities.float2str(price, 5),
            self.market.curr_quote,
            utilities.float2str(total, 6)))
        
        priceGox = utilities.float2gox(price, self.market.curr_quote)
        sizeGox = utilities.float2gox(size, self.market.curr_base)
        if trade_type == 'BUY':
            self.market.buy(priceGox, sizeGox)
        else:
            self.market.sell(priceGox, sizeGox)

    def recalculate_size(self):
        #When the size button is clicked:
        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        #divide Total by Price and fill the size edit box in.
        size = total / price
        self.set_trade_size(utilities.float2gox(size,self.market.curr_base))

    def recalculate_total(self):
        #When the total button is clicked
        price = self.get_trade_price()
        size = self.get_trade_size()
        #Multiply Price by Size and fill the total edit box in
        total = price * size
        self.set_trade_total(utilities.float2gox(total,self.market.curr_quote))

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2str(size, self.market.curr_base)
        price = utilities.gox2str(price, self.market.curr_quote,5)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message("{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}".format(# @IgnorePep8
                str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)
                
    def userorder_selected(self, index):
        mapdict = {"ask":"SELL","bid":"BUY"}
        self.set_selected_trade_type(mapdict[self.modelOwns.get_typ(index.row())])
        self.set_trade_price(self.modelOwns.get_price(index.row()))
        self.set_trade_size(self.modelOwns.get_size(index.row()))
        self.set_order_id(self.modelOwns.get_oid(index.row()))
        
    def cancel_order(self):
        if self.ui.checkBoxCancelAll.isChecked():
            self.market.cancel_by_type()
            self.ui.checkBoxCancelAll.setChecked(False)
        else:
            order_id = self.get_order_id()
            self.status_message(
                "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
            self.market.cancel(order_id)
            
    def update_edit_from_ask_book(self, index):
        #when a order on the ask side is clicked
        #set the radio button to the opposite (buy) 
        self.set_trade_price(self.modelAsk.get_price(index.row()))  #set the price edit box 
        self.set_trade_size(self.modelAsk.get_size(index.row()))    #set the size edit box
        self.set_selected_trade_type('BUY')                        #set the BUY radiobutton
        
    def update_edit_from_bid_book(self, index):
        #when a order on the bids side is clicked 
        #set the radio button to the opposite (sell)
        self.set_trade_price(self.modelBid.get_price(index.row()))  #set the price edit box
        self.set_trade_size(self.modelBid.get_size(index.row()))    #set the size edit box
        self.set_selected_trade_type('SELL')                         #set the SELL radiobutton
       
    def update_edit_on_button(self):
        #When Price button is clicked, fill in the edit boxes, 
        trade_type = self.get_selected_trade_type()
        #depending on which radiobutton "Buy" or "Sell" is selected at the time,
        #get the OPPOSITE side's current best price and the corresponding size 
        mapdict = {"SELL":self.modelBid,"BUY":self.modelAsk}
        self.set_trade_price(mapdict[trade_type].get_price(0))
        self.set_trade_size(mapdict[trade_type].get_size(0))        
        #so you can fulfill that person's current best offer just by clicking Go.
        #(This functionality is something I want, and I can understand it being confusing having it on this button)
        #because the size button behaves normally the original way still.
        #similarly confusing having it map to the opposite side (but necessary)
        #

    def stop(self):
        self.market.stop()        
Пример #9
0
class View(QMainWindow):
    """
    Represents the combined view / control.
    """

    # how the application-proposed bid
    # will differ from the selected bid (in pips)
    ADD_TO_BID_PIPS = 1

    # how the application-proposed ask
    # will differ from the selected ask (in pips)
    SUB_FROM_ASK_PIPS = 1

    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.slot_update_price_from_asks)
        self.ui.tableBid.clicked.connect(self.slot_update_price_from_bids)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_price_best)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market, preferences)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market, preferences)
        self.ui.tableBid.setModel(self.modelBid)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, "tick"],
            [self.ui.checkBoxLogTrade, "TRADE"],
            [self.ui.checkBoxLogDepth, "depth"],
        ]

        # resets dynamic ui elements
        self.reset()

        # activate market
        self.market.start()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()

    def get_base_currency(self):
        return self.preferences.get_currency(Preferences.CURRENCY_INDEX_BASE)

    def get_quote_currency(self):
        return self.preferences.get_currency(Preferences.CURRENCY_INDEX_QUOTE)

    def reset(self):

        # initialize wallet values
        self.set_wallet_a(None)
        self.set_wallet_b(None)

        # adjust decimal values to current currencies
        self.adjust_decimals()

    def adjust_decimals(self):
        currencyQuote = self.get_quote_currency()
        currencyBase = self.get_base_currency()
        self.ui.doubleSpinBoxSize.setDecimals(currencyBase.decimals)
        self.ui.doubleSpinBoxPrice.setDecimals(currencyQuote.decimals)
        self.ui.doubleSpinBoxTotal.setDecimals(currencyQuote.decimals)

    def adjust_for_mac(self):
        """
        Fixes some stuff that looks good on windows but bad on mac.
        """
        # the default fixed font is unreadable on mac, so replace it
        font = QtGui.QFont("Monaco", 11)
        self.ui.tableAsk.setFont(font)
        self.ui.tableBid.setFont(font)
        self.ui.textBrowserLog.setFont(font)
        self.ui.textBrowserStatus.setFont(font)
        self.ui.lineEditOrder.setFont(font)
        self.ui.doubleSpinBoxSize.setFont(font)
        self.ui.doubleSpinBoxPrice.setFont(font)
        self.ui.doubleSpinBoxTotal.setFont(font)

        # the space between application title bar and
        # the ui elements is too small on mac
        margins = self.ui.widgetMain.layout().contentsMargins()
        margins.setTop(24)
        self.ui.widgetMain.layout().setContentsMargins(margins)

    def show_preferences(self):

        result = self.preferences.show()
        if result == True:
            self.status_message("Preferences changed, restarting market.")
            self.market.stop()
            self.preferences.apply()
            self.reset()
            self.market.start()
            self.status_message("Market restarted successfully.")

    def get_selected_trade_type(self):
        if self.ui.radioButtonBuy.isChecked():
            return "BUY"
        else:
            return "SELL"

    def set_selected_trade_type(self, trade_type):
        if trade_type == "BUY":
            self.ui.radioButtonBuy.toggle()
        else:
            self.ui.radioButtonSell.toggle()

    def slot_log(self, text):

        logging.info(text)
        text = self.prepend_date(text)

        doOutput = False

        if self.ui.checkBoxLogSystem.isChecked():
            doOutput = True

        for entry in self.logchannels:
            if entry[1] in text:
                doOutput = entry[0].isChecked()

        if doOutput:
            self.ui.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return "{}.{:0>3} {}".format(time.strftime("%X"), millis, text)

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        logging.info(text)
        text = self.prepend_date(text)
        self.ui.textBrowserStatus.moveCursor(QTextCursor.End)
        self.ui.textBrowserStatus.append(text)

    def set_wallet_a(self, value):

        if value == None:
            self.ui.pushButtonWalletA.setEnabled(False)
            self.ui.pushButtonWalletA.setText("n/a")
            return

        self.ui.pushButtonWalletA.setEnabled(True)
        self.ui.pushButtonWalletA.setText(money.to_long_string(value, self.get_base_currency()))

    def set_wallet_b(self, value):

        if value == None:
            self.ui.pushButtonWalletB.setEnabled(False)
            self.ui.pushButtonWalletB.setText("n/a")
            return

        self.ui.pushButtonWalletB.setEnabled(True)
        self.ui.pushButtonWalletB.setText(money.to_long_string(value, self.get_quote_currency()))

    def get_trade_size(self):
        return money.to_money(self.ui.doubleSpinBoxSize.value())

    def set_trade_size(self, value):
        self.ui.doubleSpinBoxSize.setValue(money.to_float(value))

    def get_trade_price(self):
        return money.to_money(self.ui.doubleSpinBoxPrice.value())

    def set_trade_price(self, value):
        self.ui.doubleSpinBoxPrice.setValue(money.to_float(value))

    def get_trade_total(self):
        return money.to_money(self.ui.doubleSpinBoxTotal.value())

    def set_trade_total(self, value):
        self.ui.doubleSpinBoxTotal.setValue(money.to_float(value))

    def get_order_id(self):
        return str(self.ui.lineEditOrder.text())

    def set_order_id(self, text):
        self.ui.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def display_wallet(self):

        self.set_wallet_a(self.market.get_balance(Preferences.CURRENCY_INDEX_BASE))
        self.set_wallet_b(self.market.get_balance(Preferences.CURRENCY_INDEX_QUOTE))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(self.market.get_balance(Preferences.CURRENCY_INDEX_BASE))
        self.set_selected_trade_type("SELL")

    def set_trade_total_from_wallet(self):
        self.set_trade_total(self.market.get_balance(Preferences.CURRENCY_INDEX_QUOTE))
        self.set_selected_trade_type("BUY")

    def display_orderlag(self, ms, text):
        self.ui.labelOrderlag.setText("Trading Lag: " + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = money.multiply(price, size)

        trade_name = "BID" if trade_type == "BUY" else "ASK"

        self.status_message(
            "Placing order: {0} {1} at {2} (total {3})...".format(  # @IgnorePep8
                trade_name,
                money.to_long_string(size, self.get_base_currency()),
                money.to_long_string(price, self.get_quote_currency()),
                money.to_long_string(total, self.get_quote_currency()),
            )
        )

        if trade_type == "BUY":
            self.market.buy(price, size)
        else:
            self.market.sell(price, size)

    def recalculate_size(self):

        price = self.get_trade_price()

        if price == 0:
            return

        total = self.get_trade_total()
        size = money.divide(total, price)
        self.set_trade_size(size)

    def recalculate_total(self):

        price = self.get_trade_price()
        size = self.get_trade_size()
        total = money.multiply(price, size)

        self.set_trade_total(total)

    def display_userorder(self, price, size, order_type, oid, status):

        if order_type == "":
            self.status_message('Order <a href="{0}">{0}</a> {1}.'.format(oid, status))
            if status == "removed" and self.get_order_id() == oid:
                self.set_order_id("")
        else:
            self.status_message(
                '{0} size: {1}, price: {2}, oid: <a href="{3}">{3}</a> - {4}'.format(  # @IgnorePep8
                    str.upper(str(order_type)),
                    money.to_long_string(size, self.get_base_currency()),
                    money.to_long_string(price, self.get_quote_currency()),
                    oid,
                    status,
                )
            )
            if status == "post-pending":
                self.set_order_id(oid)

    def slot_update_price_from_asks(self, index):
        self.update_price_from_asks(index.row())

    def update_price_from_asks(self, row):
        value = self.modelAsk.get_price(row)
        pip = money.pip(self.get_quote_currency()) * View.SUB_FROM_ASK_PIPS
        self.set_trade_price(value - pip)

    def slot_update_price_from_bids(self, index):
        self.update_price_from_bids(index.row())

    def update_price_from_bids(self, row):
        value = self.modelBid.get_price(row)
        pip = money.pip(self.get_quote_currency()) * View.SUB_FROM_ASK_PIPS
        self.set_trade_price(value + pip)

    def cancel_order(self):
        order_id = self.get_order_id()
        self.status_message('Cancelling order <a href="{0}">{0}</a>...'.format(order_id))
        self.market.cancel(order_id)

    def update_price_best(self):

        trade_type = self.get_selected_trade_type()
        if trade_type == "BUY":
            self.update_price_from_bids(0)
        elif trade_type == "SELL":
            self.update_price_from_asks(0)

    def stop(self):
        self.market.stop()
Пример #10
0
    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret
        
        #lazy users can create a section in the goxtool ini file such as : 
        #[goxgui]
        #password = XXXXXXXX
        #and it will decrypt the saved credentials also in the ini file with this password
        try:
            self.passphrase = self.gox.config.get("goxgui", "password")
        except:
            self.passphrase = ""
        if self.passphrase:
            self.load_credentials(passphrase=self.passphrase)
            
        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.tickerCheckBox, 'tick'],
            [self.mainWindow.tradesCheckBox, 'trade'],
            [self.mainWindow.depthCheckBox, 'depth'],
        ]
        
        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)
        self.adaptor.signal_ticker.connect(self.update_titlebar)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        #Account Balance TAB
        self.mainWindow.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)

        #Auth TAB
        self.mainWindow.pushButtonApply.released.connect(self.save_credentials)
        #Password TAB
        self.mainWindow.passwordButton.released.connect(self.load_credentials)
        
        #OrderBook TAB
        self.mainWindow.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.mainWindow.tableBid.clicked.connect(self.update_edit_from_bid_book)
        
        #User Orders TAB
        self.modelOwns = ModelOwns(self.gox)
        self.mainWindow.tableUserOrders.setModel(self.modelOwns)
        self.mainWindow.tableUserOrders.resizeColumnsToContents()
        self.mainWindow.tableUserOrders.clicked.connect(self.userorder_selected)
        
        #Trading Box
        self.mainWindow.pushButtonGo.released.connect(self.execute_trade)
        self.mainWindow.pushButtonCancel.released.connect(self.cancel_order)
        self.mainWindow.pushButtonSize.released.connect(self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.mainWindow.pushButtonTotal.released.connect(self.recalculate_total)
        
        #enable clicking of OrderID links in the Trading textBrowser
        self.mainWindow.textBrowserStatus.anchorClicked.connect(self.order_selected)
        
        #reset the mtgox socketIO socket when button is pushed.
        self.mainWindow.pushbuttonResetSocket.released.connect(self.restart_gox)
        
        #create the stop orders TAB.
        self.modelStops = ModelStops(self.gox)
        self.mainWindow.tableStopOrders.setModel(self.modelStops)
        self.mainWindow.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.mainWindow.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.mainWindow.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.mainWindow.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.mainWindow.checkBoxActivateStopLossBot.clicked.connect(self.stopbot_act_deact)
        
        #for stuff in the Ticker TAB
        self.mainWindow.pushButtonRefreshTicker.released.connect(self.refresh_and_display_ticker)
        self.mainWindow.checkBoxAutoRefreshTicker.clicked.connect(self.autorefresh_ticker_selected)
        
        
        self.show()
        self.raise_()
        
        self.initialize_ticker()
        self.refresh_and_display_ticker()
Пример #11
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''


    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret
        
        #lazy users can create a section in the goxtool ini file such as : 
        #[goxgui]
        #password = XXXXXXXX
        #and it will decrypt the saved credentials also in the ini file with this password
        try:
            self.passphrase = self.gox.config.get("goxgui", "password")
        except:
            self.passphrase = ""
        if self.passphrase:
            self.load_credentials(passphrase=self.passphrase)
            
        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.tickerCheckBox, 'tick'],
            [self.mainWindow.tradesCheckBox, 'trade'],
            [self.mainWindow.depthCheckBox, 'depth'],
        ]
        
        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)
        self.adaptor.signal_ticker.connect(self.update_titlebar)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        #Account Balance TAB
        self.mainWindow.pushButtonWalletA.released.connect(self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(self.set_trade_total_from_wallet)

        #Auth TAB
        self.mainWindow.pushButtonApply.released.connect(self.save_credentials)
        #Password TAB
        self.mainWindow.passwordButton.released.connect(self.load_credentials)
        
        #OrderBook TAB
        self.mainWindow.tableAsk.clicked.connect(self.update_edit_from_ask_book)
        self.mainWindow.tableBid.clicked.connect(self.update_edit_from_bid_book)
        
        #User Orders TAB
        self.modelOwns = ModelOwns(self.gox)
        self.mainWindow.tableUserOrders.setModel(self.modelOwns)
        self.mainWindow.tableUserOrders.resizeColumnsToContents()
        self.mainWindow.tableUserOrders.clicked.connect(self.userorder_selected)
        
        #Trading Box
        self.mainWindow.pushButtonGo.released.connect(self.execute_trade)
        self.mainWindow.pushButtonCancel.released.connect(self.cancel_order)
        self.mainWindow.pushButtonSize.released.connect(self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(self.update_edit_on_button)
        self.mainWindow.pushButtonTotal.released.connect(self.recalculate_total)
        
        #enable clicking of OrderID links in the Trading textBrowser
        self.mainWindow.textBrowserStatus.anchorClicked.connect(self.order_selected)
        
        #reset the mtgox socketIO socket when button is pushed.
        self.mainWindow.pushbuttonResetSocket.released.connect(self.restart_gox)
        
        #create the stop orders TAB.
        self.modelStops = ModelStops(self.gox)
        self.mainWindow.tableStopOrders.setModel(self.modelStops)
        self.mainWindow.tableStopOrders.resizeColumnsToContents()

        #add stop orders into the stop database
        self.mainWindow.pushButton1StopAdd.released.connect(self.add_stopOrder)
        #on click, put Stop Order ID into the cancel button box.
        self.mainWindow.tableStopOrders.clicked.connect(self.stopOrder_selected)
        #remove a stop order
        self.mainWindow.pushButtonStopRemove.released.connect(self.remove_stopOrder)
        #activate the stop loss bot with the checkbox.
        self.mainWindow.checkBoxActivateStopLossBot.clicked.connect(self.stopbot_act_deact)
        
        #for stuff in the Ticker TAB
        self.mainWindow.pushButtonRefreshTicker.released.connect(self.refresh_and_display_ticker)
        self.mainWindow.checkBoxAutoRefreshTicker.clicked.connect(self.autorefresh_ticker_selected)
        
        
        self.show()
        self.raise_()
        
        self.initialize_ticker()
        self.refresh_and_display_ticker()

    def initialize_ticker(self):
        use_ssl = self.gox.config.get_bool("gox", "use_ssl")
        proto = {True: "https", False: "http"}[use_ssl]
        currency = self.gox.currency
        class Ticker(object):
            def __init__(self):
                self.buy = None
                self.sell = None
                self.last = None
                self.volume = None
                self.high = None
                self.low = None
                self.avg = None
                self.vwap = None
                self.refresh_both()
            def refresh_both(self):
                self.refresh_ticker2()
                self.refresh_tickerfast()
            def refresh_tickerfast(self):
                ticker_fast = http_request(proto + "://" +  HTTP_HOST + "/api/2/BTC" + currency + "/money/ticker_fast")
                self.ticker_fast = json.loads(ticker_fast)["data"]
                self.create_fast(self.ticker_fast)                
            def refresh_ticker2(self):
                ticker2 = http_request(proto + "://" +  HTTP_HOST + "/api/2/BTC" + currency + "/money/ticker")
                self.ticker2 = json.loads(ticker2)["data"]
                self.create_ticker2(self.ticker2)
            def create_fast(self,ticker_fast):
                self.buy = ticker_fast["buy"]["value"]
                self.sell = ticker_fast["sell"]["value"]
                self.last = ticker_fast["last"]["value"]
            def create_ticker2(self,ticker2):
                self.buy = ticker2["buy"]["value"]
                self.sell = ticker2["sell"]["value"]
                self.last = ticker2["last"]["value"]
                self.volume = ticker2["vol"]["value"]
                self.volumestr = ticker2["vol"]["display"]
                self.high = ticker2["high"]["value"]
                self.low = ticker2["low"]["value"]
                self.avg = ticker2["avg"]["value"]
                self.vwap = ticker2["vwap"]["value"]

        self.ticker = Ticker() 
        
        
    def display_ticker(self):
        
        if not self.ticker.ticker_fast.get("error"):
            self.mainWindow.lineEdit1Buy.setText("$" + self.ticker.buy)
            self.mainWindow.lineEdit2Sell.setText("$" + self.ticker.sell)
            self.mainWindow.lineEdit3Last.setText("$" + self.ticker.last)
        else:
            self.mainWindow.lineEdit1Buy.setText("Error")
            self.mainWindow.lineEdit2Sell.setText("Error")
            self.mainWindow.lineEdit3Last.setText("Error")

        if not self.ticker.ticker2.get("error"):
            self.mainWindow.lineEdit4Volume.setText(self.ticker.volumestr)
            self.mainWindow.lineEdit5High.setText("$" + self.ticker.high)
            self.mainWindow.lineEdit6Low.setText("$" + self.ticker.low)
            self.mainWindow.lineEdit7Avg.setText("$" + self.ticker.avg)
            self.mainWindow.lineEdit8VWAP.setText("$" + self.ticker.vwap)
        else:
            self.mainWindow.lineEdit4Volume.setText("Error")
            self.mainWindow.lineEdit5High.setText("Error")
            self.mainWindow.lineEdit6Low.setText("Error")
            self.mainWindow.lineEdit7Avg.setText("Error")
            self.mainWindow.lineEdit8VWAP.setText("Error")
            

    def refresh_and_display_ticker(self,dummy_1=None,dummy_2=None):
        self.ticker.refresh_both()
        self.display_ticker()
                    
    def autorefresh_ticker_selected(self):
        if self.mainWindow.checkBoxAutoRefreshTicker.isChecked():
            interval = self.mainWindow.spinBoxAutoRefreshTicker.value()
            self.ticker_refresh_timer = Timer(interval)
            self.ticker_refresh_timer.connect(self.refresh_and_display_ticker)
        else:
            if self.ticker_refresh_timer:
                self.ticker_refresh_timer.cancel()
        
        
    def add_stopOrder(self):
        size = float(self.mainWindow.lineEdit1StopSize.text())  #read from input boxes
        price = float(self.mainWindow.lineEdit2StopPrice.text())
        self.mainWindow.lineEdit1StopSize.setText('')   #set input boxes to blank again
        self.mainWindow.lineEdit2StopPrice.setText('')
        oid = len(self.gox.stopOrders)+1                #set OID number to a human number(OID# is actually just for us humans)
        self.gox.stopOrders.append([oid,size,price])    #add order to the list
        self.modelStops.changed()                       #trigger the changed function

    def stopOrder_selected(self, index):
        self.mainWindow.lineEdit3StopID.setText(str(self.modelStops.get(index.row(),0)))        
        
    def remove_stopOrder(self):
        oid = self.mainWindow.lineEdit3StopID.text()    #read OID from the input box
        oid = int(oid)-1                                #change human OID to internal
        self.mainWindow.lineEdit3StopID.setText('')     #set input box to blank
        self.gox.stopOrders.remove(self.gox.stopOrders[oid])    #remove order from the list
        self.modelStops.changed()                       #trigger the changed function

    def stopbot_act_deact(self):
        if self.mainWindow.checkBoxActivateStopLossBot.isChecked():     #if the checkbox is active
            self.gox.stopbot_active = True              #enable stop-loss bot
        else:
            self.gox.stopbot_active = False             #or disable it.

    def update_titlebar(self,bid,ask):
        #change the title bar to match any updates from the ticker channel
        try:
            volstring = ", Vol: " + self.ticker.volumestr[:-4] + " BTC" #has some strange unicode char in it.
        except:
            volstring = ""
        newtitle = "MtGox Trading UI - Bid: {0}, Ask: {1}{2}".format(bid/1E5,ask/1E5,volstring)
        self.setWindowTitle(QApplication.translate("MainWindow", newtitle, None, QApplication.UnicodeUTF8))
        
    def restart_gox(self):
        self.gox.client.debug("Restarting MtGox SocketIO Client")
        self.gox.client.socket.close()
        self.gox.client.connected = False

    def get_selected_trade_type(self):
        return 'BUY' if self.mainWindow.radioButtonBuy.isChecked() else 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.mainWindow.radioButtonBuy.toggle()
        else:
            self.mainWindow.radioButtonSell.toggle()

    def log(self, text):
        text = self.prepend_date(text)
        self.log_to_file(text)
        
        doOutput = False
        
        for entry in self.logchannels:  
            if not entry[0].isChecked():    #if the checkbox is unticked:
                if entry[1] in text:        #and the message matches whichever checkbox
                    return                  #then exit without printing anything 
                
        #two loops are necessary, otherwise system being unchecked 
        #will mute the 3 other checkboxes's respective messages
        #if we got this far, the message doesn't match any unticked boxes.
        if self.mainWindow.systemCheckBox.isChecked():
            doOutput = True
        else:
            #if the system checkbox is NOT checked, do not print anything UNLESS:                                           
            for entry in self.logchannels:  #the message is one of the 3 "channels" in self.logchannels
                if entry[1] in text:        
                    doOutput = True

        if doOutput:                                    #actually print it out,unless no boxes are ticked.
            self.mainWindow.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def log_to_file(self, text):
        if not self.logfile.closed:
            self.logfile.write('{}{}'.format(text, os.linesep))

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        self.mainWindow.textBrowserStatus.moveCursor(QTextCursor.End)
        text = self.prepend_date(text)
        self.mainWindow.textBrowserStatus.append(text)
        self.log_to_file(text)

    def set_wallet_btc(self, value):
        self.mainWindow.pushButtonWalletA.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletA.setText(
            'BTC: ' + utilities.internal2str(value))

    def set_wallet_usd(self, value):
        self.mainWindow.pushButtonWalletB.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletB.setText(
            'USD: ' + utilities.internal2str(value, 5))

    def get_trade_size(self):
        value = self.mainWindow.doubleSpinBoxBtc.value()
        return utilities.float2internal(value)

    def set_trade_size(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxBtc.setValue(value_float)

    def get_trade_price(self):
        value = self.mainWindow.doubleSpinBoxPrice.value()
        return utilities.float2internal(value)

    def set_trade_price(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxPrice.setValue(value_float)

    def get_trade_total(self):
        value = self.mainWindow.doubleSpinBoxTotal.value()
        return utilities.float2internal(value)

    def set_trade_total(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxTotal.setValue(value_float)

    def get_order_id(self):
        return str(self.mainWindow.lineEditOrder.text())

    def set_order_id(self, text):
        self.mainWindow.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))
        
    def userorder_selected(self, index):
        mapdict = {"ask":"SELL","bid":"BUY"}
        self.set_selected_trade_type(mapdict[self.modelOwns.get_typ(index.row())])
        self.set_trade_price(self.modelOwns.get_price(index.row()))
        self.set_trade_size(self.modelOwns.get_size(index.row()))
        self.set_order_id(self.modelOwns.get_oid(index.row()))

    def save_credentials(self):
        '''
        Tries to encrypt the credentials entered by the user
        and save them to the configuration file.
        Incomplete or inplausible credentials will not be saved.
        '''
        def error_message(reason):          #refactored to be a little cleaner
            phrase = 'Credentials not saved '
            self.status_message(phrase + reason)
            return 0

        key = str(format(self.mainWindow.lineEditKey.text()))
        secret = str(self.mainWindow.lineEditSecret.text())
           
        if key == '':
            return error_message("(empty key).")
        if secret == '':
            return error_message("(empty secret).")

        #get the passphrase from Password Tab
        self.passphrase = str(self.mainWindow.passwordLineEdit.text())
        #if the user never filled in the password box, cause an error, and
        #switch the current tab to the password tab for them to fill it in.
        if self.passphrase == '':
            self.mainWindow.tabWidget_1.setCurrentIndex(2)
            return error_message("(invalid password).")
                
        try:
            utilities.assert_valid_key(key)
        except Exception:
            return error_message("(invalid key).")
        
        try:
            secret = utilities.encrypt(secret, self.passphrase)
        except Exception:
            return error_message("(invalid secret).")

        self.gox.config.set("gox", "secret_key", key)
        self.gox.config.set("gox", "secret_secret", secret)
        self.gox.config.save()
        #if everything's OK, trigger a reload of credentials(below)
        self.load_credentials()

    def load_credentials(self,passphrase=''):
        '''
        Tries to load the credentials from the configuration file
        and display them to the user. If the credentials in the
        configuration file are invalid, they will not be loaded.
        '''
        savedPassword = True        #a default condition is needed.
        key = self.gox.config.get_string("gox", "secret_key")
        secret = self.gox.config.get_string("gox", "secret_secret")
        if not passphrase:          #if password is blank (default NOT stored)
            savedPassword = False   #then change the default condition to False
            #and grab password from the password tab password box.
            self.passphrase = str(self.mainWindow.passwordLineEdit.text())
        try:
            utilities.assert_valid_key(key)
            secret = utilities.decrypt(secret, self.passphrase)
        except Exception:
            key = ''
            secret = ''

        self.secret.key = key
        self.secret.secret = secret
        if not key == '' and not secret == '':
            #if everything is OK, set the placeholder text to show credentials were loaded OK
            self.mainWindow.lineEditKey.setPlaceholderText('Loaded Key From File')
            self.mainWindow.lineEditSecret.setPlaceholderText('Decrypted Secret Using Password')
            #and switch current tab back to the main Account Balance Tab
            self.mainWindow.tabWidget_1.setCurrentIndex(0)
            if not savedPassword:       #check for default password. if not, restart the socket.
                self.status_message("Credentials changed. Restarting MtGox Client")
                self.restart_gox()      #restart the gox socket.
        else:
            self.status_message("Key and Secret are blank. Enter them and click Apply.")
            self.mainWindow.tabWidget_1.setCurrentIndex(1)
        
    def display_wallet(self):
        self.set_wallet_usd(utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_wallet_btc(utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))

#when the account balance buttons are clicked
#set the size edit box to match
    def set_trade_size_from_wallet(self):
        self.set_trade_size(utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))
        self.set_selected_trade_type('SELL')        #and check the sell radiobutton

    def set_trade_total_from_wallet(self):
        self.set_trade_total(utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_selected_trade_type('BUY')         #and check the buy radiobutton

    def display_orderlag(self, ms, text):
        self.mainWindow.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()
        
        size = utilities.internal2str(self.get_trade_size())
        price = utilities.internal2str(self.get_trade_price(), 5)
        total = utilities.internal2str(self.get_trade_total(), 5)

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message('Placing order: {0} {1} BTC at $ {2} USD (total $ {3} USD)...'.format(# @IgnorePep8
            trade_name,size,price,total))
        
        sizeGox = int(D(size)*B)
        priceGox = int(D(price)*U)

        mapdict = {"BUY":self.gox.buy,"SELL":self.gox.sell}
        mapdict[trade_type](priceGox, sizeGox)

    def recalculate_size(self):
        #When the size button is clicked:
        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        #divide Total by Price and fill the size edit box in.
        size = utilities.divide_internal(total, price)
        self.set_trade_size(size)

    def recalculate_total(self):
        #When the total button is clicked
        price = self.get_trade_price()
        size = self.get_trade_size()
        #Multiply Price by Size and fill the total edit box in
        total = utilities.multiply_internal(price, size)
        self.set_trade_total(total)

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2internal(size, 'BTC')
        price = utilities.gox2internal(price, 'USD')

        size = utilities.internal2str(size)
        price = utilities.internal2str(price,5)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message("{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}".format(# @IgnorePep8
                str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)

    def cancel_order(self):
        order_id = self.get_order_id()
        self.status_message(
            "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
        self.gox.cancel(order_id)
        
    def update_edit_from_ask_book(self, index):
        #when a order on the ask side is clicked
        #set the radio button to the opposite (buy) 
        self.set_trade_price(self.modelAsk.get_price(index.row()))  #set the price edit box 
        self.set_trade_size(self.modelAsk.get_size(index.row()))    #set the size edit box
        self.set_selected_trade_type('BUY')                        #set the BUY radiobutton
        
    def update_edit_from_bid_book(self, index):
        #when a order on the bids side is clicked 
        #set the radio button to the opposite (sell)
        self.set_trade_price(self.modelBid.get_price(index.row()))  #set the price edit box
        self.set_trade_size(self.modelBid.get_size(index.row()))    #set the size edit box
        self.set_selected_trade_type('SELL')                         #set the SELL radiobutton
       
    def update_edit_on_button(self):
        #When Price button is clicked, fill in the edit boxes, 
        trade_type = self.get_selected_trade_type()
        #depending on which radiobutton "Buy" or "Sell" is selected at the time,
        #get the OPPOSITE side's current best price and the corresponding size 
        mapdict = {"SELL":self.modelBid,"BUY":self.modelAsk}
        self.set_trade_price(mapdict[trade_type].get_price(0))
        self.set_trade_size(mapdict[trade_type].get_size(0))        
        #so you can fulfill that person's current best offer just by clicking Go.
        #(This functionality is something I want, and I can understand it being confusing having it on this button)
        #because the size button behaves normally the original way still.
        #similarly confusing having it map to the opposite side (but necessary)
        #
Пример #12
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''

    # how the application-proposed bid will differ from the selected bid
    ADD_TO_BID = 1000

    # how the application-proposed ask will differ from the selected ask
    SUB_FROM_ASK = 1000

    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(
            self.execute_trade)
        self.ui.tableAsk.clicked.connect(
            self.update_price_from_asks)
        self.ui.tableBid.clicked.connect(
            self.update_price_from_bids)
        self.ui.pushButtonCancel.released.connect(
            self.cancel_order)
        self.ui.textBrowserStatus.anchorClicked.connect(
            self.order_selected)
        self.ui.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.ui.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.ui.pushButtonSize.released.connect(
            self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(
            self.update_price_best)
        self.ui.pushButtonTotal.released.connect(
            self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(
            self.show_preferences)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self, self.market)
        self.ui.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self, self.market)
        self.ui.tableBid.setModel(self.modelBid)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, 'tick'],
            [self.ui.checkBoxLogTrade, 'TRADE'],
            [self.ui.checkBoxLogDepth, 'depth'],
        ]

        # activate market
        self.market.start()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()

    def adjust_for_mac(self):
        '''
        Fixes some stuff that looks good on windows but bad on mac.
        '''
        # the default fixed font is unreadable on mac, so replace it
        font = QtGui.QFont('Monaco', 11)
        self.ui.tableAsk.setFont(font)
        self.ui.tableBid.setFont(font)
        self.ui.textBrowserLog.setFont(font)
        self.ui.textBrowserStatus.setFont(font)
        self.ui.lineEditOrder.setFont(font)
        self.ui.doubleSpinBoxBtc.setFont(font)
        self.ui.doubleSpinBoxPrice.setFont(font)
        self.ui.doubleSpinBoxTotal.setFont(font)

        # the space between application title bar and
        # the ui elements is too small on mac
        margins = self.ui.widgetMain.layout().contentsMargins()
        margins.setTop(24)
        self.ui.widgetMain.layout().setContentsMargins(margins)

    def show_preferences(self):

        result = self.preferences.show()
        if result == True:
            self.status_message('Preferences changed, restarting market.')
            self.market.stop()
            self.preferences.apply()
            self.market.start()
            self.status_message('Market restarted successfully.')

    def get_selected_trade_type(self):
        if self.ui.radioButtonBuy.isChecked():
            return 'BUY'
        else:
            return 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.ui.radioButtonBuy.toggle()
        else:
            self.ui.radioButtonSell.toggle()

    def slot_log(self, text):

        logging.info(text)
        text = self.prepend_date(text)

        doOutput = False

        if self.ui.checkBoxLogSystem.isChecked():
            doOutput = True

        for entry in self.logchannels:
            if entry[1] in text:
                doOutput = entry[0].isChecked()

        if doOutput:
            self.ui.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        logging.info(text)
        text = self.prepend_date(text)
        self.ui.textBrowserStatus.moveCursor(QTextCursor.End)
        self.ui.textBrowserStatus.append(text)

    def set_wallet_btc(self, value):
        self.ui.pushButtonWalletA.setEnabled(value > 0)
        self.ui.pushButtonWalletA.setText(
            'BTC: ' + utilities.internal2str(value))

    def set_wallet_usd(self, value):
        self.ui.pushButtonWalletB.setEnabled(value > 0)
        self.ui.pushButtonWalletB.setText(
            'USD: ' + utilities.internal2str(value, 5))

    def get_trade_size(self):
        value = self.ui.doubleSpinBoxBtc.value()
        return utilities.float2internal(value)

    def set_trade_size(self, value):
        value_float = utilities.internal2float(value)
        self.ui.doubleSpinBoxBtc.setValue(value_float)

    def get_trade_price(self):
        value = self.ui.doubleSpinBoxPrice.value()
        return utilities.float2internal(value)

    def set_trade_price(self, value):
        value_float = utilities.internal2float(value)
        self.ui.doubleSpinBoxPrice.setValue(value_float)

    def get_trade_total(self):
        value = self.ui.doubleSpinBoxTotal.value()
        return utilities.float2internal(value)

    def set_trade_total(self, value):
        value_float = utilities.internal2float(value)
        self.ui.doubleSpinBoxTotal.setValue(value_float)

    def get_order_id(self):
        return str(self.ui.lineEditOrder.text())

    def set_order_id(self, text):
        self.ui.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def display_wallet(self):

        self.set_wallet_usd(
            utilities.gox2internal(self.market.get_balance('USD'), 'USD'))
        self.set_wallet_btc(
            utilities.gox2internal(self.market.get_balance('BTC'), 'BTC'))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(
            utilities.gox2internal(self.market.get_balance('BTC'), 'BTC'))
        self.set_selected_trade_type('SELL')

    def set_trade_total_from_wallet(self):
        self.set_trade_total(
            utilities.gox2internal(self.market.get_balance('USD'), 'USD'))
        self.set_selected_trade_type('BUY')

    def display_orderlag(self, ms, text):
        self.ui.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = self.get_trade_total()

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message('Placing order: {0} {1} BTC at {2} USD (total {3} USD)...'.format(# @IgnorePep8
            trade_name,
            utilities.internal2str(size),
            utilities.internal2str(price, 5),
            utilities.internal2str(total, 5)))

        if trade_type == 'BUY':
            self.market.buy(price, size)
        else:
            self.market.sell(price, size)

    def recalculate_size(self):

        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        size = utilities.divide_internal(total, price)
        self.set_trade_size(size)

    def recalculate_total(self):

        price = self.get_trade_price()
        size = self.get_trade_size()
        total = utilities.multiply_internal(price, size)
        self.set_trade_total(total)

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2internal(size, 'BTC')
        price = utilities.gox2internal(price, 'USD')

        size = utilities.internal2str(size)
        price = utilities.internal2str(price)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message("{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}".format(# @IgnorePep8
                str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)

    def update_price_from_asks(self, index):
        self.set_trade_price(self.modelAsk.get_price(index.row())
            - self.SUB_FROM_ASK)

    def update_price_from_bids(self, index):
        self.set_trade_price(self.modelBid.get_price(index.row())
            + self.ADD_TO_BID)

    def cancel_order(self):
        order_id = self.get_order_id()
        self.status_message(
            "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
        self.market.cancel(order_id)

    def update_price_best(self):

        trade_type = self.get_selected_trade_type()
        if trade_type == 'BUY':
            price = self.modelBid.get_price(0)
            price += self.ADD_TO_BID
            self.set_trade_price(price)
        elif trade_type == 'SELL':
            price = self.modelAsk.get_price(0)
            price -= self.SUB_FROM_ASK
            self.set_trade_price(price)

    def stop(self):
        self.market.stop()
Пример #13
0
class View(QMainWindow):
    '''
    Represents the combined view / control.
    '''

    # how the application-proposed bid will differ from the selected bid
    ADD_TO_BID = 1

    # how the application-proposed ask will differ from the selected ask
    SUB_FROM_ASK = 1

    PASSPHRASE = 'fffuuuuuuu'

    def __init__(self, gox, secret, logfile):

        self.logfile = logfile

        QMainWindow.__init__(self)

        # setup UI
        self.mainWindow = Ui_MainWindow()
        self.mainWindow.setupUi(self)

        # setup gox objects
        self.gox = gox
        self.secret = secret

        # connect to gox signals
        self.adaptor = Adaptor(self.gox)
        self.adaptor.signal_log.connect(self.log)
        self.adaptor.signal_wallet.connect(self.display_wallet)
        self.adaptor.signal_orderlag.connect(self.display_orderlag)
        self.adaptor.signal_userorder.connect(self.display_userorder)

        # initialize and connect bid / ask table models
        self.modelAsk = ModelAsk(self.gox)
        self.mainWindow.tableAsk.setModel(self.modelAsk)
        self.modelBid = ModelBid(self.gox)
        self.mainWindow.tableBid.setModel(self.modelBid)

        # connect signals from UI Qt components to our own slots
        self.mainWindow.pushButtonApply.released.connect(self.save_credentials)
        self.mainWindow.pushButtonGo.released.connect(self.execute_trade)
        self.mainWindow.tableAsk.clicked.connect(self.update_price_from_asks)
        self.mainWindow.tableBid.clicked.connect(self.update_price_from_bids)
        self.mainWindow.pushButtonCancel.released.connect(self.cancel_order)
        self.mainWindow.textBrowserStatus.anchorClicked.connect(
            self.order_selected)
        self.mainWindow.pushButtonWalletA.released.connect(
            self.set_trade_size_from_wallet)
        self.mainWindow.pushButtonWalletB.released.connect(
            self.set_trade_total_from_wallet)
        self.mainWindow.pushButtonSize.released.connect(self.recalculate_size)
        self.mainWindow.pushButtonPrice.released.connect(
            self.update_price_best)
        self.mainWindow.pushButtonTotal.released.connect(
            self.recalculate_total)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.mainWindow.checkBoxLogTicker, 'tick'],
            [self.mainWindow.checkBoxLogTrade, 'TRADE'],
            [self.mainWindow.checkBoxLogDepth, 'depth'],
        ]

        # load credentials from configuration file
        self.load_credentials()

        self.show()
        self.raise_()

    def restart_gox(self):
        '''
        Restarts gox by closing the connection
        (recommended by prof7bit)
        '''
        if self.gox.client.socket:
            self.gox.client.socket.close()

    def get_selected_trade_type(self):
        if self.mainWindow.radioButtonBuy.isChecked():
            return 'BUY'
        else:
            return 'SELL'

    def set_selected_trade_type(self, trade_type):
        if trade_type == 'BUY':
            self.mainWindow.radioButtonBuy.toggle()
        else:
            self.mainWindow.radioButtonSell.toggle()

    def log(self, text):

        text = self.prepend_date(text)
        self.log_to_file(text)

        doOutput = False

        if self.mainWindow.checkBoxLogSystem.isChecked():
            doOutput = True
        else:
            for entry in self.logchannels:
                if entry[0].isChecked() and entry[1] in text:
                    doOutput = True

        if doOutput:
            self.mainWindow.textBrowserLog.append(text)

    def prepend_date(self, text):
        millis = int(round(time.time() * 1000)) % 1000
        return '{}.{:0>3} {}'.format(time.strftime('%X'), millis, text)

    def log_to_file(self, text):
        if not self.logfile.closed:
            self.logfile.write('{}{}'.format(text, os.linesep))

    def status_message(self, text):
        # call move cursor before append to work around link clicking bug
        # see: https://bugreports.qt-project.org/browse/QTBUG-539
        self.mainWindow.textBrowserStatus.moveCursor(QTextCursor.End)
        text = self.prepend_date(text)
        self.mainWindow.textBrowserStatus.append(text)
        self.log_to_file(text)

    def set_wallet_btc(self, value):
        self.mainWindow.pushButtonWalletA.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletA.setText(
            'BTC: ' + utilities.internal2str(value))

    def set_wallet_usd(self, value):
        self.mainWindow.pushButtonWalletB.setEnabled(value > 0)
        self.mainWindow.pushButtonWalletB.setText(
            'USD: ' + utilities.internal2str(value, 5))

    def get_trade_size(self):
        value = self.mainWindow.doubleSpinBoxBtc.value()
        return utilities.float2internal(value)

    def set_trade_size(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxBtc.setValue(value_float)

    def get_trade_price(self):
        value = self.mainWindow.doubleSpinBoxPrice.value()
        return utilities.float2internal(value)

    def set_trade_price(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxPrice.setValue(value_float)

    def get_trade_total(self):
        value = self.mainWindow.doubleSpinBoxTotal.value()
        return utilities.float2internal(value)

    def set_trade_total(self, value):
        value_float = utilities.internal2float(value)
        self.mainWindow.doubleSpinBoxTotal.setValue(value_float)

    def get_order_id(self):
        return str(self.mainWindow.lineEditOrder.text())

    def set_order_id(self, text):
        self.mainWindow.lineEditOrder.setText(text)

    def order_selected(self, url):
        self.set_order_id(str(url.toString()))

    def save_credentials(self):
        '''
        Tries to encrypt the credentials entered by the user
        and save them to the configuration file.
        Incomplete or inplausible credentials will not be saved.
        '''

        key = str(format(self.mainWindow.lineEditKey.text()))
        secret = str(self.mainWindow.lineEditSecret.text())

        if key == '':
            self.status_message("Credentials not saved (empty key).")
            return

        if secret == '':
            self.status_message("Credentials not saved (empty secret).")
            return

        try:
            utilities.assert_valid_key(key)
        except Exception:
            self.status_message("Credentials not saved (invalid key).")
            return

        try:
            secret = utilities.encrypt(secret, View.PASSPHRASE)
        except Exception:
            self.status_message("Credentials not saved (invalid secret).")
            return

        self.gox.config.set("gox", "secret_key", key)
        self.gox.config.set("gox", "secret_secret", secret)
        self.gox.config.save()
        self.status_message("Credentials saved.")
        self.load_credentials()
        self.restart_gox()

    def load_credentials(self):
        '''
        Tries to load the credentials from the configuration file
        and display them to the user. If the credentials in the
        configuration file are invalid, they will not be loaded.
        '''

        key = self.gox.config.get_string("gox", "secret_key")
        secret = self.gox.config.get_string("gox", "secret_secret")

        try:
            utilities.assert_valid_key(key)
            secret = utilities.decrypt(secret, View.PASSPHRASE)
        except Exception:
            key = ''
            secret = ''

        self.secret.key = key
        self.mainWindow.lineEditKey.setText(key)
        self.secret.secret = secret
        self.mainWindow.lineEditSecret.setText(secret)

    def display_wallet(self):
        self.set_wallet_usd(
            utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_wallet_btc(
            utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))

    def set_trade_size_from_wallet(self):
        self.set_trade_size(
            utilities.gox2internal(self.gox.wallet['BTC'], 'BTC'))
        self.set_selected_trade_type('SELL')

    def set_trade_total_from_wallet(self):
        self.set_trade_total(
            utilities.gox2internal(self.gox.wallet['USD'], 'USD'))
        self.set_selected_trade_type('BUY')

    def display_orderlag(self, ms, text):
        self.mainWindow.labelOrderlag.setText('Trading Lag: ' + text)

    def execute_trade(self):

        trade_type = self.get_selected_trade_type()

        size = self.get_trade_size()
        price = self.get_trade_price()
        total = self.get_trade_total()

        trade_name = 'BID' if trade_type == 'BUY' else 'ASK'

        self.status_message(
            'Placing order: {0} {1} BTC at {2} USD (total {3} USD)...'.
            format(  # @IgnorePep8
                trade_name, utilities.internal2str(size),
                utilities.internal2str(price, 5),
                utilities.internal2str(total, 5)))

        sizeGox = utilities.internal2gox(size, 'BTC')
        priceGox = utilities.internal2gox(price, 'USD')

        if trade_type == 'BUY':
            self.gox.buy(priceGox, sizeGox)
        else:
            self.gox.sell(priceGox, sizeGox)

    def recalculate_size(self):

        price = self.get_trade_price()
        if price == 0:
            return

        total = self.get_trade_total()
        size = utilities.divide_internal(total, price)
        self.set_trade_size(size)

    def recalculate_total(self):

        price = self.get_trade_price()
        size = self.get_trade_size()
        total = utilities.multiply_internal(price, size)
        self.set_trade_total(total)

    def display_userorder(self, price, size, order_type, oid, status):

        size = utilities.gox2internal(size, 'BTC')
        price = utilities.gox2internal(price, 'USD')

        size = utilities.internal2str(size)
        price = utilities.internal2str(price)

        if order_type == '':
            self.status_message("Order <a href=\"{0}\">{0}</a> {1}.".format(
                oid, status))
            if status == 'removed' and self.get_order_id() == oid:
                self.set_order_id('')
        else:
            self.status_message(
                "{0} size: {1}, price: {2}, oid: <a href=\"{3}\">{3}</a> - {4}"
                .format(  # @IgnorePep8
                    str.upper(str(order_type)), size, price, oid, status))
            if status == 'post-pending':
                self.set_order_id(oid)

    def update_price_from_asks(self, index):
        self.set_trade_price(
            self.modelAsk.get_price(index.row()) - self.SUB_FROM_ASK)

    def update_price_from_bids(self, index):
        self.set_trade_price(
            self.modelBid.get_price(index.row()) + self.ADD_TO_BID)

    def cancel_order(self):
        order_id = self.get_order_id()
        self.status_message(
            "Cancelling order <a href=\"{0}\">{0}</a>...".format(order_id))
        self.gox.cancel(order_id)

    def update_price_best(self):

        trade_type = self.get_selected_trade_type()
        if trade_type == 'BUY':
            price = self.modelBid.get_price(0)
            price += self.ADD_TO_BID
            self.set_trade_price(price)
        elif trade_type == 'SELL':
            price = self.modelAsk.get_price(0)
            price -= self.SUB_FROM_ASK
            self.set_trade_price(price)
Пример #14
0
    def __init__(self, preferences, market):

        QMainWindow.__init__(self)

        self.preferences = preferences
        self.market = market

        # set up main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # improve ui on mac
        if utilities.platform_is_mac():
            self.adjust_for_mac()

        # connect market signals to our logic
        self.market.signal_log.connect(self.slot_log)
        self.market.signal_wallet.connect(self.display_wallet)
        self.market.signal_orderlag.connect(self.display_orderlag)
        self.market.signal_userorder.connect(self.display_userorder)
        self.market.signal_ticker.connect(self.update_ticker)

        # connect ui signals to our logic
        self.ui.pushButtonGo.released.connect(self.execute_trade)
        self.ui.tableAsk.clicked.connect(self.slot_update_price_from_asks)
        self.ui.tableBid.clicked.connect(self.slot_update_price_from_bids)
        self.ui.pushButtonCancel.released.connect(self.cancel_order)
        self.ui.textBrowserStatus.anchorClicked.connect(self.order_selected)
        self.ui.pushButtonSize.released.connect(self.recalculate_size)
        self.ui.pushButtonPrice.released.connect(self.update_price_best)
        self.ui.pushButtonTotal.released.connect(self.recalculate_total)
        self.ui.actionPreferences_2.triggered.connect(self.show_preferences)

        # associate log channels with their check boxes
        self.logchannels = [
            [self.ui.checkBoxLogTicker, "tick"],
            [self.ui.checkBoxLogTrade, "TRADE"],
            [self.ui.checkBoxLogDepth, "depth"],
        ]

        # set correct resizing for the bid and ask tables
        self.ui.tableAsk.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        self.ui.tableBid.horizontalHeader().setResizeMode(QHeaderView.Stretch)

        # set up info table
        self.info = Info(self, self.preferences, self.ui.tableInfo.clicked)
        self.ui.tableInfo.setModel(self.info)
        self.ui.tableInfo.horizontalHeader().setResizeMode(QHeaderView.Stretch)

        # connect to signals from info table
        self.info.signal_base_balance_clicked.connect(self.set_trade_size_from_wallet)
        self.info.signal_quote_balance_clicked.connect(self.set_trade_total_from_wallet)

        # initializes dynamic ui elements
        self.init()

        # activate market
        self.market.start()

        # show main window
        self.adjustSize()
        self.show()
        self.raise_()