def test_float(self): self.assertEqual( float(Amount("1", self.symbol)), 1.00000)
def updateorders(self, newprice): """ Update the orders """ self.log.info("Replacing orders. Baseprice is %f" % newprice) step1 = self.worker['spread'] / 200.0 * newprice step2 = self.worker['staggerspread'] / 100.0 * newprice self['price'] = newprice # apply bias if self.worker['bias'] != 0.0: newprice = (100.0 + self.worker['bias']) / 100.0 * newprice self.log.info("After applying bias of %f%% baseprice is now %f" % (self.worker['bias'], newprice)) # Canceling orders self.cancel_all() # record balances if hasattr(self, "record_balances"): self.record_balances(newprice) myorders = {} if newprice < self.worker["min"]: self.disabled = True self.log.critical("Price {} is below minimum {}".format( newprice, self.worker["min"])) return False if newprice > self.worker["max"]: self.disabled = True self.log.critical("Price {} is above maximum {}".format( newprice, self.worker["max"])) return False sell_wall = self.balance( self.market['quote']) * self.worker['wall_percent'] / 100.0 sell_price = newprice + step1 for i in range(0, self.worker['staggers']): self.log.info( "Entering SELL order {amt} at {price:.4g} {base}/{quote} (= {inv_price:.4g} {quote}/{base})" .format(amt=repr(sell_wall), price=sell_price, inv_price=1 / sell_price, quote=self.market['quote']['symbol'], base=self.market['base']['symbol'])) ret = self.market.sell(sell_price, sell_wall, account=self.account, returnOrderId="head") self.log.debug("SELL order done") myorders[ret['orderid']] = sell_price sell_price += step2 buy_wall = Amount( float( self.balance(self.market['base']) * self.worker['wall_percent'] / 100.00 / newprice), self.market['quote']) buy_price = newprice - step1 for i in range(0, self.worker['staggers']): self.log.info( "Entering BUY order {amt} at {price:.4g} {base}/{quote} (= {inv_price:.4g} {quote}/{base})" .format(amt=repr(buy_wall), price=buy_price, inv_price=1 / buy_price, quote=self.market['quote']['symbol'], base=self.market['base']['symbol'])) ret = self.market.buy( buy_price, buy_wall, account=self.account, returnOrderId="head", ) self.log.debug("BUY order done") myorders[ret['orderid']] = buy_price buy_price -= step2 self['myorders'] = myorders # ret = self.execute() this doesn't seem to work reliably # self.safe_dissect(ret,"execute") return True
def test_int(self): self.assertEqual( int(Amount("1", self.symbol)), 100000)
def get_balances(self, take, continuation=None, addresses=None): # deprecated, redo logic according to azure storage for performance address_balances = collections.defaultdict( lambda: collections.defaultdict()) if continuation is None: continuation = 0 if not addresses: addresses = [ x["address"] for x in list( self._address_storage.find({ "usage": "balance" }).sort([("_id", pymongo.ASCENDING)])) ] lenAddresses = len(addresses) try: end = (min(continuation + take, lenAddresses)) except TypeError: raise InputInvalidException() addresses = addresses[continuation:end] if end >= lenAddresses: end = None address_balances["continuation"] = end if type(addresses) == str: addresses = [addresses] for address in addresses: addrs = split_unique_address(address) max_block_number = 0 for operation in self.get_operations_completed( filter_by={"customer_id": addrs["customer_id"]}): this_block_num = operation["block_num"] asset_id = operation["amount_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": address_balances[address].get(asset_id, "0") }) amount_value = Amount({ "asset_id": asset_id, "amount": operation["amount_value"] }) if addrs["account_id"] == operation["from"]: # negative address_balances[address][asset_id] =\ str(int(balance - amount_value)) # fee as well asset_id = operation["fee_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": address_balances[address].get(asset_id, "0") }) fee_value = Amount({ "asset_id": asset_id, "amount": operation["fee_value"] }) address_balances[address][asset_id] =\ str(int(balance - fee_value)) elif addrs["account_id"] == operation["to"]: # positive address_balances[address][asset_id] =\ str(int(balance + amount_value)) else: raise InvalidOperationException() max_block_number = max(max_block_number, this_block_num) if max_block_number > 0: address_balances[address]["block_num"] = max_block_number # do not return default dicts for key, value in address_balances.items(): if type(value) == collections.defaultdict: address_balances[key] = dict(value) return dict(address_balances)
from bitshares import BitShares from bitshares.amount import Amount bitshares = BitShares(nobroadcast=False) bitshares.wallet.unlock(getpass()) proposal = bitshares.new_proposal( proposer="xeroc", proposal_expiration=timedelta(days=3).seconds, proposal_review=3600, ) for i in range(1, 4): bitshares.create_worker( "refund100k-{}".format(i), daily_pay=Amount(100000, "BTS"), begin=datetime(2019, 2, 1, 0, 0, 0), end=datetime(2030, 12, 31, 23, 59, 59), payment_type="refund", account="committee-account", append_to=proposal, ) for i in range(1, 4): bitshares.create_worker( "refund50k-{}".format(i), daily_pay=Amount(50000, "BTS"), begin=datetime(2019, 2, 1, 0, 0, 0), end=datetime(2030, 12, 31, 23, 59, 59), payment_type="refund", account="committee-account",
def build_transaction(incidentId, fromAddress, fromMemoWif, toAddress, asset_id, amount, includeFee, bitshares_instance=None): """ Builds a transaction (without signature) :param guid incidentId: Lykke unique operation ID :param str fromAddress: Source address :param str toAddress: Destination address :param str assetId: Asset ID to transfer :param str amount: Amount to transfer. Integer as string, aligned to the asset accuracy. Actual value can be calculated as x = amount / (10 ^ asset.Accuracy) :param bool includeFee: Flag, which indicates, that the fee should be included in the specified amount """ def obtain_raw_tx(): # if old_operation is None: _memo = memo.encrypt(memo_plain) _expiration = Config.get("bitshares", "transaction_expiration_in_sec", 60 * 60 * 24) # 24 hours # else: # memo_encrypted = memo.encrypt(memo_plain) op = operations.Transfer(**{ "fee": { "amount": 0, "asset_id": "1.3.0" }, # will be replaced "from": from_account["id"], "to": to_account["id"], "amount": amount.json(), "memo": _memo, "prefix": bitshares_instance.prefix }) tx = TransactionBuilder( bitshares_instance=bitshares_instance ) tx.appendOps(op) tx.set_expiration(_expiration) # Build the transaction, obtain fee to be paid tx.constructTx() return tx.json() operation_formatter.validate_incident_id(incidentId) if not is_valid_address(fromAddress): raise AccountDoesNotExistsException() if not is_valid_address(toAddress): raise AccountDoesNotExistsException() # # check if this was already built # old_operation = None # try: # old_operation = _get_os().get_operation(incidentId) # except OperationNotFoundException: # pass # Decode addresses from_address = split_unique_address(fromAddress) to_address = split_unique_address(toAddress) # obtain chain accounts from addresses from_account = Account( from_address["account_id"], bitshares_instance=bitshares_instance) to_account = Account( to_address["account_id"], bitshares_instance=bitshares_instance) memo_plain = create_memo(from_address, to_address, incidentId) try: # Construct amount amount = Amount( { "amount": amount, "asset_id": asset_id }, bitshares_instance=bitshares_instance ) except AssetDoesNotExistsException: raise AssetNotFoundException() # encrypt memo # TODO this is a hack. python-bitshares issue is opened, once resolve, fix if not fromMemoWif: if from_address["account_id"] == Config.get("bitshares", "exchange_account_id"): fromMemoWif = Config.get("bitshares", "exchange_account_memo_key") if fromMemoWif: bitshares_instance.wallet.setKeys(fromMemoWif) # memo key of the account must be known! if not from_account["options"]["memo_key"] in Wallet.keys: raise MemoMatchingFailedException() memo = Memo( from_account=from_account, to_account=to_account, bitshares_instance=bitshares_instance ) try: tx = obtain_raw_tx() except MissingKeyError: raise MemoMatchingFailedException() fee = Amount(tx["operations"][0][1]["fee"], bitshares_instance=bitshares_instance) # virtual internal transfers always do full amount if includeFee and from_account != to_account: # Reduce fee from amount to transfer amount -= fee tx = obtain_raw_tx() # Add additional/optional information # - add incident_id as fallback for internal database # - add decoded memo to avoid double decoding tx.update({ "incident_id": incidentId, "decoded_memo": memo_plain, }) if bitshares_instance.prefix != "BTS": tx["prefix"] = bitshares_instance.prefix return {"transactionContext": json.dumps(tx)}
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 zero_balance_quote(asset): if asset == worker.market['quote']: return Amount(0, asset, bitshares_instance=bitshares) else: return Amount(100, asset, bitshares_instance=bitshares)
def place_market_sell_order(self, amount, price, return_none=False, invert=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 bool | invert: True = return inverted sell order :param args: :param kwargs: :return: """ symbol = self.market['quote']['symbol'] precision = self.market['quote']['precision'] quote_amount = truncate(amount, precision) return_order_id = kwargs.pop('returnOrderId', self.returnOrderId) # 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 return_order_id 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 with {:.{prec}f} {} @ {:.8f}'.format( quote_amount, symbol, price, prec=precision)) # 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=return_order_id, fee_asset=self.fee_asset['id'], *args, **kwargs) self.log.debug('Placed sell order {}'.format(sell_transaction)) if return_order_id: 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) self.recheck_orders = True if sell_order and invert: sell_order.invert() return sell_order else: return True
def place_market_buy_order(self, amount, price, return_none=False, *args, **kwargs): """ Places a buy 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['base']['symbol'] precision = self.market['base']['precision'] base_amount = truncate(price * amount, precision) return_order_id = kwargs.pop('returnOrderId', self.returnOrderId) # 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 return_order_id 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 with {:.{prec}f} {} @ {:.8f}'.format( base_amount, symbol, price, prec=precision)) # Place the order buy_transaction = self.retry_action( self.market.buy, price, Amount(amount=amount, asset=self.market["quote"], bitshares_instance=self.bitshares), account=self.account.name, expiration=self.expiration, returnOrderId=return_order_id, fee_asset=self.fee_asset['id'], *args, **kwargs) self.log.debug('Placed buy order {}'.format(buy_transaction)) if return_order_id: 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, amount, price) self.recheck_orders = True return buy_order else: return True
def _get_balances_recalculate(self, take, continuation=None, addresses=None): address_balances = collections.defaultdict(lambda: collections.defaultdict()) if not addresses: if continuation is not None: try: continuation_marker = json.loads(continuation) continuation_marker = str(continuation_marker) except TypeError: raise InputInvalidException() except JSONDecodeError: raise InputInvalidException() addresses = self._service.query_entities( self._azure_config["address_table"] + "balance", num_results=take, marker=continuation_marker) else: addresses = self._service.query_entities( self._azure_config["address_table"] + "balance", num_results=take) if addresses.next_marker: address_balances["continuation"] = json.dumps(addresses.next_marker) addresses = [x["address"] for x in addresses] if type(addresses) == str: addresses = [addresses] for address in addresses: addrs = split_unique_address(address) max_block_number = 0 for operation in self.get_operations_completed( filter_by={ "customer_id": addrs["customer_id"] }): this_block_num = operation["block_num"] asset_id = operation["amount_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": address_balances[address].get(asset_id, "0")}) amount_value = Amount({ "asset_id": asset_id, "amount": operation["amount_value"]}) if addrs["account_id"] == operation["from"]: # negative address_balances[address][asset_id] =\ str(int(balance - amount_value)) # fee as well asset_id = operation["fee_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": address_balances[address].get(asset_id, "0")}) fee_value = Amount({ "asset_id": asset_id, "amount": operation["fee_value"]}) address_balances[address][asset_id] =\ str(int(balance - fee_value)) elif addrs["account_id"] == operation["to"]: # positive address_balances[address][asset_id] =\ str(int(balance + amount_value)) else: raise InvalidOperationException() max_block_number = max(max_block_number, this_block_num) if max_block_number > 0: address_balances[address]["block_num"] = max_block_number # do not return default dicts for key, value in address_balances.items(): if type(value) == collections.defaultdict: address_balances[key] = dict(value) return dict(address_balances)
def _ensure_balances(self, operation): affected_address = get_tracking_address(operation) logging.getLogger(__name__).debug("_ensure_balances: with " + operation["chain_identifier"] + " for address " + str(affected_address)) try: self._get_address(affected_address) except AddressNotTrackedException: # delte if exists and return try: self._delete_balance(affected_address) except AzureMissingResourceHttpError: pass return try: balance_dict = self._service.get_entity( self._azure_config["balances_table"], self._short_digit_hash(affected_address), affected_address) insert = False except AzureMissingResourceHttpError as e: balance_dict = {"address": affected_address} balance_dict["PartitionKey"] = self._short_digit_hash(balance_dict["address"]) balance_dict["RowKey"] = balance_dict["address"] insert = True if operation["block_num"] < balance_dict.get("blocknum", 0): raise BalanceConcurrentException() elif operation["block_num"] == balance_dict.get("blocknum", 0) and\ operation["txnum"] < balance_dict.get("txnum", 0): raise BalanceConcurrentException() elif operation["block_num"] == balance_dict.get("blocknum", 0) and\ operation["txnum"] == balance_dict.get("txnum", 0) and\ operation["opnum"] <= balance_dict.get("opnum", 0): raise BalanceConcurrentException() balance_dict["blocknum"] = max(balance_dict.get("blocknum", 0), operation["block_num"]) balance_dict["txnum"] = max(balance_dict.get("txnum", 0), operation["tx_in_block"]) balance_dict["opnum"] = max(balance_dict.get("opnum", 0), operation["op_in_tx"]) total = 0 addrs = split_unique_address(affected_address) asset_id_key = "balance" + operation["amount_asset_id"].split("1.3.")[1] asset_id = operation["amount_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": balance_dict.get(asset_id_key, "0")}) amount_value = Amount({ "asset_id": asset_id, "amount": operation["amount_value"]}) if addrs["account_id"] == operation["from"]: # internal transfer and withdraw # negative balance_dict[asset_id_key] = str(int(balance - amount_value)) # fee as well asset_id_key = "balance" + operation["fee_asset_id"].split("1.3.")[1] asset_id = operation["fee_asset_id"] balance = Amount({ "asset_id": asset_id, "amount": balance_dict.get(asset_id_key, "0")}) fee_value = Amount({ "asset_id": asset_id, "amount": operation["fee_value"]}) balance_dict[asset_id_key] = str(int(balance - fee_value)) elif addrs["account_id"] == operation["to"]: # deposit # positive balance_dict[asset_id_key] = str(int(balance + amount_value)) # fees were paid by someone else else: raise InvalidOperationException() for key, value in balance_dict.items(): if key.startswith("balance"): total = total + int(value) if total == 0: if not insert: try: self._delete_balance(affected_address, if_match=balance_dict.etag) except AzureMissingResourceHttpError: pass return # may be updated or inserted, total > 0 if (insert): try: self._service.insert_entity( self._azure_config["balances_table"], balance_dict ) except AzureMissingResourceHttpError: raise OperationStorageException("Critical error in database consistency") else: try: self._service.update_entity( self._azure_config["balances_table"], balance_dict, if_match=balance_dict.etag ) except AzureConflictHttpError: raise OperationStorageException("Critical error in database consistency")