The Complete Guide On How To Calculate STEEM Using Steem-Python

in #utopian-io6 years ago (edited)

One of the things that frustrated me while I was coding SteemAX

was finding a straight forward answer to how One goes about calculating a single upvote from a Steemit.com account. Steem-python, nor any other Steem utility that I know of calculates this or provides this functionality for you. One must figure it out on their own. Luckily I had many pioneers ahead of me, so the information is out there. However I thought it would be beneficial to put everything into one tutorial.

Most of the tutorials I found were either too general, too ambiguous, didn't include any code, didn't include any math, or were out of date and only applied to an earlier hardfork. In the end I used quite a few resources to determine exactly how to calculate STEEM, STEEM POWER, or the Rewards Pool (STEEM Backed Dollars is something I'll discuss in a later tutorial) and to do it for an upvote, for a payout, or whatever; all using the Steem-Python library. Hopefully I save someone out there from the same headache I went through. Everything I demonstrate here is good for hardfork 19.

You can download and install the Steem-Python library by following the instructions that are available at the Steem-Python GitHub repository.

You Will Learn in This Tutorial:

  • How to use the Steem-Python library to calculate STEEM, STEEM POWER, and the Reward Pool in a definitive way that lets you use these values at will in your own Steem-based apps. This tutorial will help synthesize and consolidate a lot of information that is already available into one, easy-to-access source.

  • A deeper undersanding of how the Reward Pool works, even beyond what may have already been published.

To Follow the Examples in This Tutorial:

Advanced Learning

I assume that if you're reading this tutorial you already have a firm understanding of:

I include more links to tutorials at the end to help fill in any missing knowledge.

Note: The code I present in this tutorial is written for clarity of reading and not necessarily optimization. Breaking this code into methods and classes would be a much better approach.



learn_reward_pool.jpg

A Deeper Understanding of the Reward Pool

To find the current reward pool total using Steem-Python is relatively simple.

#!/usr/bin/python
from steem import Steem
s = Steem()

reward_fund = s.get_reward_fund()
reward_balance = reward_fund["reward_balance"]
print ("Reward balance: " + reward_balance)

Running this prints:

Reward balance: 729923.05 STEEM

Who owns this STEEM and where is it? One answer I found to this question came from @timcliff's comment to this article:

The rewards pool does not actually contain STEEM coins. It is a virtual pool representing coins that haven't been created yet.

Is this true? For a deeper understanding I personally needed to know how all of this started out. A sort of...

History of the Steemit Reward Pool

From the Steemit Whitepaper I read that

The Steem network started with a currency supply of 0 and allocated STEEM via proof of work at a rate of approximately 40 STEEM per minute to miners, with an additional 40 STEEM per minute being created to seed the content and curation reward pools (for a total of 80 STEEM per minute).

According to the whitepaper the reward pool is indeed made of STEEM tokens, but as @timcliff was saying these are essentially "virtual" as they cannot be traded. The STEEM that goes into the Reward Pool is created by Witnesses processing the blocks on the Steemit blockchain. For each block that is processed a certain amount of STEEM is added to the Reward Pool.

The exact amount of STEEM generated is outlined in the Steemit Whitepaper:

Curation rewards: 1 STEEM per block or 3.875% per year, whichever is greater

Content Creation rewards: 1 STEEM per block or 3.875% per year, whichever is greater

Block production rewards: 1 STEEM per block or 0.750% per year, whichever is greater

POW inclusion rewards before block 864,000: 1 STEEM per block (awarded as 21 STEEM per round)

POW inclusion rewards after block 864,000: 0.0476 STEEM per block (awarded as 1 STEEM per round) or 0.750% per year, whichever is greater.

Liquidity rewards: 1 STEEM per block (awarded as 1200 STEEM per hour) or 0.750% per year, whichever is greater

Honestly, these explanations are a bit vague to me in the sense that I'm still looking for a better understanding of what is meant by "per block". Is there a "curation block", a "content block", etc.? Never-the-less, we can see that it is STEEM that is produced and it is STEEM that goes into the Reward Pool. Also make note that as of hardfork 16, according to the Whitepaper:

Steem began creating new tokens at a yearly inflation rate of 9.5%. The inflation rate decreases at a rate of 0.01% every 250,000 blocks, or about 0.5% per year. The inflation will continue decreasing at this pace until the overall inflation rate reaches 0.95%. This will take about 20.5 years from the time hard fork 16 went into effect.

75% of the new tokens that are generated go to fund the reward pool, which is split between authors and curators. 15% of the new tokens are awarded to holders of SP. The remaining 10% pays for the witnesses to power the blockchain.**

Recent Claims

OK, so the Reward Balance was at 729923.05 STEEM when we looked at it last. But how much of that has been claimed? Minute by minute STEEM is entering the Reward Pool by the production of blocks made by Witness nodes, and STEEM is leaving the Reward Pool each time a Steemian claims their rewards. To see the total amount of recent claims:

#!/usr/bin/python
from steem import Steem
s = Steem()

reward_fund = s.get_reward_fund()
recent_claims = reward_fund["recent_claims"]
print ("Recent Claims: " + recent_claims)

Running this prints:

Recent Claims: 455854824824584246

Since reward claims are distributed in all 3 denominations (STEEM, STEEM POWER and STEEM Backed Dollars) I assume this total is being displayed in VESTS, and not STEEM (more on VESTS below). Also, that's a very big number (4 quadrillion) for it to be STEEM. One thing I would like to know is how recent this is; 24 hours? Seems unlikely. What would make more sense is if this is the total number of claims ever made.

Here's why

According to several sources, especially the tutorial How To Calculate A Post's Total Rewards Using Steem-Python by @steempytutorials we must divide the Reward Balance (729923.05 STEEM) by the Recent Claims (455854824824584246) and this will give a new number: Reward Share.

Knowing the value of a single reward share becomes important for calculating the value of a vote or post as explained below.

#!/usr/bin/python
from steem import Steem
from steem.amount import Amount
s = Steem()

reward_fund = s.get_reward_fund()
recent_claims = reward_fund["recent_claims"]
reward_balance = Amount(reward_fund["reward_balance"]).amount

reward_share = reward_balance / float(recent_claims)

print("A Single Reward Share: " + str(reward_share))

Running this prints a very small number as that's 12 zeros to the right of the decimal point:

A Single Reward Share: 1.6008643289850157e-12

As a side tip, you can quickly remove the text "STEEM" from reward_balance and convert it from a string to an integer using the Amount module from Steem-Python.

Doing the math this way makes more sense after reading the intro in the Steemit Whitepaper:

The most important principle is that everyone who contributes to a venture should receive pro-rata ownership, payment or debt from the venture. This principle is the same principle that is applied to all startups as they allocate shares at founding and during subsequent funding rounds. (Italics mine)

So the Reward Pool is the BIG STEEM PIE IN THE SKY. In other words it represents the total net "worth" of the "company". And the Recent Claims is the number of slices in that pie, or in other words, the number of "shares" owned by "shareholders" in that "company." 1 slice of Reward Pool "Pie" equals 1 Reward Share. I believe One could simply replace "Recent Claims" with "Total Shares". A Reward Share, regardless of its name, is still STEEM, as it was STEEM that we divided. It's the STEEM value of 1 share.

As a side note:

The Reward Pool shrinks when the number of claims on rewards and the number of accounts Powering Down outnumber/outweigh the number of accounts Powering Up and the number of posts and votes made by influential accounts. The shrinking of the Reward Pool is akin to a company over spending it's way to bankruptcy. The most effective thing any Steemian could do to prevent the shrinking of the Reward Pool is to invest into STEEM POWER and use that power to upvote as often as possible. The more one upvotes and posts the more blocks that are processed and therefore the more STEEM is allocated to the Reward Pool. How much STEEM is allocated depends on the total amount of STEEM POWER held by all Steemians.

STEEM vs. VESTS

We already know that 1 STEEM = 1 STEEM POWER, and that STEEM POWER is simply STEEM that's been "invested". So to work with the Steem-Python code STEEM POWER is STEEM converted into VESTS. In his tutorial, Understanding Vests and the Steem Power Illusion by @yabapmatt, he writes:

The Steem blockchain has two units of account - STEEM and VESTS... VESTS ... can be thought of as shares of ownership of the Steem blockchain. VESTS are also a token like STEEM, with balances maintained on the blockchain, but they cannot be transferred between accounts.

However, the search for a true understanding of what a VEST is has led me to some interesting finds.

Interestingly enough the Steemit Whitepaper does not use the term VESTS.

Not even once. The only official source for the meaning of this term can only be found in the Steem-Python code documentation for the Converter package.

*sp_to_vests(sp)*

Obtain VESTS (not MVESTS!) from SP
Parameters: sp (number) – SP to convert

*steem_per_mvests()*

Obtain STEEM/MVESTS ratio

*vests_to_sp(vests)*

Obtain SP from VESTS (not MVESTS!)
Parameters: vests (number) – Vests to convert to SP

I'm still not entirely sure if a VEST is a true cryptocurrency unit on the blockchain, of it's just an abstract number that represents STEEM on the blockchain, in a form that is "frozen" or "invested" and can be used to determine influence and voting values within the Steem-Python code. @Yabapmatt believes that a VEST is its own crypto unit, but without proper documentation, it would require someone with a deeper understanding of cryptography and the Steem blockchain code in general to answer this question. Anybody? Anybody?

However:


One-Does-Not-Simply-VESTS.jpg

One simply needs to know that a VEST is the unit of STEEM POWER used in Steem-Python calculations.

To obtain STEEM POWER from VESTS simply use the Steem-Python Converter module. Notice that to get the true STEEM POWER of an account we must first get the total VESTS, then subtract the amount that has been delegated to others, and then add the amount others have delegated to the account.

#!/usr/bin/python
from steem import Steem
from steem.converter import Converter
from steem.amount import Amount
s = Steem()
c = Converter()

accountname = "learnelectronics"

account = s.get_account(accountname)
vests = Amount(account['vesting_shares']).amount
delegated_vests = Amount(account['delegated_vesting_shares']).amount
received_vests = Amount(account['received_vesting_shares']).amount

current_vests = float(vests) - float(delegated_vests) + float(received_vests)

steem_power = c.vests_to_sp(current_vests)

print ("@" + accountname + " has " + str(steem_power) + " STEEM POWER")

Running this prints:

@learnelectronics has 15.018912545356736 STEEM POWER

Not much right now, I know, but I'm working on it. :)

Getting the Price of STEEM

This is probably the easiest thing you can do with the Steem-Python library.

#!/usr/bin/python
from steem import Steem
from steem.amount import Amount
s = Steem()

price_of_steem = Amount(s.get_current_median_history_price()["base"]).amount
print ("STEEM is currently $" + str(price_of_steem))

Running this prints:

STEEM is currently $3.927

Nice.

Calculating Vote Power

As a Steemian votes their vote power decreases by approximately 2% each vote. It takes 24 hours for 20% of their vote power to return; this is called "vote power regeneration". The Steem-Python code will return the vote power of an account at the time of their last vote. This means that if you want to know the current vote power you must do some timestamp manipulations and date and time functions. Here, I've done them for you.

#!/usr/bin/python
from steem import Steem
from datetime import datetime
s = Steem()

accountname = "learnelectronics"

account = s.get_account(accountname)
vote_power = account['voting_power']
vote_time = account['last_vote_time']

#Convert timestamp to number of seconds since right now
delta = datetime.utcnow() - datetime.strptime(vote_time,'%Y-%m-%dT%H:%M:%S')
time_total = (delta.days * 86400) + delta.seconds

#Calculate voting power since the last vote in the range of 150 to 10000 since
#this is the range needed to supply the sp_to_rshares() method

regenerated_vote_power = time_total * 10000 / 86400 / 5
vpow_scaled = vote_power + regenerated_vote_power

#If more time has passed then is needed to reach 100% then we are just at 100%
if vpow_scaled > 10000:
    vpow_scaled = 10000

#Convert range to normal percentage for printing to screen
vpow = vpow_scaled / 100
vpow = round(vpow, 2)

print ("@" + accountname + " has a current vote power of " + str(vpow) + "%")

Running this prints:

@learnelectronics has a current vote power of 95.77%

Visit Learn Python Series (#21) - Handling Dates and Time Part 1 for more info on Python the datetime module.

The interesting bit of math here is:

regenerated_vote_power = time_total * 10000 / 86400 / 5

That's the time since the last vote multiplied by 10000 (since that's the range we need to use the sp_to_rshares() method, which is explained below), divided by the number of seconds in a day, divided by the number of days it takes to fully regenerate.

Vote Weight

An upvote's value is calculated using both STEEM POWER as well as the weight of the vote at the time it is given. Vote weight is set by a slider that becomes available once an account has reached 1 million VESTS, however it's my understanding that vote weight can be set programmatically for any Steemit account using the Steem-Python code regardless of how much STEEM POWER the account may have. When entering Vote Weight into the sp_to_rshares() method it must be in a range of 150 to 10000, so we must convert the percentage into this range. Although in this example below the weight variable is given a set value, the operations are necessary for unknown values that might be passed to the sp_to_rshares() method.

#voting weight of 50% is converted and kept within range
weight = 50
vote_weight = int(weight) * 100
if vote_weight < 150:
    vote_weight = 150
elif vote_weight > 10000:
    vote_weight = 10000

The sp_to_rshares() Method

We can now finally get to where we wanted to go at the beginning of this tutorial. The sp_to_rshares method takes three arguments, STEEM POWER, Vote Power, and Vote Weight, and returns the number of rshares. I assume the "r" stands for "reward", but this value is not the same as the Reward Share calculated earlier and gets used differently as we'll see here in a minute.

rshares = c.sp_to_rshares(steem_power, vpow_scaled, vote_weight)

Calculate the Value of an Upvote

Now we can calculate the current value of an account's upvote. Notice here that rshares represents how many slices of the Reward Pie the account can generate given how much STEEM POWER it has, and the Reward_Share is the size of 1 slice. We multiply that by the current price of Steem and this gives the current vote value. It's hard to determine the denomination of this value. It's definitely not STEEM, or STEEM POWER, or STEEM Backed Dollars, simply because of the way payouts work. I prefer to call them STEEM TOKEN UNITS as described by @dragosroua in his post Steem.Supply Update: Rewards Algorithm Rewrite, Major Cleanup, Version Bump.

vote_value = rshares * reward_share * price_of_steem

Calculate the Value of a Post

We can see that the math to calculate a post's rewards is very similar to a vote value. We must simply add together all the rshares given to the post by way of upvotes, then perform the same calculation to get a value in STEEM TOKEN UNITS.

c = s.get_content("learnelectronics", "resistors")
for v in c['active_votes']:
    total_rshares += int(v['rshares'])

post_value = total_rshares * reward_share * price_of_steem
post_value = round(post_value, 4)
print ("The post @learnelectronics/resistors has received $" + str(post_value))

Putting It All Together

I added a little treat at the end. By iterating through the list of voters using the get_content() method we can get the rshares value for each vote given to a post thus allowing us to see exactly how much each voter has contributed to the total value of the post. This final program outputs a nice report using all the methods covered in this tutorial. Enjoy!

#!/usr/bin/python
from steem import Steem
from steem.amount import Amount
from steem.converter import Converter
from datetime import datetime
s = Steem()
c = Converter()

accountname = "learnelectronics"
post_indentifier = "@learnelectronics/resistors"
weight = 100

account = s.get_account(accountname)

#Calculate Reward Share from Reward Pool
reward_fund = s.get_reward_fund()
recent_claims = reward_fund["recent_claims"]
reward_balance = Amount(reward_fund["reward_balance"]).amount
reward_share = reward_balance / float(recent_claims)

#Get the price of STEEM
price_of_steem = Amount(s.get_current_median_history_price()["base"]).amount

#Calculate current Voting Power
vote_power = account['voting_power']
vote_time = account['last_vote_time']
delta = datetime.utcnow() - datetime.strptime(vote_time,'%Y-%m-%dT%H:%M:%S')
time_total = (delta.days * 86400) + delta.seconds
regenerated_vote_power = time_total * 10000 / 86400 / 5
vpow_scaled = vote_power + regenerated_vote_power
if vpow_scaled > 10000:
    vpow_scaled = 10000
vpow = vpow_scaled / 100
vpow = round(vpow, 2)

#Calculate Steem Power
vests = Amount(account['vesting_shares']).amount
delegated_vests = Amount(account['delegated_vesting_shares']).amount
received_vests = Amount(account['received_vesting_shares']).amount
current_vests = float(vests) - float(delegated_vests) + float(received_vests)
steem_power = c.vests_to_sp(current_vests)

#Set Vote Weight to the correct range
vote_weight = int(weight) * 100
if vote_weight < 150:
    vote_weight = 150
if vote_weight > 10000:
    vote_weight = 10000

#Calculate rshares using the rshares method
rshares = c.sp_to_rshares(steem_power, vpow_scaled, vote_weight)

#Calculate the value of an upvote
vote_value = rshares * reward_share * price_of_steem

#Calculate the value of a post
p = s.get_content("learnelectronics", "resistors")
total_rshares = 0
list_of_voters = []
for v in p['active_votes']:
    total_rshares += int(v['rshares'])
    this_upvote = int(v['rshares']) * reward_share * price_of_steem
    this_upvote = round(this_upvote, 4)
    list_of_voters.append(v['voter'] + " gave a vote of $" + str(this_upvote))
post_value = total_rshares * reward_share * price_of_steem
post_value = round(post_value, 4)

#Print out a report
print ("\n\n\n____ The Reward Pool ____\n")
print ("    Reward Balance: " + str(reward_balance) + " STEEM")
print ("    Recent Claims: " + str(recent_claims))
print ("    1 Reward Share (Slice): " + str(reward_share))
print ("    Price of STEEM: $" + str(price_of_steem))
print ("\n____ @" + accountname + " _____\n")
print ("    STEEM POWER: " + str(steem_power) + " STEEM")
print ("    Current Vote Power: " + str(vpow) + "%")
print ("    Current Upvote Value: $" + str(vote_value) + " STEEM TOKEN UNITS")
print ("\n____ " + post_indentifier + " _____\n")
print ("    This post received a total of $" + str(post_value) + " STEEM TOKEN UNITS")
print ("    The following accounts upvoted this post:")
for a in list_of_voters:
    print ("        " + a)
print ("\n\n")

#EOF

print_results.png

Further Reading

References

Written by "@Artopium" Mike

Visit ArtoLabs on GitHub
Visit: https://mike.artopium.com
Contact: https://discord.gg/97GKVFC

Sort:  

The submission is reviewed and approved, thank you for contributions to open source community.

Suggestions:

  • Utopian has some templates for providing information in every post on each category. Even if you made a good contribution, you should use this tutorials template in your future contributions. You can edit the template as you wish, as long as you provide required information.

Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @learnelectronics

Thanks for contributing via Utopian.
We're already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.20
TRX 0.14
JST 0.030
BTC 67808.66
ETH 3248.00
USDT 1.00
SBD 2.67