My First Steemit Bot

pwangdu(57)
Published in
#bots
Words
94
Reading
1 min
9y
Listen to this post
~1 min

So I started writing out my first Steemit Bot. It is as simple as it can get. Wakes up every 65 minutes and looks at best bet from hot posts api.steemjs.com/getState?path=/hot.

BOT

Getting Hot Posts

public static final String API_URI = "https://api.steemjs.com/getState?path=/hot";

    @Test
    public void testLoadHotPosts() throws IOException {
        String hotPosts = Utils.getHotPosts(API_URI);
        ObjectMapper objectMapper = new ObjectMapper();
        HotPostsReply hotPostsReply = objectMapper.readValue(hotPosts.toString(), HotPostsReply.class);
        assertNotNull(hotPostsReply);
        assertNotNull(hotPostsReply.getCurrentRoute());
        assertNotNull(hotPostsReply.getProps());
        assertNotNull(hotPostsReply.getProps().getCurrentSupply());
        assertNotNull(hotPostsReply.getProps().getMaxVirtualBandwidth());
        assertNotNull(hotPostsReply.getContent());
        assertFalse(hotPostsReply.getContent().isEmpty());
    }

The Configuration

    @Value("${account}")
    private String account;
    @Value("${posting.key}")
    private String postingKey;
    @Value("${active.key}")
    private String activeKey;
    @Value("${phrases}")
    private String phrases;
    @Value("${comment.tag}")
    private String commentTag;
    @Value("${hour.range}")
    private static int hourRange;
    @Value("${hotpost.url}")
    private String hotPostsURL;

Check if we have already voted

   /**
     * Checks if already voted this post
     *
     * @param steemJ
     * @param author
     * @param permlink
     * @return
     * @throws SteemResponseException
     * @throws SteemCommunicationException
     */
    private boolean alreadyVoted(SteemJ steemJ, AccountName author, Permlink permlink) throws SteemResponseException, SteemCommunicationException {
        return steemJ.getActiveVotes(author, permlink)
                .stream()
                .anyMatch(a -> a.getVoter().getName().equals(account));
    }

Check if bandwidth is available

   /**
     * Calculate the bandwidth ratio
     * A ratio greater than 1 means the account has bandwidth
     *
     * @param steemJ
     * @param accountName
     * @return
     * @throws SteemCommunicationException
     * @throws SteemResponseException
     */
    public static boolean isBandwidthAvailable(SteemJ steemJ, String accountName) throws Exception {
        final ExtendedAccount theAccount = getAccountInfo(steemJ, accountName);
        final BigDecimal account_vesting_shares = BigDecimal.valueOf(theAccount.getVestingShares().getAmount() + theAccount.getReceivedVestingShares().getAmount());
        final BigDecimal account_average_bandwidth = BigDecimal.valueOf(theAccount.getAverageBandwidth());
        final BigDecimal total_vesting_shares = BigDecimal.valueOf(steemJ.getDynamicGlobalProperties().getTotalVestingShares().getAmount());
        final BigDecimal market_average_bandwidth = new BigDecimal(steemJ.getDynamicGlobalProperties().getMaxVirtualBandwidth());
        return account_vesting_shares.multiply(market_average_bandwidth).subtract(account_average_bandwidth.multiply(total_vesting_shares)).doubleValue() > 0;
    }

Algorithm (As simple as it is... I will try to put in some machine learning so as to maximize the rewards going forward as I make a leap in AI)

   /**
     * A scheduled method to wake up the bot every 65 minutes
     *
     * @throws Exception
     */
    @Scheduled(fixedDelay = 1000 * 60 * 65)
    public void commentAndVote() throws Exception {
        SteemJ steemJ = getSteemJInstance(account, postingKey, activeKey);
        words = Arrays.asList(phrases.split(","));
        final HotPostsReply hotPostsReply = objectMapper.readValue(getHotPosts("https://api.steemjs.com/getState?path=/hot").toString(), HotPostsReply.class);
        hotPostsReply.getContent()
                .values()
                .stream()
                .sorted(getComparatorByTime())
                .filter(c -> postsLessThanThirtyMinutes(c))
                .sorted((c1, c2) -> maximumSharesByVotesRatio(c1, c2))
                .findFirst()
                .ifPresent(post -> commentAndVote(steemJ, post));
    }

    /**
     * Gets the difference between net shares/net vots for two posts. Helpful for sorting
     *
     * @param c1
     * @param c2
     * @return
     */
    private int maximumSharesByVotesRatio(ContentEntry c1, ContentEntry c2) {
        return Double.valueOf((double) (c1.getNetRshares() / c1.getNetVotes() - c2.getNetRshares() / c2.getNetVotes()) / 1000d).intValue();
    }

    /**
     * Checks if the post was created within last 30 minutes
     *
     * @param c
     * @return
     */
    private boolean postsLessThanThirtyMinutes(ContentEntry c) {
        return (new java.util.Date().getTime() - c.getCreated().getDateTimeAsDate().getTime()) / 60000 < 30;
    }

    /**
     * Time comparison for ordering posts
     *
     * @return
     */
    private Comparator<ContentEntry> getComparatorByTime() {
        return (c1, c2) -> c2.getCreated().getDateTimeAsDate().compareTo(c1.getCreated().getDateTimeAsDate());
    }

    /**
     * Vote & Comment Scheduling.
     * We want to vote exactly after 30 mins have elapsed after the post was created
     *
     * @param steemJ
     * @param post
     */
    private void commentAndVote(SteemJ steemJ, ContentEntry post) {
        try {
            if (isBandwidthAvailable(steemJ, account) && !alreadyVoted(steemJ, post.getAuthor(), post.getPermlink())) {
                final long delay = 30 - (new Date().getTime() - post.getCreated().getDateTimeAsDate().getTime()) / 60000;
                service.schedule(() -> action(steemJ, post), delay, TimeUnit.MINUTES);
                System.out.println(((new java.util.Date().getTime() - post.getCreated().getDateTimeAsDate().getTime()) / 60000) + ":" + delay);
            } else {
                logger.log(Level.ALL, "Bandwidth Not Available or already voted in similar way...");
            }
        } catch (Throwable e) {
            logger.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    /**
     * Actual voting and commenting happens here
     *
     * @param steemJ
     * @param post
     */
    private void action(SteemJ steemJ, ContentEntry post) {
        try {
            steemJ.vote(post.getAuthor(), post.getPermlink(), (short) 100);
            steemJ.createComment(post.getAuthor(), post.getPermlink(), words.get(randInt(0, words.size() - 1)) + "!", new String[]{commentTag});
        } catch (Throwable e) {
            logger.log(Level.SEVERE, e.getMessage(), e);
        }
    }

Thanks to dez1337@dez1337 for developing SteemJ. Very helpful library indeed.

Image Courtesy:

My First Steemit Bot | Ecency