Part 16: How To Analyse A User's Vote History In A Specific Time Period Using Steem-Python

in #utopian-io6 years ago (edited)

steem-python.png

This tutorial is part of a series where we explain different aspects of programming with steem-python. Links to the other tutorials can be found in the curriculum section below. In part 9 of this series we learned how to calculate the total rewards of a post and in this tutorial we will learn how to estimate the curation rewards of a post!


What will I learn

  • How to sort an account's history
  • How to only analyse the last N days
  • How to use a namedtuple
  • How to format output nicely

Requirements

  • Python3.6
  • steem-python

Difficulty

  • Basic

Tutorial

If you find it easier to follow along this way you can get the entire code for this tutorial from here, where I have split everything up into the relevant sections.

Filtering an account's history

Instead of streaming and filtering the blockchain we can also do this for an account's history as we did in part 12. To do this we used the function history_reverse(), which streams an account's history in reverse chronological order. Filtering this is done the same was as filtering the blockchain, so for example if we want to filter an account's history and see what posts that account voted on, we can do the following

account = "utopian-io"
for vote in Account(account).history_reverse(filter_by="vote"):
    if vote["voter"] == account:
        # DO SOMETHNIG

Limiting history to a certain period

Just like when we analysed the rewards, we don't want to go through an account's entire history, so we should limit it to a certain time period. To do this we can use datetime's timedelta() function. Using timedelta() we can easily define a time period, so for example five days would be timedelta(days=5) and five weeks would be timedelta(weeks=5). For now let's limit it to one hour. So to get all posts that the specified account voted on in the last day we can do the following

import datetime
from dateutil.parser import parse

current_time = datetime.datetime.now()
time_period  = datetime.timedelta(hours=1)

for vote in Account(account).history_reverse(filter_by="vote"):
    if vote["voter"] == account:
        time_voted = parse(vote["timestamp"])
        if current_time - time_voted < time_period:
            # DO SOMETHING
        else:
            break

In part 12 we could just use the time_elapsed() function on a Post function to see if the time period had already passed, but this time we use dateutil.parser's parse function to easily get the time a vote was made.

Creating a namedtuple

Now we can limit the account's voting history to a certain period we can decide what to do with it. For example, you could want to print the post's author, the title of the post and its pending payout. A nice way to do this is to create a User object with all this information so we can easily print this afterwards. To do this we need to define what our User object will look like before we do this, like so

from collections import namedtuple
User = namedtuple("User", ["name", "post", "pending"])

Using this we can then create a list of these objects as follows

users = []
for vote in Account(account).history_reverse(filter_by="vote"):
    if vote["voter"] == account:
        time_voted = parse(vote["timestamp"])
        if current_time - time_voted < time_period:
            
            permlink = "@{}/{}".format(vote["author"], vote["permlink"])
            post = Post(permlink)
            
            if post.is_main_post():
                # Create list of User objects
                user = User(post["author"], post["title"],
                    Amount(post["pending_payout_value"]).amount)
                users.append(user)
        else:
            break

Printing everything nicely

Once we have our list of User objects we can print them out in whatever format we want. For example, I want to print everything like this: <author> - <title> - $<pending payout>, where the title is truncated, and print the total pending payout at the end. I also want everything to be spaced nicely, so everything lines up and it's easier to read. To do this I can use the following code

total_pending = sum([user.pending for user in users])
width = 40
for user in users:
    print("{0:16} - {1:43} - ${2}".format(
        user.name, user.post[:width] + (user.post[width:] and "..."),
        user.pending))

print("Total pending payout: ${}".format(total_pending))

where we specify the index of the variable and the width with {<index>:<width>}. We also truncate the title by slicing it. At the time of writing this tutorial this had the following output

aldianrony1     - My idea. Add the function of who has vis... - $7.42
arie.steem      - Gpredict - Make It New Module & Setting ... - $46.869
darewealth      - Adding incognito Tab to Lucid Browser       - $7.41
redart          - Geogebra Dynamic Mathematics Turkish Vid... - $43.307
fabiyamada      - STEEM PLUS - New view styles for the fee... - $155.179
buckydurddle    - VCV Rack -  JW Module Full Scope            - $51.834
miniature-tiger - Analysis of @steemit Account Powerdown      - $112.097
raycoms         - Minecolonies & The Quality of Playing - ... - $238.65
tobias-g        - Steemgigs spotlight (User recognition ar... - $27.083
justyy          - Adding `Stats` Class to PHP Client of Ut... - $154.088
netuoso         - [Steem Examples] Steem Price Rate Histor... - $275.51
tensor          - Intro to Kotlin (Basic Types, Type Infer... - $58.412

Congratulations, you've now learned how to filter an account's history using steem-python, how to limit this to a certain time period, how to create an object using namedtuple and format your output nicely!

Curriculum

Set up:
Filtering
Voting
Posting
Constructing
Rewards
Transfers
Account Analysis

The code for this tutorial can be found on GitHub!

This tutorial was written by @amosbastian in conjunction with @juliank.



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

thanks for the tutorial, with this tutorial I can know how many votes that I get, hopefully this tutorial is not hard to do

Hey @steempytutorials I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Hello out there!

Not sure if anyone will read this at all but if possible I'd love to get an answer...I'm trying to run this example:

But unfortunatelly, I get this error with both Python 2.7 and 3.6:

Is it a known issue or something wrong on my side?

I created a completely clean virtual environment, installed steem-python and tried running it and it worked fine for me

You can try upgrading your steem-python since maybe you have an older version. If that doesn't work you can also contact me on Discord at Amos#4622 and I can help you out!

hmmm..thanks for ur work, I'll take a closer look on that and will let you know!

Which python version r u using?

Python 3.6.5 :: Anaconda custom (64-bit).

Coin Marketplace

STEEM 0.17
TRX 0.13
JST 0.030
BTC 56519.24
ETH 2991.31
USDT 1.00
SBD 2.16