This tutorial is part of a series where different aspects of programming with steem-python
are explained. Links to the other tutorials can be found in the curriculum section below. This part will discuss how a bidbot
can be made.
Repository
https://github.com/steemit/steem-python
What will I learn
- How does a bidbot work?
- How to process incoming bids
- Verify incorrect bids
- Refund incorrect bids
- Monitor voting power
- Perform votes
Requirements
- Python3.6
steem-python
Difficulty
- intermediate
Tutorial
Setup
Download the files from Github. There 2 are files bidbot.py
which contains the main code and classes.py
which contains the classes Bid
and Queue
. bidbot.py
takes two arguments which are the starting_block
to start scanning the blockchain
from and account
on which the bidbot will be run.
Run scripts as following:
> python bidbot.py 23822234 steempytutorials
How does a bidbot work?
The idea of a bidbot
is that users can bid
on a the voting power
of the bidbot
account by sending SBD
and a memo
which contains the url
of the post to be upvoted. To maximise the voting power
a voting round ends when voting power reaches 100% and will go down to 98% when another round will start. This 2% drop in voting power equals a 100% vote. This bidbot
will not take into account the profitability of a bid and such this responsibility lies with the users doing the bidding.
How to process incoming bids
Tutorial 23 goes into depth how to retrieve transfers from blocks. This tutorials continues on that code. Two classes will be used in this bot Bid
and Queue
. Every Bid
consists of the user
sending the bid
, the amount
(which is converted to an Amount object
), the memo
and a placeholder for a Post object
.
class Bid():
def __init__(self, user, amount, memo):
self.user = user
self.amount = Amount(amount)
self.memo = memo
self.post = 0
The Queue
object has a dictionary list
that will house all the bids
as a (indentifier, bid_amount)
pair, a variable total_sbd
to keep track of the total value of all the bids
. The Steem
object to interact with Steem and the bot's account
.
class Queue():
def __init__(self, steem, account):
self.list = {}
self.total_sbd = 0
self.steem = steem
self.account = account
Each transaction is checked to be of the transfer
type, if so the operation is processed.
for transaction in block['transactions']:
self.process_transaction(transaction)
def process_transaction(self, transaction):
if transaction['operations'][0][0] == 'transfer':
operation = transaction['operations'][0][1]
self.process_transfer(operation)
Only transfers going to
the bidbot
account are of importance. For each transfer
which to
equals the bidbot account
a Bid object
is created and passed on to the queue
.
def process_transfer(self, operation):
user = operation['from']
amount = operation['amount']
memo = operation['memo']
to = operation['to']
if to == self.account:
bid = classes.Bid(user, amount, memo)
self.queue.add_bid(bid)
The bid
is verified to be correct, if not it will be returned to the user
. When a bid
has passed quality control it is added to the list
dictionary. The identifier
is used as the unique key while the bidding amount
is used as the value. The total_sbd
is updated, and will be used to determine the percentage of each bid
when the round ends.
def add_bid(self, bid):
print(f'\nProcessing bid from {bid.user} for {bid.amount}')
if self.verify_bid(bid) == 1:
print('Added bid to list\n')
self.list[bid.post['identifier']] = bid.amount['amount']
self.total_sbd += bid.amount['amount']
Verify incorrect bids
There are several ways in which a user can make an incorrect bid. The bot will reject the following 3 bids: a post which is already bid on, an url
which is not correct and the incorrect asset
used to bid, only SBD
is accepted.
def verify_bid(self, bid):
valid = 1
while valid == 1:
try:
bid.post = Post(bid.memo)
if bid.post['identifier'] in self.list:
self.refund(bid, 'Already in list')
valid = 0
except Exception as e:
self.refund(bid, 'Invalid url')
valid = 0
print(repr(e))
if bid.amount['asset'] != 'SBD':
self.refund(bid, 'Invalid asset')
valid = 0
break
return valid
Verifying the url
is done by creating a Post
object. If this fails the url
is not valid. When this passes the post['identifier']
is taken and checked against the list
of bids. The asset
used in the bid
is verified by using the Amount
class: bid.amount['asset']
. When an incorrect bid is detected a refund is issued.
Refund incorrect bids
When an invalid bid
is detected the bid
is returned to the user
with a memo
containing the reason for the refund.
def refund(self, bid, memo):
print('Refund: ', memo)
self.steem.transfer(to=bid.user,
amount=bid.amount['amount'],
asset=bid.amount['asset'],
memo=memo,
account=self.account)
Monitor voting power
To evaluate the current voting power of the account the altered function voting_power()
is used, the function is located in account.py
from steem-Python
def voting_power(self):
diff_in_seconds = (datetime.datetime.utcnow() - parse_time(
self["last_vote_time"])).seconds
regenerated_vp = diff_in_seconds * 10000 / 86400 / 5
total_vp = (self["voting_power"] + regenerated_vp) / 100
if total_vp>100:
return 100
else:
return "%.2f" % total_vp
source
To optimise calls to this function the block time
is used to determine when a minute has passed. The block time
is found under block['timestamp']
and can be processed with datetime.strptime()
. Each minute the voting_power
is checked to be 100, if so a voting round will be started.
def process_timestamp(self, block):
timestamp = block['timestamp']
datetime_object = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S')
if datetime_object.second == 0:
account = Account(self.account)
print(f'\nVoting power: {account.voting_power()}%\n')
if account.voting_power() == 100:
self.queue.run_voting_round()
Perform votes
List
is a dictionary containing sets of (identifier, bid amount)
. Together with total_sbd
the percentage share of each bid can be calculated as follows: bid_amount/total_sbd*100
def run_voting_round(self):
print('Starting upvoting round')
for post in self.list:
upvote_pct = self.list[post]/self.total_sbd*100
self.steem.vote(post, upvote_pct, account=self.account)
print(f'Upvoted {post} {upvote_pct:.2f}%')
self.reset()
print('Finished upvoting round')
Votes are casted with steem.vote()
which requires the identifier
, upvote_percentage
and upvote_account
.
Running the script
Running the script will scan any blocks for incoming transfers to the specified account. In order to test the bot 5 transfers were made to @steempyturials. After which the the blockchain was scanned starting from the block of the first transfer. In these 5 transfers some bids were made incorrect on purpose.
Running the script then led to the following output:
python bidbot.py 23822234 steempytutorials
Connected to: https://rpc.steemviz.com
Block: 23822234
Processing bid from juliank for 0.010 SBD
Added bid to list
Block: 23822235
Processing bid from juliank for 0.010 SBD
Refund: Already in list
Block: 23822236
Block: 23822237
Processing bid from juliank for 0.030 SBD
Added bid to list
Block: 23822238
Processing bid from juliank for 0.010 STEEM
Refund: Invalid asset
Block: 23822239
Processing bid from juliank for 0.010 SBD
Refund: Invalid url
Block: 23822240
.
.
.
Block: 23822253
Voting power: 100%
Starting upvoting round:
Upvoted juliank/thesmallcityofopatij-201806302000001487 25.00%
Upvoted juliank/outoftitlesforallthewaterfalls-20180629213452777 75.00%
Finished upvoting round
Curriculum
Set up:
- Part 0: How To Install Steem-python, The Official Steem Library For Python
- Part 1: How To Configure The Steempy CLI Wallet And Upvote An Article With Steem-Python
Filtering
- Part 2: How To Stream And Filter The Blockchain Using Steem-Python
- Part 6: How To Automatically Reply To Mentions Using Steem-Python
- Part 23: Part 23: Retrieve And Process Full Blocks From The Steem Blockchain
- Part 24: An In Dept Look At Steem Operation Types Part I
Voting
- Part 3: Creating A Dynamic Autovoter That Runs 24/7
- Part 4: How To Follow A Voting Trail Using Steem-Python
- Part 8: How To Create Your Own Upvote Bot Using Steem-Python
Posting
- Part 5: Post An Article Directly To The Steem Blockchain And Automatically Buy Upvotes From Upvote Bots
- Part 7: How To Schedule Posts And Manually Upvote Posts For A Variable Voting Weight With Steem-Python
Constructing
Rewards
- Part 9: How To Calculate A Post's Total Rewards Using Steem-Python
- Part 12: How To Estimate Curation Rewards Using Steem-Python
- Part 14: How To Estimate All Rewards In Last N Days Using Steem-Python
Transfers
- Part 11: How To Build A List Of Transfers And Broadcast These In One Transaction With Steem-Python
- Part 13: Upvote Posts In Batches Based On Current Voting Power With Steem-Python
Account Analysis
- Part 15: How To Check If An Account Is Following Back And Retrieve Mutual Followers/Following Between Two Accounts
- Part 16: How To Analyse A User's Vote History In A Specific Time Period Using Steem-Python
- Part 18: How To Analyse An Account's Resteemers Using Steem-Python
The code for this tutorial can be found on GitHub!
This tutorial was written by @juliank.
So awesome to see this! Thank you
Thank you for your contribution.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Hey @steempytutorials
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!
It's very interesting
im new to python but want to make a bid bot but really confused. how can i run the scripts exactly. can i just have the full code and change some things