def get_balances(self): available = { 'GOLOS': Amount(self['balance']).amount, 'GBG': Amount(self['sbd_balance']).amount, 'GESTS': Amount(self['vesting_shares']).amount, } savings = { 'GOLOS': Amount(self['savings_balance']).amount, 'GBG': Amount(self['savings_sbd_balance']).amount, } totals = { 'GOLOS': sum([available['GOLOS'], savings['GOLOS']]), 'GBG': sum([available['GBG'], savings['GBG']]), 'GESTS': sum([available['GESTS']]), } total = walk_values(rpartial(round, 3), totals) return { 'available': available, 'savings': savings, 'total': total, }
def estimate_median_price(steemd_instance, verbose=False): """ Calculate new expected median price based on current price feeds :param Steem steemd_instance: Steem() instance to use when accesing a RPC :param bool verbose: print witnesses sorted by price feed """ count = 21 try: witnesses = steemd_instance.get_witnesses_by_vote('', count) except Exception as e: log.error(e) return False # add price key for w in witnesses: base = Amount(w['sbd_exchange_rate']['base']).amount quote = Amount(w['sbd_exchange_rate']['quote']).amount w['price'] = base / quote # sort witnesses by price sorted_w = sorted(witnesses, key=lambda k: k['price']) if verbose: for w in sorted_w: print('{}: {:.3f}'.format(w['owner'], w['price'])) # 11th element price return sorted_w[10]['price']
def curation_stats(self): trailing_24hr_t = time.time() - datetime.timedelta( hours=24).total_seconds() trailing_7d_t = time.time() - datetime.timedelta( days=7).total_seconds() reward_24h = 0.0 reward_7d = 0.0 for reward in take(5000, self.history_reverse(filter_by="curation_reward")): timestamp = parse_time(reward["timestamp"]).timestamp() if timestamp > trailing_7d_t: reward_7d += Amount(reward["reward"]).amount if timestamp > trailing_24hr_t: reward_24h += Amount(reward["reward"]).amount reward_7d = self.converter.vests_to_sp(reward_7d) reward_24h = self.converter.vests_to_sp(reward_24h) return { "24hr": reward_24h, "7d": reward_7d, "avg": reward_7d / 7, }
def steem_per_mvests(self): """ Obtain STEEM/MVESTS ratio """ info = self.steemd.get_dynamic_global_properties() return ( Amount(info["total_vesting_fund_steem"]).amount / (Amount(info["total_vesting_shares"]).amount / 1e6) )
def sbd_median_price(self): """ Obtain the sbd price as derived from the median over all witness feeds. Return value will be SBD """ return (Amount(self.steemd.get_feed_history()['current_median_history'] ['base']).amount / Amount(self.steemd.get_feed_history()['current_median_history'] ['quote']).amount)
def estimate_median_price(self) -> float: """Calculate new expected median price based on last median price feed.""" last_feed = self.get_feed_history()['price_history'][-1] base = Amount(last_feed['base']).amount quote = Amount(last_feed['quote']).amount price = base / quote return price
def get_min_price(self) -> float: """Get GBG/GOLOS minimal price (limit by chain).""" props = self.get_dynamic_global_properties() sbd_supply = Amount(props['current_sbd_supply']) current_supply = Amount(props['current_supply']) # libraries/chain/database.cpp # this min_price caps system debt to 10% of GOLOS market capitalisation min_price = 9 * sbd_supply.amount / current_supply.amount return min_price
def estimate_median_price_from_feed(steemd_instance): """ Calculate new expected median price based on last median price feed :param Steem steemd_instance: Steem() instance to use when accesing a RPC """ last_feed = steemd_instance.get_feed_history()['price_history'][-1:] base = Amount(last_feed[0]['base']) quote = Amount(last_feed[0]['quote']) median = base.amount / quote.amount return median
def main(ctx): """Show pricefeed history.""" hist = ctx.helper.get_feed_history()['price_history'] hist_size = len(hist) # median history contains values for STEEMIT_FEED_HISTORY_WINDOW # median price update performed once per hour for i in hist: timestamp = datetime.now() - timedelta(hours=hist_size) base = Amount(i['base']) quote = Amount(i['quote']) price = base.amount / quote.amount print('{}: {:.3f}'.format(timestamp.strftime('%d.%m.%Y %H'), price)) # use hist_size as iterator hist_size -= 1
def main(): parser = argparse.ArgumentParser( description='Scan account history looking for transfers', epilog='Report bugs to: https://github.com/bitfag/golos-scripts/issues' ) parser.add_argument('-d', '--debug', action='store_true', help='enable debug output'), parser.add_argument('-c', '--config', default='./common.yml', help='specify custom path for config file') parser.add_argument( '-a', '--amount', type=float, default=0, help='minimal transfer amount to look for (default: 0)') parser.add_argument( '-l', '--limit', type=int, default=50, help='limit number of transactions to scan, default: 50') parser.add_argument('account', help='account to scan') args = parser.parse_args() # create logger if args.debug == True: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") handler.setFormatter(formatter) log.addHandler(handler) # parse config with open(args.config, 'r') as ymlfile: conf = yaml.load(ymlfile) golos = Steem(nodes=conf['nodes_old'], keys=conf['keys']) account = Account(args.account, steemd_instance=golos) history = account.rawhistory(only_ops=['transfer'], limit=args.limit) for item in history: #pprint(item) timestamp = datetime.strptime(item[1]['timestamp'], '%Y-%m-%dT%H:%M:%S') t_from = item[1]['op'][1]['from'] to = item[1]['op'][1]['to'] amount = Amount(item[1]['op'][1]['amount']) if amount.amount > args.amount: print('{}: {:<16} -> {:<16}, {}'.format(timestamp, t_from, to, amount))
def calc_payout(steemd_instance, net_rshares, curve='linear'): """ Calc payout in GOLOS based on net_rshares https://golos.io/ru--apvot50-50/@now/kak-na-samom-dele-rabotayut-kvadratichnye-nachisleniya-golosa-2kh-50-50 :param Steem steemd_instance: Steem() instance to use when accesing a RPC :param int net_rshares: net_rshares to calculate payout from :param str curve: reward curve :return float payout: payout amount in GOLOS """ try: global_props = steemd_instance.get_dynamic_global_properties() except Exception as e: log.error(e) return False if curve == 'quadratic': # perform same calculations as golosd v0.16.4 # c++ code: return (rshares + s) * (rshares + s) - s * s; vshares = (net_rshares + CONTENT_CONSTANT) * ( net_rshares + CONTENT_CONSTANT) - CONTENT_CONSTANT**2 elif curve == 'linear': vshares = net_rshares total_reward_fund_steem = Amount(global_props['total_reward_fund_steem']) total_reward_shares2 = int(global_props['total_reward_shares2']) payout = vshares * total_reward_fund_steem.amount / total_reward_shares2 log.debug('calculated post payout, GOLOS: {:.8f}'.format(payout)) return payout
def refresh(self): post_author, post_permlink = resolve_identifier(self.identifier) post = self.steemd.get_content(post_author, post_permlink) if not post["permlink"]: raise PostDoesNotExist("Post does not exist: %s" % self.identifier) # If this 'post' comes from an operation, it might carry a patch if "body" in post and re.match("^@@", post["body"]): self.patched = True # TODO: Check # This field is returned from blockchain, but it's empty. Fill it post['reblogged_by'] = [i for i in self.steemd.get_reblogged_by(post_author, post_permlink) if i != post_author] # Parse Times parse_times = ["active", "cashout_time", "created", "last_payout", "last_update", "max_cashout_time"] for p in parse_times: post[p] = parse_time(post.get(p, "1970-01-01T00:00:00")) # Parse Amounts sbd_amounts = [ 'total_payout_value', 'max_accepted_payout', 'pending_payout_value', 'curator_payout_value', 'total_pending_payout_value', 'promoted', ] for p in sbd_amounts: post[p] = Amount(post.get(p, "0.000 GBG")) # calculate trending and hot scores for sorting post['score_trending'] = calculate_trending(post.get('net_rshares', 0), post['created']) post['score_hot'] = calculate_hot(post.get('net_rshares', 0), post['created']) # turn json_metadata into python dict meta_str = post.get("json_metadata", "{}") post['json_metadata'] = silent(json.loads)(meta_str) or {} post["tags"] = [] post['community'] = '' if isinstance(post['json_metadata'], dict): if post["depth"] == 0: tags = [post["parent_permlink"]] tags += get_in(post, ['json_metadata', 'tags'], default=[]) tags_set = set(tags) post["tags"] = [tag for tag in tags if tag not in tags_set] post['community'] = get_in(post, ['json_metadata', 'community'], default='') # If this post is a comment, retrieve the root comment self.root_identifier, self.category = self._get_root_identifier(post) self._store_post(post)
def get_witness_pricefeed(self, witness: Union[str, Dict]) -> float: """Obtain current published price for single witness.""" if isinstance(witness, str): witness_data = Witness(witness) else: witness_data = witness base = Amount(witness_data['sbd_exchange_rate']['base']).amount quote = Amount(witness_data['sbd_exchange_rate']['quote']).amount # whether witness not exists yet, return 0 if quote == 0: return 0 price = base / quote return price
def main(ctx, min_mgests, account): """Find all vesting withdrawals with rates and dates.""" ctx.log.debug('total accounts: %s', ctx.helper.get_account_count()) if account: accs = [account] else: accs = ctx.helper.get_all_usernames() start = datetime.utcnow() # get all accounts in one batch all_accounts = ctx.helper.get_accounts(accs) # we well get summary info about total withdrawal rate and number of accounts sum_rate = float() count = int() cv = ctx.helper.converter steem_per_mvests = cv.steem_per_mvests() for acc in all_accounts: vshares = Amount(acc['vesting_shares']) mgests = vshares.amount / 1000000 rate = Amount(acc['vesting_withdraw_rate']) date = parse_time(acc['next_vesting_withdrawal']) if mgests > min_mgests and rate.amount > 1000: # We use own calculation instead of cv.vests_to_sp() to speed up execution # avoiding API call on each interation rate_gp = rate.amount / 1e6 * steem_per_mvests gp = vshares.amount / 1e6 * steem_per_mvests sum_rate += rate_gp count += 1 print('{:<16} {:<18} {:>6.0f} {:>8.0f}'.format( acc['name'], date.strftime('%Y-%m-%d %H:%M'), rate_gp, gp)) ctx.log.debug('accounts iteration took {:.2f} seconds'.format( (datetime.utcnow() - start).total_seconds())) ctx.log.info( 'numbers of matching accounts on vesting withdrawal: {}'.format(count)) ctx.log.info('sum rate: {:.0f}'.format(sum_rate))
def main(ctx, gests, from_, to, amount): if gests: gests = amount else: cv = ctx.helper.converter gests = cv.sp_to_vests(amount) gests = Amount('{} GESTS'.format(gests)) ctx.helper.delegate_vesting_shares(to, gests, account=from_)
def get_price_feeds(self) -> List[feed]: """Get current price feeds as reported by witnesses.""" witnesses = self.get_active_witnesses() witnesses = [Witness(i) for i in witnesses] # add price key for i in witnesses: base = Amount(i['sbd_exchange_rate']['base']).amount quote = Amount(i['sbd_exchange_rate']['quote']).amount try: i['price'] = base / quote except ZeroDivisionError: pass feeds = [ feed(i['owner'], i['price']) for i in witnesses if 'price' in i ] feeds = sorted(feeds, key=lambda k: k.price) return feeds
def get_ticker(self): """ Returns the ticker for all markets. Output Parameters: * ``latest``: Price of the order last filled * ``lowest_ask``: Price of the lowest ask * ``highest_bid``: Price of the highest bid * ``sbd_volume``: Volume of SBD * ``steem_volume``: Volume of STEEM * ``percent_change``: 24h change percentage (in %) .. note:: Market is STEEM:SBD and prices are SBD per STEEM! Sample Output: .. code-block:: js {'highest_bid': 0.30100226633322913, 'latest': 0.0, 'lowest_ask': 0.3249636958897082, 'percent_change': 0.0, 'sbd_volume': 108329611.0, 'steem_volume': 355094043.0} """ t = self.steemd.get_ticker() return { 'highest_bid': float(t['highest_bid']), 'latest': float(t["latest"]), 'lowest_ask': float(t["lowest_ask"]), 'percent_change': float(t["percent_change"]), 'sbd_volume': Amount(t["sbd_volume"]), 'steem_volume': Amount(t["steem_volume"]) }
def main(ctx, account): """Calculate profit from vesting holdings.""" props = ctx.helper.get_dynamic_global_properties() acc = Account(account) balance = acc.get_balances() account_vesting = balance['total']['GESTS'] vesting_fund = Amount(props['total_vesting_shares']) daily_emission = ctx.helper.calc_inflation() vesting_share = account_vesting / vesting_fund.amount ctx.log.info(f'{account} vesting share: {vesting_share:.4%}') daily_account_vesting = vesting_share * daily_emission.vesting ctx.log.info(f'{account} daily vesting: {daily_account_vesting:.0f}')
def sbd_to_rshares(self, sbd_payout): """ Obtain r-shares from SBD :param number sbd_payout: Amount of SBD """ steem_payout = self.sbd_to_steem(sbd_payout) props = self.steemd.get_dynamic_global_properties() total_reward_fund_steem = Amount(props['total_reward_fund_steem']) total_reward_shares2 = int(props['total_reward_shares2']) post_rshares2 = (steem_payout / total_reward_fund_steem) * total_reward_shares2 rshares = math.sqrt(self.CONTENT_CONSTANT ** 2 + post_rshares2) - self.CONTENT_CONSTANT return rshares
def main(ctx, amount_limit, limit, account): """Scan account history looking for transfers.""" account = Account(account) history = account.rawhistory(only_ops=['transfer'], limit=limit) for item in history: ctx.log.debug(pformat(item)) timestamp = parse_time(item[1]['timestamp']) from_ = item[1]['op'][1]['from'] to = item[1]['op'][1]['to'] amount = Amount(item[1]['op'][1]['amount']) memo = item[1]['op'][1]['memo'] if amount.amount > amount_limit: print('{}: {:<16} -> {:<16}, {}, {}'.format(timestamp, from_, to, amount, memo))
def typify(value: Union[dict, list, set, str]): """ Enhance block operation with native types. Typify takes a blockchain operation or dict/list/value, and then it parses and converts string types into native data types where appropriate. """ if type(value) == dict: return walk_values(typify, value) if type(value) in [list, set]: return list(map(typify, value)) if type(value) == str: if re.match('^\d+\.\d+ (GOLOS|GBG|GESTS)$', value): return keep_in_dict(dict(Amount(value)), ['amount', 'asset']) if re.match('^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$', value): return parse_time(value) return value
def get_balances(self): available = { "GOLOS": Amount(self["balance"]).amount, "GBG": Amount(self["sbd_balance"]).amount, "GESTS": Amount(self["vesting_shares"]).amount, } savings = { "GOLOS": Amount(self["savings_balance"]).amount, "GBG": Amount(self["savings_sbd_balance"]).amount, } accumulative = {"GOLOS": Amount(self["accumulative_balance"]).amount} tip = {"GOLOS": Amount(self["tip_balance"]).amount} totals = { "GOLOS": sum([ available["GOLOS"], savings["GOLOS"], accumulative["GOLOS"], tip["GOLOS"] ]), "GBG": sum([available["GBG"], savings["GBG"]]), "GESTS": sum([available["GESTS"]]), } total = walk_values(rpartial(round, 3), totals) return { "available": available, "savings": savings, "accumulative": accumulative, "tip": tip, "total": total, }
def reward(self): """Return a float value of estimated total SBD reward. """ return Amount(self.get("total_payout_value", "0 SBD")) + \ Amount(self.get("pending_payout_value", "0 SBD"))
def test_amount_init(): a = Amount('1 GOLOS') assert dict(a) == {'amount': 1.0, 'asset': 'GOLOS'}
def sp(self): vests = Amount(self["vesting_shares"]).amount return round(self.converter.vests_to_sp(vests), 3)
def main(): parser = argparse.ArgumentParser( description='Use this script to estimate potential upvote profit', epilog='Report bugs to: https://github.com/bitfag/golos-scripts/issues' ) parser.add_argument('-d', '--debug', action='store_true', help='enable debug output'), parser.add_argument('-c', '--config', default='./common.yml', help='specify custom path for config file') parser.add_argument( 'account', help='specify account which upvote should be estimated') parser.add_argument('-p', '--percent', default=100, type=float, help='specify upvote percent') parser.add_argument('--curve', default='linear', choices=['quadratic', 'linear'], help='select curve type') parser.add_argument('-u', '--url', help='post id in format @author/article or full url') args = parser.parse_args() # create logger if args.debug == True: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter("%(levelname)s: %(message)s") handler.setFormatter(formatter) log.addHandler(handler) # parse config with open(args.config, 'r') as ymlfile: conf = yaml.load(ymlfile) golos = Steem(nodes=conf['nodes_old'], keys=conf['keys']) if args.curve == 'quadratic': if not args.url: log.critical( 'you need to provide --url when using quadratic curve') sys.exit(1) # extract author and post permlink from args.url p = re.search('@(.*?)/([^/]+)', args.url) if p == None: log.critical('Wrong post id specified') sys.exit(1) else: author = p.group(1) log.debug('author: {}'.format(author)) post_permlink = p.group(2) log.debug('permlink: {}'.format(post_permlink)) post = functions.get_post_content(golos, author, post_permlink) if not post: log.critical('could not find post in blockchain') sys.exit(1) # current post rshares net_rshares = int(post['net_rshares']) # current pending_payout_value, GBG current_pending_payout_value = post['pending_payout_value'] log.info('current pending_payout_value: {}'.format( current_pending_payout_value)) # estimate current expected author reward author_payout_gp, author_payout_gbg, author_payout_golos = functions.estimate_author_payout( golos, current_pending_payout_value) log.info( 'estimated author payout: {:.3f} GBG, {:.3f} GOLOS, {:.3f} GP'. format(author_payout_gbg, author_payout_golos, author_payout_gp)) rshares = functions.calc_rshares(golos, args.account, args.percent) new_rshares = net_rshares + rshares new_payout = functions.calc_payout(golos, new_rshares) new_payout_gbg = functions.convert_golos_to_gbg(golos, new_payout, price_source='median') new_payout_gbg = Amount('{} GBG'.format(new_payout_gbg)) log.info('new pending_payout_value: {}'.format(new_payout_gbg)) payout_diff = new_payout_gbg.amount - current_pending_payout_value.amount log.info('pending_payout diff: {:.3f}'.format(payout_diff)) # estimate new author reward author_payout_gp, author_payout_gbg, author_payout_golos = functions.estimate_author_payout( golos, new_payout_gbg) log.info( 'new estimated author payout: {:.3f} GBG, {:.3f} GOLOS, {:.3f} GP'. format(author_payout_gbg, author_payout_golos, author_payout_gp)) elif args.curve == 'linear': rshares = functions.calc_rshares(golos, args.account, args.percent) payout = functions.calc_payout(golos, rshares) payout_gbg = functions.convert_golos_to_gbg(golos, payout, price_source='median') payout_gbg = Amount('{} GBG'.format(payout_gbg)) log.info('raw upvote value: {} or {:.3f} GOLOS'.format( payout_gbg, payout)) author_payout_gp, author_payout_gbg, author_payout_golos = functions.estimate_author_payout( golos, payout_gbg) log.info( 'estimated author payout: {:.3f} GBG, {:.3f} GOLOS, {:.3f} GP'. format(author_payout_gbg, author_payout_golos, author_payout_gp)) author_payout_gbg_repr = author_payout_gbg author_payout_gbg_repr += functions.convert_golos_to_gbg( golos, author_payout_golos, price_source='market') author_payout_gbg_repr += functions.convert_golos_to_gbg( golos, author_payout_gp, price_source='market') log.info( 'estimated author payout in GBG representation: {:.3f} GBG'.format( author_payout_gbg_repr))
def get_bandwidth(steemd_instance, account, type='market'): """ Estimate current account bandwidth and usage ratio :param Steem steemd_instance: Steem() instance to use when accesing a RPC :param str account: account name :param str type: 'market' used for transfer operations, forum - for posting and voting """ a = Account(account, steemd_instance=steemd_instance) global_props = steemd_instance.get_dynamic_global_properties() account_vshares = Amount(a['vesting_shares']).amount log.debug('{:.<30}{:.>30.0f}'.format('account_vshares:', account_vshares)) # get bandwidth info from network if type == 'market': account_average_bandwidth = int(a['average_market_bandwidth']) last_bw_update_time = datetime.strptime( a['last_market_bandwidth_update'], '%Y-%m-%dT%H:%M:%S') elif type == 'forum': account_average_bandwidth = int(a['average_bandwidth']) last_bw_update_time = datetime.strptime(a['last_bandwidth_update'], '%Y-%m-%dT%H:%M:%S') # seconds passed since last bandwidth update elapsed_time = (datetime.utcnow() - last_bw_update_time).total_seconds() max_virtual_bandwidth = int(global_props['max_virtual_bandwidth']) log.debug('{:.<30}{:.>30.0f}'.format('max_virtual_bandwidth:', max_virtual_bandwidth)) log.debug('{:.<30}{:.>30.0f}'.format( 'max_virtual_bandwidth, KB:', max_virtual_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024)) total_vesting_shares = Amount(global_props['total_vesting_shares']).amount log.debug('{:.<30}{:.>30.0f}'.format('total_vesting_shares:', total_vesting_shares)) # calculate bandwidth regeneration if elapsed_time > STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS: new_bandwidth = 0 else: new_bandwidth = ( ((STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - elapsed_time) * account_average_bandwidth) / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS) # example code to estimate whether your new transaction will exceed bandwidth or not #trx_size = 1024*2 # imagine 2 KB trx #trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION #account_average_bandwidth = new_bandwidth + trx_bandwidth account_average_bandwidth = new_bandwidth log.debug('{:.<30}{:.>30.0f}'.format('account_average_bandwidth:', account_average_bandwidth)) # c++ code: # has_bandwidth = (account_vshares * max_virtual_bandwidth) > (account_average_bandwidth * total_vshares); avail = account_vshares * max_virtual_bandwidth used = account_average_bandwidth * total_vesting_shares log.debug('{:.<30}{:.>30.0f}'.format('used:', used)) log.debug('{:.<30}{:.>30.0f}'.format('avail:', avail)) used_ratio = used / avail log.info('{:.<30}{:.>30.2%}'.format('used ratio:', used_ratio)) # account bandwidth is actually a representation of sent bytes, so get these bytes used_kb = account_average_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024 # market ops uses x10 bandwidth if type == 'market': used_kb = used_kb / 10 log.info('{:.<30}{:.>30.2f}'.format('used KB:', used_kb)) # available account bandwidth is a fraction of max_virtual_bandwidth based on his portion of total_vesting_shares avail_kb = account_vshares / total_vesting_shares * max_virtual_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024 if type == 'market': avail_kb = avail_kb / 10 log.info('{:.<30}{:.>30.2f}'.format('avail KB:', avail_kb)) if used < avail: log.debug('has bandwidth') else: log.debug('no bandwidth') return used / avail * 100
def main(): parser = argparse.ArgumentParser( description= 'Scan account history looking for author or curator payouts', epilog='Report bugs to: https://github.com/bitfag/golos-scripts/issues' ) parser.add_argument('-d', '--debug', action='store_true', help='enable debug output'), parser.add_argument('-c', '--config', default='./common.yml', help='specify custom path for config file') parser.add_argument( '-t', '--type', default='author', choices=['author', 'curator'], help='reward type, "author" or "curator", default: author') parser.add_argument('account', help='account to scan') args = parser.parse_args() # create logger if args.debug == True: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") handler.setFormatter(formatter) log.addHandler(handler) # parse config with open(args.config, 'r') as ymlfile: conf = yaml.load(ymlfile) if args.type == 'author': ops = ['author_reward'] elif args.type == 'curator': ops = ['curation_reward'] golos = Steem(nodes=conf['nodes_old'], keys=conf['keys']) cv = Converter(golos) account = Account(args.account, steemd_instance=golos) history = account.rawhistory(only_ops=ops) for item in history: #pprint(item) permlink = item[1]['op'][1]['permlink'] payout_timestamp = datetime.strptime(item[1]['timestamp'], '%Y-%m-%dT%H:%M:%S') sbd_payout = Amount(item[1]['op'][1]['sbd_payout']) steem_payout = Amount(item[1]['op'][1]['steem_payout']) vesting_payout = Amount(item[1]['op'][1]['vesting_payout']) gp = cv.vests_to_sp(vesting_payout.amount) golos_payout = steem_payout.amount + gp gpg_repr = sbd_payout.amount + functions.convert_golos_to_gbg( golos, golos_payout, price_source='market') print('{} {}: {} {} {:.3f} GP, GBG repr: {:.3f}'.format( payout_timestamp, permlink, sbd_payout, steem_payout, gp, gpg_repr))
def main(): parser = argparse.ArgumentParser( description='Find all vesting withdrawals with rates and dates', epilog='Report bugs to: https://github.com/bitfag/golos-scripts/issues' ) parser.add_argument('-d', '--debug', action='store_true', help='enable debug output'), parser.add_argument('-c', '--config', default='./common.yml', help='specify custom path for config file') parser.add_argument( '-m', '--min-mgests', default=100, type=float, help= 'look for account with vesting shares not less than X MGESTS, default is 100' ) args = parser.parse_args() # create logger if args.debug == True: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") handler.setFormatter(formatter) log.addHandler(handler) # parse config with open(args.config, 'r') as ymlfile: conf = yaml.load(ymlfile) golos = Steem(nodes=conf['nodes_old'], keys=conf['keys']) c = golos.get_account_count() log.debug('total accounts: {}'.format(c)) accs = golos.get_all_usernames() start = datetime.utcnow() # get all accounts in one batch all_accounts = golos.get_accounts(accs) # we well get summary info about total withdrawal rate and number of accounts sum_rate = float() count = int() cv = Converter(golos) steem_per_mvests = cv.steem_per_mvests() for a in all_accounts: vshares = Amount(a['vesting_shares']) mgests = vshares.amount / 1000000 rate = Amount(a['vesting_withdraw_rate']) d = datetime.strptime(a['next_vesting_withdrawal'], '%Y-%m-%dT%H:%M:%S') if mgests > args.min_mgests and rate.amount > 1000: # We use own calculation instead of cv.vests_to_sp() to speed up execution # avoiding API call on each interation rate_gp = rate.amount / 1e6 * steem_per_mvests gp = vshares.amount / 1e6 * steem_per_mvests sum_rate += rate_gp count += 1 print('{:<16} {:<18} {:>6.0f} {:>8.0f}'.format( a['name'], d.strftime('%Y-%m-%d %H:%M'), rate_gp, gp)) # non-pretty format # log.info('{} {} {:.0f} / {:.0f}'.format( # a['name'], # d.strftime('%Y-%m-%d %H:%M'), # rate_gp, gp)) log.debug('accounts iteration took {:.2f} seconds'.format( (datetime.utcnow() - start).total_seconds())) log.info( 'numbers of matching accounts on vesting withdrawal: {}'.format(count)) log.info('sum rate: {:.0f}'.format(sum_rate))
async def calc_debt(ctx, usd): price_usd_gold, price_btc_usd, (price_btc_golos, _) = await asyncio.gather( get_price_usd_gold_cbr(), get_price_btc_usd_exchanges(), get_bitshares_center_price(ctx)) print('External price USD/XAU: {:.5f}'.format(price_usd_gold)) print('External price USD/BTC: {:.8f}'.format(price_btc_usd)) print('External price BTC/GOLOS: {:.8f}'.format(price_btc_golos)) # BTC/GOLD price_btc_gold = price_usd_gold / price_btc_usd print('External price BTC/XAU: {:.8f}'.format(price_btc_gold)) props = ctx.helper.get_dynamic_global_properties() sbd_supply = Amount(props['current_sbd_supply']) current_supply = Amount(props['current_supply']) virtual_supply = Amount(props['virtual_supply']) total_reward_fund_steem = Amount(props['total_reward_fund_steem']) median = ctx.helper.converter.sbd_median_price() median_estimated = ctx.helper.estimate_median_price() # libraries/chain/database.cpp # this min_price caps system debt to 10% of GOLOS market capitalisation min_price = 9 * sbd_supply.amount / current_supply.amount print('Minimal possible median price GBG/GOLOS: {:.3f}'.format(min_price)) # #define STEEMIT_100_PERCENT 10000 # this is current GBG percent printed percent_sbd = sbd_supply.amount / median * 100 / virtual_supply.amount print('System GBG debt percent (by blockchain median): {:.2f}'.format( percent_sbd)) percent_sbd = sbd_supply.amount / median_estimated * 100 / virtual_supply.amount print( 'System GBG debt percent (by feed price): {:.2f}'.format(percent_sbd)) if percent_sbd > 10: # estimate supply when debt will return to 10% at current price target_supply = 9 * sbd_supply.amount / median_estimated print('GBG supply: {:,.0f} GBG'.format(sbd_supply.amount)) print('Current supply: {:,.0f} GOLOS'.format(current_supply.amount)) print('Expected supply for reaching 10% debt: {:,.0f} GOLOS'.format( target_supply)) converted_supply = sbd_supply.amount / median print( 'New GOLOS amount on full convertation by blockchain price: {:,.0f} GOLOS' .format(converted_supply)) converted_supply = sbd_supply.amount / median_estimated print( 'New GOLOS amount on full convertation by feed price: {:,.0f} GOLOS' .format(converted_supply)) print( 'Total supply after full convertation by feed price: {:,.0f} GOLOS' .format(current_supply.amount + converted_supply)) # model gradual conversion of all GBG supply step = 10000 price = min_price gbg = sbd_supply.amount golos = current_supply.amount flag = False while gbg > step: gbg -= step golos += step / price price = max(9 * gbg / golos, median_estimated) virtual_supply = golos + gbg / price percent_sbd = gbg / median_estimated * 100 / virtual_supply if percent_sbd < 20 and not flag: print('GBG supply at 20% debt: {:,.0f}'.format(gbg)) print('New GOLOS amount from conversion to 20% debt: {:,.0f}'. format(golos - current_supply.amount)) flag = True new_supply = golos - current_supply.amount print( 'New GOLOS amount after gradual convertation of all GBG with step {}: {:,.0f} GOLOS' .format(step, new_supply)) sbd_print_rate = props['sbd_print_rate'] / 100 gbg_emission_week = (total_reward_fund_steem.amount / 2) * median * sbd_print_rate / 100 gbg_emission_day = gbg_emission_week / 7 print('GBG print rate: {:.2f}'.format(sbd_print_rate)) print('Approximate GBG emission per day: {:.0f}'.format(gbg_emission_day)) print('Conversion-derived price BTC/GBG: {:.8f}'.format(price_btc_golos / median)) if usd: print('Approximate USD/GOLOS price at 2%-debt point: {:.3f}'.format( price_usd_gold * min_price * 5)) print('Approximate USD/GOLOS price at 5%-debt point: {:.3f}'.format( price_usd_gold * min_price * 2)) print('Approximate USD/GOLOS price at 10%-debt point: {:.3f}'.format( price_usd_gold * min_price)) else: print('Approximate BTC/GOLOS price at 2%-debt point: {:.8f}'.format( price_btc_gold * min_price * 5)) print('Approximate BTC/GOLOS price at 5%-debt point: {:.8f}'.format( price_btc_gold * min_price * 2)) print('Approximate BTC/GOLOS price at 10%-debt point: {:.8f}'.format( price_btc_gold * min_price))