def market_buy(self, quote_amount, price, return_none=False, *args, **kwargs): symbol = self.market['base']['symbol'] precision = self.market['base']['precision'] base_amount = truncate(price * quote_amount, precision) # Don't try to place an order of size 0 if not base_amount: self.log.critical('Trying to buy 0') self.disabled = True return None # Make sure we have enough balance for the order if self.returnOrderId and self.balance( self.market['base']) < base_amount: self.log.critical("Insufficient buy balance, needed {} {}".format( base_amount, symbol)) self.disabled = True return None self.log.info('Placing a buy order for {} {} @ {:.8f}'.format( base_amount, symbol, price)) # Place the order buy_transaction = self.retry_action(self.market.buy, price, Amount(amount=quote_amount, asset=self.market["quote"]), account=self.account.name, expiration=self.expiration, returnOrderId=self.returnOrderId, fee_asset=self.fee_asset['id'], *args, **kwargs) self.log.debug('Placed buy order {}'.format(buy_transaction)) if self.returnOrderId: buy_order = self.get_order(buy_transaction['orderid'], return_none=return_none) if buy_order and buy_order['deleted']: # The API doesn't return data on orders that don't exist # We need to calculate the data on our own buy_order = self.calculate_order_data(buy_order, quote_amount, price) self.recheck_orders = True return buy_order else: return True
def market_buy(self, amount, price): self.log.info('Placing a buy order for {} {} @ {}'.format( price * amount, self.market["base"]['symbol'], price)) buy_transaction = self.retry_action(self.market.buy, price, Amount(amount=amount, asset=self.market["quote"]), account=self.account.name, returnOrderId="head") self.log.info('Placed buy order {}'.format(buy_transaction)) buy_order = self.get_order(buy_transaction['orderid']) return buy_order
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 claim(ctx, vestingid, account, amount): """ Claim funds from the vesting balance """ vesting = Vesting(vestingid) if amount: amount = Amount(float(amount), "BTS") else: amount = vesting.claimable pprint( ctx.bitshares.vesting_balance_withdraw(vesting["id"], amount=amount, account=vesting["owner"]))
def update(ctx, ticket_id, target, amount, account): """ Update staking time of a voting ballot. Changes the stake-lock duration of a voting ticket. Can update full amount of a ticket or a partial amount. If partial, result is two separate tickets, putting optional AMOUNT on the new ticket/time-target while the old ticket retains the remainder. This command can also be used to "free" tickets by updating the time target to "liquid" (except for fully-charged lock_forever tickets). EXAMPLE 1: If ticket 1.18.xxx has 1000 BTS locked for 180 days, you could upgrade the entire ticket to a lock_forever ticket with: uptick ticket update 1.18.xxx lock_forever EXAMPLE 2: If ticket 1.18.yyy has 1500 BTS locked for 180 days, you could free a third of it with: uptick ticket update --amount 500 BTS 1.18.yyy liquid The release of BTS will follow a power-down schedule. """ amount = Amount(*amount) if amount[0] is not None else None ctx.blockchain.blocking = True tx = ctx.blockchain.update_voting_ticket(ticket_id, target, amount, account) tx.pop("trx", None) print_tx(tx) results = tx.get("operation_results", {}) if results: results = results[0][1] updates = results['updated_objects'] creates = results['new_objects'] removes = results['removed_objects'] monitor = updates + creates ticketword = {True: "voting tickets", False: "voting ticket"} if updates: print("Updated existing %s: " % ticketword[len(updates) > 1], end='') print(*updates, sep=', ') if creates: print("Created new %s: " % ticketword[len(creates) > 1], end='') print(*creates, sep=', ') if removes: print("Removed %s: " % ticketword[len(removes) > 1], end='') print(*removes, sep=', ') if monitor: print("Monitor your %s with: uptick info " % ticketword[len(monitor) > 1], end='') print(*monitor, sep=' ')
def take_offer(self, data): bitshares = BitShares(nobroadcast=False, keys=data['key'], blocking='head') trade_message = '' new_data = {} if data['market_or_pool'] == 'pool': new_data['operation_type'] = 'Pool Operation' if data['buy_or_sell'] == 'buy': amount_to_sell = Amount(data['expected_price']) new_data['anticipated'] = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) min_to_receive = new_data['anticipated'] * .993 trade_message = bitshares.exchange_with_liquidity_pool( pool=data['pool_id'], amount_to_sell=amount_to_sell, min_to_receive=min_to_receive, account=data['account'], ) else: amount_to_sell = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) new_data['anticipated'] = Amount(data['expected_price']) min_to_receive = new_data['anticipated'] * .993 trade_message = bitshares.exchange_with_liquidity_pool( pool=data['pool_id'], amount_to_sell=amount_to_sell, min_to_receive=min_to_receive, account=data['account'], ) new_data['operation_results'] = trade_message['operation_results'] new_data['paid'] = Amount(new_data['operation_results'][0][1]['paid'][0]) new_data['received'] = Amount(new_data['operation_results'][0][1]['received'][0]) # still not working quite right else: # market trade pass pub.sendMessage('print_transaction', data=new_data)
def place_market_sell_order(self, amount, price, return_none=False, *args, **kwargs): """ Places a sell order in the market :param float | amount: Order amount in QUOTE :param float | price: Order price in BASE :param bool | return_none: :param args: :param kwargs: :return: """ symbol = self.market['quote']['symbol'] precision = self.market['quote']['precision'] quote_amount = truncate(amount, precision) # Don't try to place an order of size 0 if not quote_amount: self.log.critical('Trying to sell 0') self.disabled = True return None # Make sure we have enough balance for the order if self.returnOrderId and self.balance(self.market['quote']) < quote_amount: self.log.critical("Insufficient sell balance, needed {} {}".format(amount, symbol)) self.disabled = True return None self.log.info('Placing a sell order for {} {} @ {:.8f}'.format(quote_amount, symbol, price)) # Place the order sell_transaction = self.retry_action( self.market.sell, price, Amount(amount=amount, asset=self.market["quote"]), account=self.account.name, expiration=self.expiration, returnOrderId=self.returnOrderId, fee_asset=self.fee_asset['id'], *args, **kwargs ) self.log.debug('Placed sell order {}'.format(sell_transaction)) if self.returnOrderId: sell_order = self.get_order(sell_transaction['orderid'], return_none=return_none) if sell_order and sell_order['deleted']: # The API doesn't return data on orders that don't exist, we need to calculate the data on our own sell_order = self.calculate_order_data(sell_order, amount, price) sell_order.invert() self.recheck_orders = True return sell_order else: return True
def test_transfer(self): tx = bitshares.transfer( "1.2.101", 1.33, "X4T", memo="Foobar", account="init0") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "transfer" ) op = tx["operations"][0][1] self.assertIn("memo", op) self.assertEqual(op["from"], "1.2.100") self.assertEqual(op["to"], "1.2.101") amount = Amount(op["amount"]) self.assertEqual(float(amount), 1.33)
def getAmount(self, asset_amount, asset_id, force_local=False): asset = self.getAsset(asset_id, force_local=force_local) #if type(asset_amount) == str: # asset_amount = float(asset_amount) #if type(asset_amount) == float: # asset_amount = int(asset_amount * 10 ** asset["precision"]) if type(asset_amount) == int: asset_amount = int(asset_amount) / 10**asset["precision"] from bitshares.amount import Amount return Amount(asset_amount, asset, blockchain_instance=self.bts)
def getAmount(self, asset_amount, asset_id): asset = self.getAsset(asset_id) #if type(asset_amount) == str: # asset_amount = float(asset_amount) #if type(asset_amount) == float: # asset_amount = int(asset_amount * 10 ** asset["precision"]) if type(asset_amount) == int: asset_amount = int(asset_amount) / 10**asset["precision"] from bitshares.amount import Amount return Amount(asset_amount, asset, bitshares_instance=self.bts)
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 market_sell(self, amount, price): self.log.info('Placing a sell order for {} {} @ {}'.format( amount, self.market["quote"]['symbol'], price)) sell_transaction = self.retry_action(self.market.sell, price, Amount( amount=amount, asset=self.market["quote"]), account=self.account.name, returnOrderId="head") self.log.info('Placed sell order {}'.format(sell_transaction)) sell_order = self.get_order(sell_transaction['orderid']) return sell_order
def sell(ctx, sell_amount, sell_asset, price, buy_asset, account): amount = Amount(sell_amount, sell_asset) price = Price( price, quote=sell_asset, base=buy_asset, bitshares_instance=ctx.bitshares ) pprint(price.market.sell( price, amount, account=account ))
def fees(ctx, currency): """ List fees """ from bitsharesbase.operationids import getOperationNameForId from bitshares.market import Market market = Market("%s:%s" % (currency, "BTS")) ticker = market.ticker() if "quoteSettlement_price" in ticker: price = ticker.get("quoteSettlement_price") else: price = ticker.get("latest", 0) price.invert() chain = Blockchain(bitshares_instance=ctx.bitshares) feesObj = chain.chainParameters().get("current_fees") fees = feesObj["parameters"] t = [["Operation", "Type", "Fee", currency]] for fee in fees: for f in fee[1]: t.append( [ highlight(getOperationNameForId(fee[0])), detail(f), detail( str(Amount({"amount": fee[1].get(f, 0), "asset_id": "1.3.0"})) ), detail( str( price * Amount({"amount": fee[1].get(f, 0), "asset_id": "1.3.0"}) ) ), ] ) print_table(t)
def sell(ctx, sell_amount, sell_asset, price, buy_asset, order_expiration, account): """ Sell a specific asset at a certain rate against a base asset """ amount = Amount(sell_amount, sell_asset) price = Price(price, quote=sell_asset, base=buy_asset, bitshares_instance=ctx.bitshares) print_tx( price.market.sell(price, amount, account=account, expiration=order_expiration))
def _populate(self): self.update({ "asset_a": Asset(self["object"]["asset_a"]), "asset_b": Asset(self["object"]["asset_b"]), "share_asset": Asset(self["object"]["share_asset"]), "taker_fee": int(self["object"]["taker_fee_percent"]) / 10000, }) share_ddo = self.blockchain.rpc.get_object( self["share_asset"]["dynamic_asset_data_id"]) self.update({ "amount_a": Amount( int(self["object"]["balance_a"]) / 10**self["asset_a"].precision, self["asset_a"]), "amount_b": Amount( int(self["object"]["balance_b"]) / 10**self["asset_b"].precision, self["asset_b"]), })
def test_transfer(self): bts = self.bts tx = bts.transfer( "1.2.8", 1.33, core_unit, memo="Foobar", account="1.2.7") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "transfer" ) op = tx["operations"][0][1] self.assertIn("memo", op) self.assertEqual(op["from"], "1.2.7") self.assertEqual(op["to"], "1.2.8") amount = Amount(op["amount"]) self.assertEqual(float(amount), 1.33)
def buy(ctx, buy_amount, buy_asset, price, sell_asset, order_expiration, account): """ Buy a specific asset at a certain rate against a base asset """ amount = Amount(buy_amount, buy_asset) price = Price(price, base=sell_asset, quote=buy_asset, bitshares_instance=ctx.bitshares) pprint( price.market.buy(price, amount, account=account, expiration=order_expiration))
def test_init(self): # self.assertEqual(1, 1) Price("0.315 USD/BTS") Price(1.0, "USD/GOLD") Price(0.315, base="USD", quote="BTS") Price(0.315, base=Asset("USD"), quote=Asset("BTS")) Price( { "base": {"amount": 1, "asset_id": "1.3.0"}, "quote": {"amount": 10, "asset_id": "1.3.106"}, } ) Price( { "receives": {"amount": 1, "asset_id": "1.3.0"}, "pays": {"amount": 10, "asset_id": "1.3.106"}, }, base_asset=Asset("1.3.0"), ) Price(quote="10 GOLD", base="1 USD") Price("10 GOLD", "1 USD") Price(Amount("10 GOLD"), Amount("1 USD"))
def test_init(self): # String init amount = Amount("1 {}".format(self.symbol)) self.dotest(amount, 1, self.symbol) # Amount init amount = Amount(amount) self.dotest(amount, 1, self.symbol) # blockchain dict init amount = Amount({ "amount": 1 * 10 ** self.precision, "asset_id": self.asset["id"] }) self.dotest(amount, 1, self.symbol) # API dict init amount = Amount({ "amount": 1.3 * 10 ** self.precision, "asset": self.asset["id"] }) self.dotest(amount, 1.3, self.symbol) # Asset as symbol amount = Amount(1.3, Asset("1.3.0")) self.dotest(amount, 1.3, self.symbol) # Asset as symbol amount = Amount(1.3, self.symbol) self.dotest(amount, 1.3, self.symbol) # keyword inits amount = Amount(amount=1.3, asset=Asset("1.3.0")) self.dotest(amount, 1.3, self.symbol) # keyword inits amount = Amount(amount=1.3, asset=dict(Asset("1.3.0"))) self.dotest(amount, 1.3, self.symbol) # keyword inits amount = Amount(amount=1.3, asset=self.symbol) self.dotest(amount, 1.3, self.symbol)
def get_blockchain_info(self): try: data = {'pool': Pool(self.pool_id_or_sym, invert=self.invert)} data['pool_object'] = data['pool']['object'] data['pool_name'] = Asset( data['pool_object']['share_asset']).symbol data['asset_x'] = Asset(data['pool_object']['asset_a']) data['asset_y'] = Asset(data['pool_object']['asset_b']) data['amount_x'] = Amount( int(data['pool_object']['balance_a']) / 10**data['asset_x'].precision, data['asset_x']) data['amount_y'] = Amount( int(data['pool_object']['balance_b']) / 10**data['asset_y'].precision, data['asset_y']) self.amount_x = data['amount_x'] self.amount_y = data['amount_y'] data['market_ticker_object'] = Market( # python bitshares reverses base and quote base=data['asset_y'], quote=data['asset_x']).ticker() data['market_orderbook'] = Market( base=data['asset_y'], quote=data['asset_x']).orderbook(50) data['pool_invariant'] = int( data['pool_object']['virtual_value']) / (10**( data['asset_x'].precision + data['asset_y'].precision)) #print(f"Invariant: {data['pool_invariant']}") # python bitshares reverses base and quote data['price_xy'] = Price(base=data['amount_y'], quote=data['amount_x']) data['price_yx'] = Price(base=data['amount_x'], quote=data['amount_y']) pub.sendMessage('update_gui', data=data) except Exception as err: print('Invalid pool selected. Error: {}'.format(err)) pub.sendMessage('invalid_pool')
def count_asset(self, order_ids=None, return_asset=False): """ Returns the combined amount of the given order ids and the account balance The amounts are returned in quote and base assets of the market :param list | order_ids: list of order ids to be added to the balance :param bool | return_asset: true if returned values should be Amount instances :return: dict with keys quote and base Todo: When would we want the sum of a subset of orders? Why order_ids? Maybe just specify asset? """ quote = 0 base = 0 quote_asset = self.market['quote']['id'] base_asset = self.market['base']['id'] # Total balance calculation for balance in self.balances: if balance.asset['id'] == quote_asset: quote += balance['amount'] elif balance.asset['id'] == base_asset: base += balance['amount'] if order_ids is None: # Get all orders from Blockchain order_ids = [order['id'] for order in self.own_orders] if order_ids: orders_balance = self.get_allocated_assets(order_ids) quote += orders_balance['quote'] base += orders_balance['base'] if return_asset: quote = Amount(quote, quote_asset, bitshares_instance=self.bitshares) base = Amount(base, base_asset, bitshares_instance=self.bitshares) return {'quote': quote, 'base': base}
def fees(ctx, currency): """ List fees """ from bitsharesbase.operationids import getOperationNameForId from bitshares.market import Market market = Market("%s:%s" % (currency, "BTS")) ticker = market.ticker() if "quoteSettlement_price" in ticker: price = ticker.get("quoteSettlement_price") else: price = ticker.get("latest", 0) chain = Blockchain(bitshares_instance=ctx.bitshares) feesObj = chain.chainParameters().get("current_fees") scale = feesObj["scale"] fees = feesObj["parameters"] t = PrettyTable(["Operation", "Type", "Fee", currency]) t.align = "l" t.align["Fee"] = "r" t.align[currency] = "r" for fee in fees: for f in fee[1]: t.add_row([ getOperationNameForId(fee[0]), f, str(Amount({ "amount": fee[1].get(f, 0), "asset_id": "1.3.0" })), str(price * Amount({ "amount": fee[1].get(f, 0), "asset_id": "1.3.0" })) ]) click.echo(t)
def test_increase_order_sizes_valley_imbalaced_small_further(worker, do_initial_allocation, increase_until_allocated): """ If furthest orders are smaller than closest, they should be increased first. See https://github.com/Codaone/DEXBot/issues/444 for details Buy side, amounts in BASE: 5 5 5 100 100 10 10 10 <center> Should be: 10 10 10 100 100 10 10 10 <center> """ worker = do_initial_allocation(worker, 'valley') # Cancel several closest orders num_orders_to_cancel = 3 worker.cancel_orders_wrapper(worker.buy_orders[:num_orders_to_cancel]) # Cancel furthest orders worker.cancel_orders_wrapper(worker.buy_orders[-num_orders_to_cancel:]) worker.refresh_orders() worker.refresh_balances() # Place limited orders initial_base = worker.buy_orders[0]['base']['amount'] base_limit = initial_base / 2 for i in range(0, num_orders_to_cancel): # Place smaller closer order worker.place_closer_order('base', worker.buy_orders[0], own_asset_limit=base_limit) # place_further_order() doesn't have own_asset_limit, so do own calculation further_order = worker.place_further_order('base', worker.buy_orders[-1], place_order=False) # Place smaller further order to_buy = base_limit / further_order['price'] worker.place_market_buy_order(to_buy, further_order['price']) worker.refresh_orders() # Drop excess balance to only allow one increase round worker.refresh_balances() increase_factor = max(1 + worker.increment, worker.min_increase_factor) to_keep = base_limit * (increase_factor - 1) * num_orders_to_cancel * 2 * 1.01 to_drop = worker.base_balance['amount'] - to_keep amount = Amount(to_drop, worker.market['base']['symbol'], bitshares_instance=worker.bitshares) worker.bitshares.reserve(amount, account=worker.account) increase_until_allocated(worker) for i in range(1, num_orders_to_cancel): further_order_amount = worker.buy_orders[-i]['base']['amount'] closer_order_amount = worker.buy_orders[i - 1]['base']['amount'] assert further_order_amount == closer_order_amount
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 == 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 json.dumps(op, indent=4)
def create(ctx, to, amount, symbol, type, hash, expiration, length, account): """ Create an HTLC contract from a hash and lock-time """ ctx.blockchain.blocking = True tx = ctx.blockchain.htlc_create(Amount(amount, symbol), to, hash_type=type, hash_hex=hash, expiration=expiration, account=account, preimage_length=length) tx.pop("trx", None) print_tx(tx) results = tx.get("operation_results", {}) if results: htlc_id = results[0][1] print("Your htlc_id is: {}".format(htlc_id))
def bitasset_local(bitshares, base_bitasset, default_account): asset = base_bitasset() dex = Dex(blockchain_instance=bitshares) # Set initial price feed price = Price(1.5, base=asset, quote=Asset("TEST")) bitshares.publish_price_feed(asset.symbol, price, account=default_account) # Borrow some amount to_borrow = Amount(100, asset) dex.borrow(to_borrow, collateral_ratio=2.1, account=default_account) # Drop pricefeed to cause margin call price = Price(1.0, base=asset, quote=Asset("TEST")) bitshares.publish_price_feed(asset.symbol, price, account=default_account) return asset
def create(ctx, target, amount, symbol, account): """ Create a voting ballot. Lock a quantity of core token for a period of time for vote-weight multiplication. """ ctx.blockchain.blocking = True tx = ctx.blockchain.create_voting_ticket(target, Amount(amount, symbol), account) tx.pop("trx", None) print_tx(tx) results = tx.get("operation_results", {}) if results: ballot_id = results[0][1] print("Your voting ticket id is: {}".format(ballot_id)) print("Use 'uptick info {}' to monitor your ticket.".format(ballot_id))
def appendTransferOpToTx(builder, from_name, to_name, amount, symbol): ## TODO: Cleanup exception catching for better user feedback try: account = Account(from_name, blockchain_instance=blockchain) to = Account(to_name, blockchain_instance=blockchain) amountAsset = Amount(amount, symbol, blockchain_instance=blockchain) except NumRetriesReached: Logger.Write( "ERROR: Can't reach API node: 'NumRetries' reached. Check network connection." ) raise except AssetDoesNotExistsException as e: Logger.Write("ERROR: Asset or token '%s' not known." % str(e)) raise except AccountDoesNotExistsException as e: Logger.Write("ERROR: Account '%s' not known." % str(e)) raise except Exception as e: Logger.Write("Unknown problem constructing Transfer operation: %s" % str(e)) raise memoObj = Memo(from_account=account, to_account=to, blockchain_instance=blockchain) memo_text = "" #"Signed by BitShares App on Ledger Nano S!" op = operations.Transfer( **{ "fee": { "amount": 0, "asset_id": "1.3.0" }, "from": account["id"], "to": to["id"], "amount": { "amount": int(amountAsset), "asset_id": amountAsset.asset["id"] }, "memo": memoObj.encrypt(memo_text), }) builder.appendOps(op) return builder
def account_balances(account_name: hug.types.text, api_key: hug.types.text, hug_timer=5): """Bitshares account balances! Simply supply an account name & provide the API key!""" if (check_api_token(api_key) == True): # Check the api key # API KEY VALID try: target_account = Account(account_name, full=True) except: print("Account doesn't exist.") return { 'valid_account': False, 'account': account_name, 'valid_key': True, 'took': float(hug_timer) } target_account_balances = target_account.balances if (len(target_account_balances) > 0): balance_json_list = {} for balance in target_account_balances: current_balance_target = Amount(balance) balance_json_list[current_balance_target. symbol] = current_balance_target.amount return { 'balances': balance_json_list, 'account_has_balances': True, 'account': account_name, 'valid_account': True, 'valid_key': True, 'took': float(hug_timer) } else: return { 'account_has_balances': False, 'account': account_name, 'valid_account': True, 'valid_key': True, 'took': float(hug_timer) } else: # API KEY INVALID! return {'valid_key': False, 'took': float(hug_timer)}