def test_float(self):
     self.assertEqual(
         float(Amount("1", self.symbol)),
         1.00000)
Example #2
0
    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)
Example #4
0
    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",
Example #6
0
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
Example #8
0
 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)
Example #9
0
    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
Example #10
0
    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
Example #11
0
    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)
Example #12
0
    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")