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 process_market(self, data): """ This method is used for post processing of market notifications. It will return instances of either * :class:`bitshares.price.Order` or * :class:`bitshares.price.FilledOrder` """ for d in data: if not d: continue if isinstance(d, str): # Single order has been placed log.info("Calling on_market with Order()") self.on_market(Order(d)) continue elif isinstance(d, dict): d = [d] # Orders have been matched for p in d: if not isinstance(p, list): p = [p] for i in p: if isinstance(i, dict): if "pays" in i and "receives" in i: self.on_market(FilledOrder(i)) elif "for_sale" in i and "sell_price" in i: self.on_market(Order(i))
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 pprintOperation(op): from bitshares.price import Order, FilledOrder id = op["op"][0] op = op["op"][1] if id == 1: return str(Order(op)) elif id == 4: return str(FilledOrder(op)) elif id == 5: return "New account created for {}".format(op["name"]) elif id == 2: return "Canceled order %s" % op["order"] elif id == 6: return "Account {} updated".format(Account(op["account"])["name"]) elif id == 33: return "Claiming from vesting: %s" % str(Amount(op["amount"])) elif id == 15: return "Reserve {}".format(str(Amount(op["amount_to_reserve"]))) elif id == 0: from_account = Account(op["from"]) to_account = Account(op["to"]) amount = Amount(op["amount"]) return "Transfer from {from_account[name]} to {to_account[name]}: {amount}".format( **locals()) else: return format_dict(op)
def updated_open_orders(self): """ Returns updated open Orders. account.openorders doesn't return updated values for the order so we calculate the values manually """ self.account.refresh() self.account.ensure_full() limit_orders = self.account['limit_orders'][:] for o in limit_orders: base_amount = o['for_sale'] assert type(base_amount) in [int, float ], "o['for_sale'] not num {}".format( dict(o)) assert type(o['sell_price']['base']['amount']) in [ int, float ], "o['sell_base']['base']['amount'] not num {}".format(dict(o)) assert type(o['sell_price']['quote']['amount']) in [ int, float ], "o['sell_base']['quote']['amount'] not num {}".format(dict(o)) price = o['sell_price']['base']['amount'] / o['sell_price'][ 'quote']['amount'] quote_amount = base_amount / price o['sell_price']['base']['amount'] = base_amount o['sell_price']['quote']['amount'] = quote_amount orders = [ Order(o, bitshares_instance=self.bitshares) for o in limit_orders ] return [o for o in orders if self.worker["market"] == o.market]
def get_updated_order(self, order_id): """ Tries to get the updated order from the API. Returns None if the order doesn't exist :param str|dict order_id: blockchain Order object or id of the order """ if isinstance(order_id, dict): order_id = order_id['id'] # At first, try to look up own orders. This prevents RPC calls whether requested order is own order order = None for limit_order in self.account['limit_orders']: if order_id == limit_order['id']: order = limit_order break else: # We are using direct rpc call here because passing an Order object to self.get_updated_limit_order() give # us weird error "Object of type 'BitShares' is not JSON serializable" order = self.bitshares.rpc.get_objects([order_id])[0] # Do not try to continue whether there is no order in the blockchain if not order: return None updated_order = self.get_updated_limit_order(order) return Order(updated_order, bitshares_instance=self.bitshares)
def get_updated_order(self, order_id): """ Tries to get the updated order from the API returns None if the order doesn't exist :param str|dict order_id: blockchain object id of the order can be an order dict with the id key in it """ if isinstance(order_id, dict): order_id = order_id['id'] # Get the limited order by id order = None for limit_order in self.account['limit_orders']: if order_id == limit_order['id']: order = limit_order break else: return order # Do not try to continue whether there is no order in the blockchain if not order: return None order = self.get_updated_limit_order(order) return Order(order, bitshares_instance=self.bitshares)
def pprintOperation(op): from bitshares.price import Order, FilledOrder if op["op"][0] == 1: return str(Order(op["op"][1])) if op["op"][0] == 4: return str(FilledOrder(op["op"][1])) else: return json.dumps(op["op"][1], indent=4)
def process_market(self, data): """ This method is used for post processing of market notifications. It will return instances of either * :class:`bitshares.price.Order` or * :class:`bitshares.price.FilledOrder` or * :class:`bitshares.price.UpdateCallOrder` Also possible are limit order updates (margin calls) """ for d in data: if not d: continue if isinstance(d, str): # Single order has been placed log.debug("Calling on_market with Order()") self.on_market(Order(d, bitshares_instance=self.bitshares)) continue elif isinstance(d, dict): d = [d] # Orders have been matched for p in d: if not isinstance(p, list): p = [p] for i in p: if isinstance(i, dict): if "pays" in i and "receives" in i: self.on_market( FilledOrder(i, bitshares_instance=self.bitshares)) elif "for_sale" in i and "sell_price" in i: self.on_market( Order(i, bitshares_instance=self.bitshares)) elif "collateral" in i and "call_price" in i: self.on_market( UpdateCallOrder( i, bitshares_instance=self.bitshares)) else: if i: log.error("Unknown market update type: %s" % i)
def market_asks(self): limits = self.market().get_limit_orders(300) asks = [] for lim in limits: if lim['for_sale']['asset'] == self.asset_y(): order = Order(1.0 / lim['price'], quote=lim['for_sale'], base=Amount( lim['for_sale']['amount'] / lim['price'], self.asset_x())) asks.append(order) return sorted(asks, key=lambda k: k['price'])
def get_limit_orders(self, depth=1): """ Returns orders from the current market. Orders are sorted by price. Does not require account info. get_limit_orders() call does not have any depth limit. :param int depth: Amount of orders per side will be fetched, default=1 :return: Returns a list of orders or None """ orders = self.bitshares.rpc.get_limit_orders( self.market['base']['id'], self.market['quote']['id'], depth) orders = [Order(o, bitshares_instance=self.bitshares) for o in orders] return orders
def get_order(order_id, return_none=True): """ Returns the Order object for the order_id :param str|dict order_id: blockchain object id of the order can be a dict with the id key in it :param bool return_none: return None instead of an empty Order object when the order doesn't exist """ if 'id' in order_id: order_id = order_id['id'] order = Order(order_id) if return_none and order['deleted']: return None return order
def get_market_orders(self, depth=1, updated=True): """ Returns orders from the current market. Orders are sorted by price. get_limit_orders() call does not have any depth limit. :param int | depth: Amount of orders per side will be fetched, default=1 :param bool | updated: Return updated orders. "Updated" means partially filled orders will represent remainders and not just initial amounts :return: Returns a list of orders or None """ orders = self.bitshares.rpc.get_limit_orders( self.market['base']['id'], self.market['quote']['id'], depth) if updated: orders = [self.get_updated_limit_order(o) for o in orders] orders = [Order(o, bitshares_instance=self.bitshares) for o in orders] return orders
def updated_orders(self): """ Returns all open orders as updated orders """ self.account.refresh() limited_orders = [] for order in self.account['limit_orders']: base_asset_id = order['sell_price']['base']['asset_id'] quote_asset_id = order['sell_price']['quote']['asset_id'] # Check if the order is in the current market if not self.is_current_market(base_asset_id, quote_asset_id): continue limited_orders.append(self.get_updated_limit_order(order)) return [ Order(o, bitshares_instance=self.bitshares) for o in limited_orders ]
def pprintOperation(op): from bitshares.price import Order, FilledOrder id = op["op"][0] op = op["op"][1] if id == 1: return str(Order(op)) elif id == 4: return str(FilledOrder(op)) elif id == 2: return "Canceled order %s" % op["order"] elif id == 0: from_account = Account(op["from"]) to_account = Account(op["to"]) amount = Amount(op["amount"]) return "Transfer from {from_account[name]} to {to_account[name]}: {amount}".format( **locals()) else: return json.dumps(op, indent=4)
def get_updated_order(self, order_id): # Todo: This needed? """ Tries to get the updated order from the API. Returns None if the order doesn't exist :param str|dict order_id: blockchain object id of the order can be an order dict with the id key in it """ if isinstance(order_id, dict): order_id = order_id['id'] # Get the limited order by id order = None for limit_order in self.account['limit_orders']: if order_id == limit_order['id']: order = limit_order break else: return order order = self.get_updated_limit_order(order) return Order(order, bitshares_instance=self.bitshares)
def get_order(self, order_id, return_none=True): """ Get Order object with order_id :param str | dict order_id: blockchain object id of the order can be an order dict with the id key in it :param bool return_none: return None instead of an empty Order object when the order doesn't exist :return: Order object """ if not order_id: return None if 'id' in order_id: order_id = order_id['id'] try: order = Order(order_id, bitshares_instance=self.bitshares) except Exception: logging.getLogger(__name__).error( 'Got an exception getting order id {}'.format(order_id)) raise if return_none and order['deleted']: return None return order
def updated_open_orders(self): """ Returns updated open Orders. account.openorders doesn't return updated values for the order so we calculate the values manually """ self.account.refresh() self.account.ensure_full() limit_orders = self.account['limit_orders'][:] for o in limit_orders: base_amount = float(o['for_sale']) price = float(o['sell_price']['base']['amount']) / float( o['sell_price']['quote']['amount']) quote_amount = base_amount / price o['sell_price']['base']['amount'] = base_amount o['sell_price']['quote']['amount'] = quote_amount orders = [ Order(o, bitshares_instance=self.bitshares) for o in limit_orders ] return [o for o in orders if self.worker["market"] == o.market]
def pprintOperation(op, show_memo=False, ctx=None): from bitshares.price import Order, FilledOrder if isinstance(op, dict) and "op" in op: id = op["op"][0] op = op["op"][1] else: id = op[0] op = op[1] if id == 1: return str(Order(op)) elif id == 4: return str(FilledOrder(op)) elif id == 5: return "New account created for {}".format(op["name"]) elif id == 2: return "Canceled order %s" % op["order"] elif id == 6: return "Account {} updated".format(Account(op["account"])["name"]) elif id == 33: return "Claiming from vesting: %s" % str(Amount(op["amount"])) elif id == 15: return "Reserve {}".format(str(Amount(op["amount_to_reserve"]))) elif id == 0: from_account = Account(op["from"]) to_account = Account(op["to"]) amount = Amount(op["amount"]) memo = "" if show_memo and ctx is not None: try: plain_memo = Memo(blockchain_instance=ctx.blockchain).decrypt( op["memo"]) except Exception as e: plain_memo = str(e) memo = " (memo: {plain_memo})".format(**locals()) return "Transfer from {from_account[name]} to {to_account[name]}: {amount}{memo}".format( **locals()) else: return format_dict(op)
def update_orders(self, new_sell_order, new_buy_order): """ Update the orders """ # Stored orders sell_order = self['sell_order'] buy_order = self['buy_order'] sell_price = self.sell_price buy_price = self.buy_price sold_amount = 0 if new_sell_order and new_sell_order['base']['amount'] < sell_order[ 'base']['amount']: # Some of the sell order was sold sold_amount = sell_order['base']['amount'] - new_sell_order[ 'base']['amount'] elif not new_sell_order and sell_order: # All of the sell order was sold sold_amount = sell_order['base']['amount'] bought_amount = 0 if new_buy_order and new_buy_order['quote']['amount'] < buy_order[ 'quote']['amount']: # Some of the buy order was bought bought_amount = buy_order['quote']['amount'] - new_buy_order[ 'quote']['amount'] elif not new_buy_order and buy_order: # All of the buy order was bought bought_amount = buy_order['quote']['amount'] if sold_amount: # We sold something, place updated buy order try: buy_order_amount = buy_order['quote']['amount'] except KeyError: buy_order_amount = 0 new_buy_amount = buy_order_amount - bought_amount + sold_amount if float(self.balance(self.market["base"])) < new_buy_amount: self.log.critical( 'Insufficient buy balance, needed {} {}'.format( buy_price * new_buy_amount, self.market['base']['symbol'])) self.disabled = True else: if buy_order and not Order(buy_order['id'])['deleted']: # Cancel the old order self.cancel(buy_order) buy_transaction = self.market.buy( buy_price, Amount(amount=new_buy_amount, asset=self.market["quote"]), account=self.account, returnOrderId="head") buy_order = self.get_order(buy_transaction['orderid']) self.log.info('Placed a buy order for {} {} @ {}'.format( new_buy_amount, self.market["quote"], buy_price)) if buy_order: self['buy_order'] = buy_order else: # Update the buy order self['buy_order'] = new_buy_order or {} if bought_amount: # We bought something, place updated sell order try: sell_order_amount = sell_order['base']['amount'] except KeyError: sell_order_amount = 0 new_sell_amount = sell_order_amount + bought_amount - sold_amount if float(self.balance(self.market["quote"])) < new_sell_amount: self.log.critical( "Insufficient sell balance, needed {} {}".format( new_sell_amount, self.market["quote"]['symbol'])) self.disabled = True else: if sell_order and not Order(sell_order['id'])['deleted']: # Cancel the old order self.cancel(sell_order) sell_transaction = self.market.sell( sell_price, Amount(amount=new_sell_amount, asset=self.market["quote"]), account=self.account, returnOrderId="head") sell_order = self.get_order(sell_transaction['orderid']) self.log.info('Placed a sell order for {} {} @ {}'.format( new_sell_amount, self.market["quote"], buy_price)) if sell_order: self['sell_order'] = sell_order else: # Update the sell order self['sell_order'] = new_sell_order or {}