def trades(ctx, market, limit, start, stop): market = Market(market, bitshares_instance=ctx.bitshares) t = PrettyTable(["time", "quote", "base", "price"]) t.align = 'r' for trade in market.trades(limit, start=start, stop=stop): t.add_row([ str(trade["time"]), str(trade["quote"]), str(trade["base"]), "{:f} {}/{}".format(trade["price"], trade["base"]["asset"]["symbol"], trade["quote"]["asset"]["symbol"]), ]) click.echo(str(t))
def market_trade_history(market_pair: hug.types.text, api_key: hug.types.text, hug_timer=5): """Given a valid market_pair (e.g. USD:BTS) & a TX limit, output the market's trade history in JSON.""" if (check_api_token(api_key) == True): # Check the api key # API KEY VALID try: target_market = Market(market_pair) except: # Market is not valid return { 'valid_market': False, 'valid_key': True, 'took': float(hug_timer) } temp_market_history = list(target_market.trades(limit=100)) #print(temp_market_history) # (2017-12-24 15:37:21) 55.8699 USD 106.84792 BTS @ 1.912441583 BTS/USD market_history_json_list = [] for market_trade in temp_market_history: str_market_trade = str(market_trade).split( " @ " ) # ["(2017-12-24 15:37:21) 55.8699 USD 106.84792 BTS", "1.912441583 BTS/USD"] trade_rate = str_market_trade[1] # "1.912441583 BTS/USD" trade_time = (str_market_trade[0].split(") ")[0]).replace("(", "") trade_details = str_market_trade[0].split(") ")[1] split_trade = trade_details.split(" ") market_history_json_list.append({ "datetime": trade_time.replace(" ", "T"), "bought": split_trade[0] + " " + split_trade[1], "sold": split_trade[2] + " " + split_trade[3], "rate ": trade_rate }) return { 'market_trade_history': market_history_json_list, 'market': market_pair, 'valid_market': True, 'valid_key': True, 'took': float(hug_timer) } else: # API KEY INVALID! return {'valid_key': False, 'took': float(hug_timer)}
def trades(ctx, market, limit, start, stop): """ List trades in a market """ market = Market(market, bitshares_instance=ctx.bitshares) t = [["time", "quote", "base", "price"]] for trade in market.trades(limit, start=start, stop=stop): t.append([ str(trade["time"]), str(trade["quote"]), str(trade["base"]), "{:f} {}/{}".format(trade["price"], trade["base"]["asset"]["symbol"], trade["quote"]["asset"]["symbol"]), ]) print_table(t)
def trades_csv(ctx, base, asset, start, stop): if "T" in start: dt_start = formatTimeString(start) else: dt_start = formatDateString(start) if "T" in stop: dt_stop = formatTimeString(stop) else: dt_stop = formatDateString(stop) click.echo("%s-%s from %s to %s" % (base, asset, dt_start, dt_stop)) pair = "%s-%s" % (base, asset) market = Market(pair, bitshares_instance=ctx.bitshares) trades = market.trades(start=dt_start, stop=dt_stop, limit=100) click.echo("%s,%s,%s,%s,%s" % ("Date", "Price", "Base_Amount", "Amount", "Pair")) for trade in trades: click.echo("%s,%s,%s,%s,%s/%s" % \ (trade["time"], trade["price"],trade["base"]["amount"], trade["quote"]["amount"], trade["base"]["symbol"], trade["quote"]["symbol"]))
class MarketTab(QtGui.QWidget): def __init__(self, *args, **kwargs): self.iso = kwargs.pop("isolator", None) self.asset_a = kwargs.pop("asset_a", None) self.asset_b = kwargs.pop("asset_b", None) self._pairtag = self.asset_a["symbol"] + ":" + self.asset_b["symbol"] self.ping_callback = kwargs.pop("ping_callback", None) super(MarketTab, self).__init__(*args, **kwargs) self.ui = Ui_MarketTab() self.ui.setupUi(self) replaceAxis(self.ui.marketPlot, "bottom", TimeAxisItem(orientation='bottom')) replaceAxis( self.ui.marketPlot, "left", CoinAxisItem(precision=self.asset_b["precision"], orientation='left')) self.ui.marketPlot.setMenuEnabled(False) self.__vLine = pg.InfiniteLine(angle=90, movable=False, pen=PG_CROSSHAIR) self.__hLine = pg.InfiniteLine(angle=0, movable=False, pen=PG_CROSSHAIR) self.__textPrice = pg.TextItem('price') view = self.ui.marketPlot.getViewBox() view.addItem(self.__textPrice, ignoreBounds=True) view.addItem(self.__vLine, ignoreBounds=True) view.addItem(self.__hLine, ignoreBounds=True) view.setLimits( # yMin = 0, # price never goes below zero xMin=datetime.datetime(2015, 1, 1).timestamp(), # ~BTS started xMax=(datetime.datetime.now() + datetime.timedelta(weeks=52)).timestamp() # 1 year ) self.start_time = None self.stop_time = None self.initfetch = 1 self.ui.marketPlot.sigXRangeChanged.connect(self.updateRange) self.ui.marketPlot.scene().sigMouseMoved.connect(self.updateTooltip) #, # axisItems={'bottom': TimeAxisItem(orientation='bottom')} self._index = 999 self.ui.buyStack.setColumnCount(3) stretch_table(self.ui.buyStack, False, hidehoriz=True) self.ui.sellStack.setColumnCount(3) stretch_table(self.ui.sellStack, False, hidehoriz=True) self.subscribed = False self.updater = RemoteFetch(manager=self.iso.mainwin.Requests) self._frame_buy = { "group": self.ui.buyGroup, "mainLabel": self.ui.buyMainLabel, "mainAmt": self.ui.buyMainAmount, "altLabel": self.ui.buyAltLabel, "altAmt": self.ui.buyAltAmount, "price": self.ui.buyPrice, "account": self.ui.buyAccount, "expireEdit": self.ui.buyExpireEdit, "expireFOK": self.ui.buyFOK, "fee": self.ui.buyFeeAsset, "button": self.ui.buyButton, "_commit_inv": True, "table": self.ui.sellStack, } self._frame_sell = { "group": self.ui.sellGroup, "mainLabel": self.ui.sellMainLabel, "mainAmt": self.ui.sellMainAmount, "altLabel": self.ui.sellAltLabel, "altAmt": self.ui.sellAltAmount, "price": self.ui.sellPrice, "account": self.ui.sellAccount, "expireEdit": self.ui.sellExpireEdit, "expireFOK": self.ui.sellFOK, "fee": self.ui.sellFeeAsset, "button": self.ui.sellButton, "_commit_inv": False, "table": self.ui.buyStack, } self.setupFrame(self._frame_buy, self.asset_a, self.asset_b, title="Buy ") self.setupFrame(self._frame_sell, self.asset_a, self.asset_b, title="Sell ") #self.ui.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) #self.ui.table.customContextMenuRequested.connect(self.show_orders_submenu) self.ui.closeButton.clicked.connect(self.close_me) self.ui.swapButton.clicked.connect(self.swap_me) def close_me(self): app().mainwin.closeMarket(self._pairtag) def swap_me(self): try: app().mainwin.swapMarket(self._pairtag) except Exception as error: showexc(error) def close(self): # TODO: unsubscribe from market!!! pass def setupFrame(self, form, asset_a, asset_b, title="Trade "): form["group"].setTitle(title + asset_a["symbol"]) form["mainLabel"].setText(asset_a["symbol"]) form["altLabel"].setText(asset_b["symbol"]) form["price"].valueChanged.connect(self.price_value_changed) form["price"].setSuffix(" " + asset_b["symbol"]) form["price"].setDecimals(asset_b["precision"]) form["price"].setMaximum(asset_b["options"]["max_supply"] * pow(10, asset_b["precision"])) form["mainAmt"].valueChanged.connect(self.main_amount_changed) form["mainAmt"].setDecimals(asset_a["precision"]) form["mainAmt"].setMaximum(asset_a["options"]["max_supply"] * pow(10, asset_a["precision"])) form["altAmt"].valueChanged.connect(self.alt_amount_changed) form["altAmt"].setDecimals(asset_b["precision"]) form["altAmt"].setMaximum(asset_b["options"]["max_supply"] * pow(10, asset_b["precision"])) form["table"].cellClicked.connect(self.cell_click) form["button"].clicked.connect(self.make_limit_order) def make_limit_order(self): form = self._frame_buy if self._frame_buy["button"] == self.sender( ) else self._frame_sell account_from = form["account"].currentText() sell_asset_name = self.asset_a["symbol"] sell_asset_amount = form["mainAmt"].value() buy_asset_name = self.asset_b["symbol"] buy_asset_amount = form["altAmt"].value() if form["_commit_inv"]: sell_asset_name = self.asset_b["symbol"] buy_asset_name = self.asset_a["symbol"] expire_seconds = deltasec(form["expireEdit"].text()) expire_fok = form["expireFOK"].isChecked() fee_asset = anyvalvis(form["fee"], None) #.currentText() buffer = app().mainwin.buffering() try: v = QTransactionBuilder.VSellAsset(account_from, sell_asset_name, sell_asset_amount, buy_asset_name, buy_asset_amount, expiration=expire_seconds, fill_or_kill=expire_fok, fee_asset=fee_asset, isolator=self.iso) if buffer: app().mainwin._txAppend(*v) else: QTransactionBuilder._QExec(self.iso, v) except Exception as error: showexc(error) return False return True def _set_spin_value(self, elem, value): elem.blockSignals(True) elem.setValue(value) elem.blockSignals(False) def price_value_changed(self): form = self._frame_buy if self._frame_buy["price"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if amt_a == 0 and price != 0: amt_a = amt_b / price self._set_spin_value(form["mainAmt"], amt_a) return amt_b = amt_a * price self._set_spin_value(form["altAmt"], amt_b) def main_amount_changed(self): form = self._frame_buy if self._frame_buy["mainAmt"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if price == 0: if amt_a == 0: return price = amt_b / amt_a self._set_spin_value(form["price"], price) return amt_b = amt_a * price self._set_spin_value(form["altAmt"], amt_b) def alt_amount_changed(self): form = self._frame_buy if self._frame_buy["altAmt"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if price == 0: if amt_a == 0: return price = amt_b / amt_a #form["price"].setValue(price) self._set_spin_value(form["price"], price) return amt_a = amt_b / price self._set_spin_value(form["mainAmt"], amt_a) def cell_click(self, row, column): form = self._frame_buy if self._frame_buy["table"] == self.sender( ) else self._frame_sell valstr = form["table"].item(row, column).text().replace(",", "") val = float(str.split(valstr, " ")[0]) if column == 0: # price form["price"].setValue(val) if column == 1: # asset_a form["mainAmt"].setValue(val) if column == 2: # asset_b form["altAmt"].setValue(val) def _refreshTitle(self): #self._title = _translate("MainWindow", "Market", None) + " " + self._pairtag self._title = self._pairtag return self._title def show_orders_submenu(self, position): menu = QtGui.QMenu() qaction(self, menu, "Cancel Order...", self.cancel_order) menu.exec_(self.ui.table.viewport().mapToGlobal(position)) def cancel_order(self): table = self.ui.table indexes = table.selectionModel().selectedRows() if len(indexes) < 1: return index = indexes[0].row() order_id = table.item(index, 0).text() #b = table.item(index, 1).text() try: trx = QTransactionBuilder.QCancelOrder( self._account_name, order_id, #fee_asset=fee_asset, isolator=self.iso) except Exception as error: showexc(error) def desync(self): self.subscribed = False def resync(self): self.updater.fetch(self.mergeMarket_before, self.iso, (self.asset_a, self.asset_b), self._pairtag, self.start_time, self.stop_time, ready_callback=self.mergeMarket_after, ping_callback=self.ping_callback, description="Refreshing market " + self._pairtag) def mergeMarket_before(self, iso, pair, tag, start, stop): asset_a = pair[0] asset_b = pair[1] rpc = iso.bts.rpc if not self.subscribed: s_id = rpc.get_subscription_id() subs = rpc.subscribe_to_market(s_id, asset_a["id"], asset_b["id"]) self._s_id = s_id self._tags.append("!" + str(s_id)) self.subscribed = True from bitshares.market import Market self.market = Market(base=asset_b, quote=asset_a, blockchain_instance=iso.bts) orders = self.market.orderbook() if self.initfetch: trades = self.market.trades(limit=100, start=start, stop=stop) else: trades = iso.getMarketBuckets(self.market["base"], self.market["quote"], start=start, stop=stop) return ( orders, trades, ) def mergeMarket_after(self, request_id, args): ( orders, trades, ) = args self.fillTable(self.ui.buyStack, orders['bids']) self.fillTable(self.ui.sellStack, orders['asks'], True) self.plotChart(trades) def fillTable(self, table, orders, inv=False): color_a = COLOR_GREEN if inv else COLOR_RED color_b = COLOR_RED if inv else COLOR_GREEN table.setRowCount(0) j = -1 for order in orders: j += 1 table.insertRow(j) set_col(table, j, 0, price__repr(order, "base")) set_col(table, j, 1, str(order["quote"]), color=color_a, align="right") set_col(table, j, 2, str(order["base"]), color=color_b, align="right") def plotChart(self, trades): xs = [] ys = [] for trade in trades: dt = datetime.datetime.strptime(trade["date"], "%Y-%m-%dT%H:%M:%S") x = int(dt.timestamp()) #trade["sequence"] y = trade["price"] xs.append(x) ys.append(y) #print(xs, ys) #import numpy as np #x = np.random.normal(size=1000) #y = np.random.normal(size=1000) self.ui.marketPlot.blockSignals(True) self.ui.marketPlot.clear() self.ui.marketPlot.plot(xs, ys, pen=PG_LINEPEN) #, pen=None, symbol=None) obj = self.ui.marketPlot.getPlotItem() axis = obj.axes["bottom"]['item'] axis._dayscale = False if len(xs) > 1: # Hack: adjust X-axis display if (xs[-1] - xs[0]) >= 3600 * 24: # >= 1 day axis._dayscale = True self.ui.marketPlot.blockSignals(False) def updateRange(self, view, rng): if self.initfetch > 0: self.initfetch -= 1 return #price_low, price_high = rng[1] # (as integer) sec_start, sec_end = rng #[0] self.start_time = datetime.datetime.fromtimestamp(sec_start) self.stop_time = datetime.datetime.fromtimestamp(sec_end) self.resync() def updateTooltip(self, pos): data = self.ui.marketPlot.getPlotItem().listDataItems() if len(data) < 1: return points = data[0].curve act_pos = points.mapFromScene(pos) xs, ys = points.getData() x, j = snapTo(act_pos.x(), xs) if j < 0: self.__vLine.hide() self.__hLine.hide() self.__textPrice.hide() return y = ys[j] #print("SNAP:", j, x, y) self.__vLine.setPos(x) self.__hLine.setPos(y) self.__textPrice.setPos(x, y) price = "{price:.{precision}f}".format( price=y, precision=self.asset_b["precision"]) self.__textPrice.setText(price) self.__vLine.show() self.__hLine.show() self.__textPrice.show()
class MarketTab(QtGui.QWidget): def __init__(self, *args, **kwargs): self.iso = kwargs.pop("isolator", None) self.asset_a = kwargs.pop("asset_a", None) self.asset_b = kwargs.pop("asset_b", None) self._pairtag = self.asset_a["symbol"] + ":" + self.asset_b["symbol"] self.ping_callback = kwargs.pop("ping_callback", None) super(MarketTab, self).__init__(*args, **kwargs) self.ui = Ui_MarketTab() self.ui.setupUi(self) replaceAxis(self.ui.marketPlot, "bottom", TimeAxisItem(orientation='bottom')) #, # axisItems={'bottom': TimeAxisItem(orientation='bottom')} self._index = 999 self.ui.buyStack.setColumnCount(3) stretch_table(self.ui.buyStack, False, hidehoriz=True) self.ui.sellStack.setColumnCount(3) stretch_table(self.ui.sellStack, False, hidehoriz=True) self.subscribed = False self.updater = RemoteFetch() self._frame_buy = { "group": self.ui.buyGroup, "mainLabel": self.ui.buyMainLabel, "mainAmt": self.ui.buyMainAmount, "altLabel": self.ui.buyAltLabel, "altAmt": self.ui.buyAltAmount, "price": self.ui.buyPrice, "account": self.ui.buyAccount, "expireEdit": self.ui.buyExpireEdit, "expireFOK": self.ui.buyFOK, "fee": self.ui.buyFeeAsset, "button": self.ui.buyButton, "_commit_inv": True, "table": self.ui.sellStack, } self._frame_sell = { "group": self.ui.sellGroup, "mainLabel": self.ui.sellMainLabel, "mainAmt": self.ui.sellMainAmount, "altLabel": self.ui.sellAltLabel, "altAmt": self.ui.sellAltAmount, "price": self.ui.sellPrice, "account": self.ui.sellAccount, "expireEdit": self.ui.sellExpireEdit, "expireFOK": self.ui.sellFOK, "fee": self.ui.sellFeeAsset, "button": self.ui.sellButton, "_commit_inv": False, "table": self.ui.buyStack, } self.setupFrame(self._frame_buy, self.asset_a, self.asset_b, title="Buy ") self.setupFrame(self._frame_sell, self.asset_a, self.asset_b, title="Sell ") #self.ui.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) #self.ui.table.customContextMenuRequested.connect(self.show_orders_submenu) self.ui.closeButton.clicked.connect(self.close_me) self.ui.swapButton.clicked.connect(self.swap_me) def close_me(self): app().mainwin.closeMarket(self._pairtag) def swap_me(self): app().mainwin.swapMarket(self._pairtag) def close(self): # TODO: unsubscribe from market!!! pass def setupFrame(self, form, asset_a, asset_b, title="Trade "): form["group"].setTitle(title + asset_a["symbol"]) form["mainLabel"].setText(asset_a["symbol"]) form["altLabel"].setText(asset_b["symbol"]) form["price"].valueChanged.connect(self.price_value_changed) form["price"].setDecimals(asset_a["precision"]) form["price"].setMaximum(asset_a["options"]["max_supply"] * pow(10, asset_a["precision"])) form["mainAmt"].valueChanged.connect(self.main_amount_changed) form["mainAmt"].setDecimals(asset_a["precision"]) form["mainAmt"].setMaximum(asset_a["options"]["max_supply"] * pow(10, asset_a["precision"])) form["altAmt"].valueChanged.connect(self.alt_amount_changed) form["altAmt"].setDecimals(asset_b["precision"]) form["altAmt"].setMaximum(asset_b["options"]["max_supply"] * pow(10, asset_b["precision"])) form["table"].cellClicked.connect(self.cell_click) form["button"].clicked.connect(self.make_limit_order) def make_limit_order(self): form = self._frame_buy if self._frame_buy["button"] == self.sender( ) else self._frame_sell account_from = form["account"].currentText() sell_asset_name = self.asset_a["symbol"] sell_asset_amount = form["mainAmt"].value() buy_asset_name = self.asset_b["symbol"] buy_asset_amount = form["altAmt"].value() if form["_commit_inv"]: sell_asset_name = self.asset_b["symbol"] buy_asset_name = self.asset_a["symbol"] expire_seconds = deltasec(form["expireEdit"].text()) expire_fok = form["expireFOK"].isChecked() fee_asset = anyvalvis(form["fee"], None) #.currentText() try: trx = QTransactionBuilder.QSellAsset(account_from, sell_asset_name, sell_asset_amount, buy_asset_name, buy_asset_amount, expiration=expire_seconds, fill_or_kill=expire_fok, fee_asset=fee_asset, isolator=self.iso) except BaseException as error: showexc(error) def _set_spin_value(self, elem, value): elem.blockSignals(True) elem.setValue(value) elem.blockSignals(False) def price_value_changed(self): form = self._frame_buy if self._frame_buy["price"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if amt_a == 0 and price != 0: amt_a = amt_b / price self._set_spin_value(form["mainAmt"], amt_a) return amt_b = amt_a * price self._set_spin_value(form["altAmt"], amt_b) def main_amount_changed(self): form = self._frame_buy if self._frame_buy["mainAmt"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if price == 0 and amt_a != 0: price = amt_b / amt_a self._set_spin_value(form["price"], price) return amt_b = amt_a * price self._set_spin_value(form["altAmt"], amt_b) def alt_amount_changed(self): form = self._frame_buy if self._frame_buy["altAmt"] == self.sender( ) else self._frame_sell price = form["price"].value() amt_a = form["mainAmt"].value() amt_b = form["altAmt"].value() if price == 0 and amt_a != 0: price = amt_b / amt_a form["price"].setValue(price) self._set_spin_value(form["price"], price) return amt_a = amt_b / price self._set_spin_value(form["mainAmt"], amt_a) def cell_click(self, row, column): form = self._frame_buy if self._frame_buy["table"] == self.sender( ) else self._frame_sell valstr = form["table"].item(row, column).text().replace(",", "") val = float(str.split(valstr, " ")[0]) if column == 0: # price form["price"].setValue(val) if column == 1: # asset_a form["mainAmt"].setValue(val) if column == 2: # asset_b form["altAmt"].setValue(val) def _refreshTitle(self): #self._title = _translate("MainWindow", "Market", None) + " " + self._pairtag self._title = self._pairtag return self._title def show_orders_submenu(self, position): menu = QtGui.QMenu() qaction(self, menu, "Cancel Order...", self.cancel_order) menu.exec_(self.ui.table.viewport().mapToGlobal(position)) def cancel_order(self): table = self.ui.table indexes = table.selectionModel().selectedRows() if len(indexes) < 1: return index = indexes[0].row() order_id = table.item(index, 0).text() #b = table.item(index, 1).text() try: trx = QTransactionBuilder.QCancelOrder( self._account_name, order_id, #fee_asset=fee_asset, isolator=self.iso) except BaseException as error: showexc(error) def desync(self): self.subscribed = False def resync(self): self.updater.fetch(self.mergeMarket_before, self.iso, (self.asset_a, self.asset_b), self._pairtag, ready_callback=self.mergeMarket_after, ping_callback=self.ping_callback, description="Refreshing market") def mergeMarket_before(self, iso, pair, tag): #iso._wait_online(timeout=3) # will raise exception #if not(iso.is_connected()): # raise Exception asset_a = pair[0] asset_b = pair[1] rpc = iso.bts.rpc if not self.subscribed: s_id = rpc.get_subscription_id() subs = rpc.subscribe_to_market(s_id, asset_a["id"], asset_b["id"]) self._s_id = s_id self._tags.append("!" + str(s_id)) self.subscribed = True from bitshares.market import Market self.market = Market(tag, bitshares_instance=iso.bts) orders = self.market.orderbook() trades = self.market.trades(limit=100, raw=True) return ( orders, trades, ) def mergeMarket_after(self, request_id, args): ( orders, trades, ) = args self.fillTable(self.ui.buyStack, orders['bids']) self.fillTable(self.ui.sellStack, orders['asks'], True) self.plotChart(trades) def fillTable(self, table, orders, inv=False): color_a = COLOR_GREEN if inv else COLOR_RED color_b = COLOR_RED if inv else COLOR_GREEN table.setRowCount(0) j = -1 for order in orders: j += 1 table.insertRow(j) set_col(table, j, 0, str(order["price"])) set_col(table, j, 1, str(order["quote"]), color=color_a, align="right") set_col(table, j, 2, str(order["base"]), color=color_b, align="right") def plotChart(self, trades): xs = [] ys = [] import datetime for trade in trades: dt = datetime.datetime.strptime(trade["date"], "%Y-%m-%dT%H:%M:%S") x = int(dt.timestamp()) #trade["sequence"] y = float(trade["price"]) xs.append(x) ys.append(y) #print(xs, ys) #import numpy as np #x = np.random.normal(size=1000) #y = np.random.normal(size=1000) self.ui.marketPlot.clear() self.ui.marketPlot.plot(xs, ys) #, pen=None, symbol=None)
class Parser(): def __init__(self, sett, **kwargs): """ Инициализация класса, рынков и получение цены BTS :param set sett: настройки класса str quote - актив, стоимость которого считаем str base - актив, в котором считаем стоимость list additional_assets - дополнительные рынки для расчета, кроме BTS list usdt_assets - дополнительные рынки, стоимость которых равна стоимости актива base float base_depth - глубина расчета цены в стаканах в активе base float history_depth - глубина расчета цены совершенных сделок в активе base int price_precision - количество знаков после запятой, для отображения цен int orderbook_limit - максимальное количество сделок из стакана получаемое от ноды int history_limit - максимальное количество сделок получаемое из истории от ноды int history_period - максимальное количество дней, за которые берется история set viz_account - данные аккаунта для публикации в блокчейне VIZ """ self.sett = sett self.quote_market = Market(self.sett['quote'] + ':BTS') self.base_market = Market('BTS:' + self.sett['base']) book = self.base_market.orderbook(limit=1) self.price = {} self.price['BTS'] = (book['asks'][0]['price'] + book['bids'][0]['price']) / 2 self.bids = [] self.asks = [] def check_ask(self, base, core): """ Функция для создания нового "виртуального" ордера в формате пары self.sett['quote'] / BTS Возвращает True в случае попадания этого ордера в выборку и False в противном случае :param bitshares.price.Order base: ордер на продажу из пары self.sett['quote'] / BTS :param bitshares.price.Order core: ордер на продажу из пары BTS / self.sett['base'] Функция проверяет объемы в ордерах base и core и создает новый на основе меньшего из них """ base_amount = base['base']['amount'] core_amount = core['quote']['amount'] if base_amount >= core_amount: new_base = base.copy() new_base['quote'] = Amount( core_amount / base['price'], base['quote']['asset'] ) new_base['base'] = core['quote'] order = Order(new_base['quote'], core['base']) else: new_core = core.copy() new_core['base'] = Amount( base_amount * core['price'], core['base']['asset'] ) new_core['quote'] = base['base'] order = Order(base['quote'], new_core['base']) return self.create_asks([order]) def check_bid(self, base, core): """ Функция для создания нового "виртуального" ордера в формате пары self.sett['quote'] / BTS Возвращает True в случае попадания этого ордера в выборку и False в противном случае :param bitshares.price.Order base: ордер на покупку из пары self.sett['quote'] / BTS :param bitshares.price.Order core: ордер на покупку из пары BTS / self.sett['base'] Функция проверяет объемы в ордерах base и core и создает новый на основе меньшего из них """ base_amount = base['base']['amount'] core_amount = core['quote']['amount'] if base_amount >= core_amount: new_base = base.copy() new_base['quote'] = Amount( core_amount / base['price'], base['quote']['asset'] ) new_base['base'] = core['quote'] order = Order(new_base['quote'], core['base']) else: new_core = core.copy() new_core['base'] = Amount( base_amount * core['price'], core['base']['asset'] ) new_core['quote'] = base['base'] order = Order(base['quote'], new_core['base']) return self.create_bids([order]) def create_asks(self, asks): """ Функция для формирования выборки ордеров на продажу. Возвращает True в случае попадания первого ордера в выборку и False в противном случае :param list(bitshares.price.Order) asks: список ордеров на продажу в формате пары self.sett['quote'] / BTS Функция сортирует ордера в порядке увеличения цены и отсекает все, которые не вписываются в параметр self.sett['base_depth'] """ tmp_asks = self.asks tmp_asks.extend(asks) tmp_asks.sort() self.asks = [] asks_amount = 0 result = False for ask in tmp_asks: self.asks.append(ask) if ask == asks[0]: result = True amount = ask['base']['amount'] * self.price['BTS'] asks_amount += amount if asks_amount > self.sett['base_depth']: break return result def create_bids(self, bids): """ Функция для формирования выборки ордеров на покупку. Возвращает True в случае попадания первого ордера в выборку и False в противном случае :param list(bitshares.price.Order) bids: список ордеров на покупку в формате пары self.sett['quote'] / BTS Функция сортирует ордера в порядке уменьшения цены и отсекает все, которые не вписываются в параметр self.sett['base_depth'] """ tmp_bids = self.bids tmp_bids.extend(bids) tmp_bids.sort(reverse=True) self.bids = [] bids_amount = 0 result = False for bid in tmp_bids: self.bids.append(bid) if bid == bids[0]: result = True amount = bid['base']['amount'] * self.price['BTS'] bids_amount += amount if bids_amount > self.sett['base_depth']: break return result def get_additional_orderbook(self): """ Функция для проверки ордеров в стаканах пар указанные в параметре self.sett['additional_assets'] Функция получает из сети BitShares данные из всех стаканов указанных в параметре self.sett['additional_assets'] и формирует выборку на основе этих данных. Результаты ее работы сохраняются в переменных класса self.bids и self.asks """ for asset in self.sett['additional_assets']: market_base = Market(self.sett['quote'] + ':' + asset) market_core = Market(asset + ':BTS') book_base = market_base.orderbook( limit=self.sett['orderbook_limit'] ) book_core = market_core.orderbook( limit=self.sett['orderbook_limit'] ) for bid_base in book_base['bids']: check = False base_amount = bid_base['base']['amount'] bid_core = book_core['bids'][0] while base_amount > 0: core_amount = bid_core['quote']['amount'] check = self.check_bid(bid_base, bid_core) if base_amount >= core_amount: bid_base['quote'] -= Amount( core_amount / bid_base['price'], bid_base['quote']['asset'] ) bid_base['base'] -= bid_core['quote'] book_core['bids'].pop(0) bid_core = book_core['bids'][0] else: bid_core['base'] -= Amount( base_amount * bid_core['price'], bid_core['base']['asset'] ) bid_core['quote'] -= bid_base['base'] break if not check: base_amount = 0 else: base_amount = bid_base['base']['amount'] if not check: break for ask_base in book_base['asks']: check = False base_amount = ask_base['base']['amount'] ask_core = book_core['asks'][0] while base_amount > 0: core_amount = ask_core['quote']['amount'] check = self.check_ask(ask_base, ask_core) if base_amount >= core_amount: ask_base['quote'] -= Amount( core_amount / ask_base['price'], ask_base['quote']['asset'] ) ask_base['base'] -= ask_core['quote'] book_core['asks'].pop(0) ask_core = book_core['asks'][0] else: ask_core['base'] -= Amount( base_amount * ask_core['price'], ask_core['base']['asset'] ) ask_core['quote'] -= ask_base['base'] break if not check: base_amount = 0 else: base_amount = ask_base['base']['amount'] if not check: break def get_history_depth(self): """ Функция для рассчета средней цены совершенных сделок Функция собирает все данные из истории, сортирует их по дате, приводит цены к self.sett['base'] и отсекает все сделки выходящие за пределы self.sett['history_depth']. Результаты сохраняет в переменных класса self.history_amount и self.average_history_price """ history = [] sum = 0 start_time = datetime.now() - timedelta( days=self.sett['history_period'] ) for trade in self.quote_market.trades( limit=self.sett['history_limit'], start=start_time ): amount = trade['base']['amount'] * self.price['BTS'] history.append(trade) sum += amount if sum > self.sett['history_depth']: break history.sort(key=self.sortByTime, reverse=True) assets = self.sett['additional_assets'].copy() assets.extend(self.sett['usdt_assets']) for asset in assets: market = Market(asset + ':BTS') book = market.orderbook(limit=1) self.price[asset] = (book['asks'][0]['price'] + book['bids'][0]['price']) / 2*self.price['BTS'] market = Market(self.sett['quote'] + ':' + asset) for trade in market.trades( limit=self.sett['history_limit'], start=start_time ): history.append(trade) history.sort(key=self.sortByTime, reverse=True) amount = trade['base']['amount'] * self.price[asset] sum += amount break_bool = False while sum >= self.sett['history_depth']: last = history.pop() last_amount = (last['base']['amount'] * self.price[last['base']['symbol']]) if last_amount > sum - self.sett['history_depth']: history.append(last) break else: sum -= last_amount if (last['quote']['symbol'] == trade['quote']['symbol'] and last['base']['symbol'] == trade['base']['symbol']): if (collections.Counter(last) == collections.Counter(trade)): break_bool = True break if break_bool: break sum = sum_quote = 0 for h in history: sum += h['base']['amount'] * self.price[h['base']['symbol']] sum_quote += h['quote']['amount'] if sum > self.sett['history_depth']: last = history.pop() ratio = sum / self.sett['history_depth'] sum_quote = sum_quote / ratio sum = self.sett['history_depth'] self.history_amount = sum_quote self.average_history_price = sum / sum_quote def get_market_depth(self): """ Основная функция для расчета средней цены ордеров в стакане Функция поочередно вызывает дочерние функции self.get_orderbook(), self.get_additional_orderbook(), self.get_usdt_orderbook() для сбора ордеров из всех пар. А затем расчитывает среднюю цену и сохраняет данные в переменных класса self.average_bid_price и self.average_ask_price """ self.get_orderbook() self.get_additional_orderbook() self.get_usdt_orderbook() quote = base = sum = 0 for bid in self.bids: amount = bid['base']['amount'] * self.price['BTS'] if sum + amount <= self.sett['base_depth']: quote += bid['quote']['amount'] base += bid['base']['amount'] sum += amount else: diff = self.sett['base_depth'] - sum ratio = diff / amount quote += bid['quote']['amount'] * ratio base += bid['base']['amount'] * ratio sum += diff self.average_bid_price = base / quote * self.price['BTS'] quote = base = sum = 0 for ask in self.asks: amount = ask['base']['amount'] * self.price['BTS'] if sum + amount <= self.sett['base_depth']: quote += ask['quote']['amount'] base += ask['base']['amount'] sum += amount else: diff = self.sett['base_depth'] - sum ratio = diff / amount quote += ask['quote']['amount'] * ratio base += ask['base']['amount'] * ratio sum += diff self.average_ask_price = base / quote * self.price['BTS'] def get_orderbook(self): """ Функция получает ордера из пары self.sett['quote'] / BTS """ orderbook = self.quote_market.orderbook( limit=self.sett['orderbook_limit'] ) self.create_bids(orderbook['bids']) self.create_asks(orderbook['asks']) def get_usdt_orderbook(self): """ Функция для проверки ордеров в стаканах пар указанные в параметре self.sett['usdt_assets'] Функция получает из сети BitShares данные из всех стаканов указанных в параметре self.sett['usdt_assets'] и формирует выборку на основе этих данных. Результаты ее работы сохраняются в переменных класса self.bids и self.asks """ for asset in self.sett['usdt_assets']: market = Market(self.sett['quote'] + ':' + asset) book = market.orderbook( limit=self.sett['orderbook_limit'] ) for bid in book['bids']: amount = bid['base']['amount'] bid = Order( bid['quote'], Amount(amount / self.price['BTS'], 'BTS') ) if not self.create_bids([bid]): break for ask in book['asks']: amount = ask['base']['amount'] ask = Order( ask['quote'], Amount(amount / self.price['BTS'], 'BTS') ) if not self.create_asks([ask]): break def sortByTime(self, input): """ Вспомогательная функция для сортировки """ return input['time']
def get_history_depth(self): """ Функция для рассчета средней цены совершенных сделок Функция собирает все данные из истории, сортирует их по дате, приводит цены к self.sett['base'] и отсекает все сделки выходящие за пределы self.sett['history_depth']. Результаты сохраняет в переменных класса self.history_amount и self.average_history_price """ history = [] sum = 0 start_time = datetime.now() - timedelta( days=self.sett['history_period'] ) for trade in self.quote_market.trades( limit=self.sett['history_limit'], start=start_time ): amount = trade['base']['amount'] * self.price['BTS'] history.append(trade) sum += amount if sum > self.sett['history_depth']: break history.sort(key=self.sortByTime, reverse=True) assets = self.sett['additional_assets'].copy() assets.extend(self.sett['usdt_assets']) for asset in assets: market = Market(asset + ':BTS') book = market.orderbook(limit=1) self.price[asset] = (book['asks'][0]['price'] + book['bids'][0]['price']) / 2*self.price['BTS'] market = Market(self.sett['quote'] + ':' + asset) for trade in market.trades( limit=self.sett['history_limit'], start=start_time ): history.append(trade) history.sort(key=self.sortByTime, reverse=True) amount = trade['base']['amount'] * self.price[asset] sum += amount break_bool = False while sum >= self.sett['history_depth']: last = history.pop() last_amount = (last['base']['amount'] * self.price[last['base']['symbol']]) if last_amount > sum - self.sett['history_depth']: history.append(last) break else: sum -= last_amount if (last['quote']['symbol'] == trade['quote']['symbol'] and last['base']['symbol'] == trade['base']['symbol']): if (collections.Counter(last) == collections.Counter(trade)): break_bool = True break if break_bool: break sum = sum_quote = 0 for h in history: sum += h['base']['amount'] * self.price[h['base']['symbol']] sum_quote += h['quote']['amount'] if sum > self.sett['history_depth']: last = history.pop() ratio = sum / self.sett['history_depth'] sum_quote = sum_quote / ratio sum = self.sett['history_depth'] self.history_amount = sum_quote self.average_history_price = sum / sum_quote
def book(nodes, a=None, b=None): #updates orderbook details # create fresh websocket connections for this child instance account = Account(USERNAME, bitshares_instance=BitShares(nodes, num_retries=0)) market = Market(BitPAIR, bitshares_instance=BitShares(nodes, num_retries=0), mode='head') node = nodes[0] begin = time.time() while time.time() < (begin + TIMEOUT): time.sleep(random()) try: # add unix time to trades dictionary trades = market.trades(limit=100) for t in range(len(trades)): ts = time.strptime(str(trades[t]['time']), '%Y-%m-%d %H:%M:%S') trades[t]['unix'] = int(time.mktime(ts)) fprice = '%.16f' % float(trades[t]['price']) trades[t]['fprice'] = fprice[:10] + ',' + fprice[10:] # last price # last = market.ticker()['latest'] last = float(trades[0]['price']) slast = '%.16f' % last # complete account balances call = decimal(time.time()) raw = list(account.balances) elapsed = float(decimal(time.time()) - call) if elapsed > 1: continue elapsed = '%.17f' % elapsed cbalances = {} for i in range(len(raw)): cbalances[raw[i]['symbol']] = float(raw[i]['amount']) # orderbook raw = market.orderbook(limit=20) bids = raw['bids'] asks = raw['asks'] sbidp = [('%.16f' % bids[i]['price']) for i in range(len(bids))] saskp = [('%.16f' % asks[i]['price']) for i in range(len(asks))] sbidv = [('%.2f' % float(bids[i]['quote'])).rjust(12, ' ') for i in range(len(bids))] saskv = [('%.2f' % float(asks[i]['quote'])).rjust(12, ' ') for i in range(len(asks))] bidv = [float(bids[i]['quote']) for i in range(len(bids))] askv = [float(asks[i]['quote']) for i in range(len(asks))] cbidv = list(np.cumsum(bidv)) caskv = list(np.cumsum(askv)) cbidv = [('%.2f' % i).rjust(12, ' ') for i in cbidv] caskv = [('%.2f' % i).rjust(12, ' ') for i in caskv] # dictionary of currency and assets in this market currency = float(account.balance(BitCURRENCY)) assets = float(account.balance(BitASSET)) balances = {BitCURRENCY: currency, BitASSET: assets} # dictionary of open orders in traditional format: # orderNumber, orderType, market, amount, price orders = [] for order in market.accountopenorders(): orderNumber = order['id'] asset = order['base']['symbol'] currency = order['quote']['symbol'] amount = float(order['base']) price = float(order['price']) orderType = 'buy' if asset == BitASSET: orderType = 'sell' price = 1 / price else: amount = amount / price orders.append({ 'orderNumber': orderNumber, 'orderType': orderType, 'market': BitPAIR, 'amount': amount, 'price': ('%.16f' % price) }) trades = trades[:10] stale = int(time.time() - float(trades[0]['unix'])) # display orderbooks print("\033c") print(time.ctime(), ' ', int(time.time()), ' ', a, b) print(' PING', (elapsed), ' ', node) print('') print(' LAST', slast[:10] + ',' + slast[10:], ' ', BitPAIR) print('') print(' ', sbidv[0], ' ', (sbidp[0])[:10] + ',' + (sbidp[0])[10:], ' ', (saskp[0])[:10] + ',' + (saskp[0])[10:], (saskv[0])) print(' ', 'BIDS', ' ', 'ASKS') for i in range(1, len(sbidp)): print(cbidv[i], sbidv[i], ' ', (sbidp[i])[:10] + ',' + (sbidp[i])[10:], ' ', (saskp[i])[:10] + ',' + (saskp[i])[10:], saskv[i], caskv[i]) print('') for o in orders: print(o) if len(orders) == 0: print(' NO OPEN ORDERS') print('') print('%s BALANCE:' % BitPAIR) print(balances) print('') print('MARKET HISTORY:', stale, 'since last trade') for t in trades: # print(t.items()) print(t['unix'], str(t['time'])[11:19], t['fprice'], ('%.4f' % float(t['quote']['amount'])).rjust(12, ' ')) print('') print('ctrl+shift+\ will EXIT to terminal') print('') print('COMPLETE HOLDINGS:') print(cbalances) except: pass