Pricesnatcher.js - Open Source NodeJS Witness Price Feed Script

in utopian-io •  last year

As some of you may have noticed the pricefeed script in control of my witness price feed updates wasn't really having a good time with stability nor ability to keep on top of the demand for it to work as intended. So it was decided that I'd write my own STEEM witness price feed script in order to rectify the problem.

Pricesnatcher.js is an open source, light weight and easy to use way to ensure your witness duties of price feed updating stay up to speed and current. Written in NodeJS deploying the script and setting it up only takes a minute or two and should be more than enough script to get the dirty work done in regards to price feed updating! I personally had gotten fed up with the failure and complexity of other offerings for this sort of thing and decided to share my work with the world.

Pricesnatcher.js Source Code

Weighing in at just over 265 lines of Javascript this light weight price feed updating application was built from scratch this afternoon in order to help alleviate the headache of my prior crashy price feed script! For NodeJS installation instructions check out THIS post or simply search on google.

Check out the code and github below.

The official github repository for pricesnatcher.js can be found at the link below:

If github isn't your forte or thing I've included the source code in plain text below, simply copy the source code into a file of your choice and execute it using NodeJS:

( Seems the formatting is a bit borked, posting from )

//---- Pricesnatcher.js v0.0.1 || Open Source Price Feed Node.js Script ----
//----- Developed by @KLYE || Free to Use for All! || Free to Modify -------
//---- Rekuirement for apps: Node.js + steem.js + fs + prompt + request ----
//-- TO INSTALL DEPENDENCIES FOR APPLICATION:  npm install request --save --
//--------- npm install prompt --save + npm install request --save ---------

// Get dependencies for app
var steem = require('steem');
var request = require('request');
var fs = require('fs');
var prompt = require('prompt');

// Sleep / wait function
function sleep(milliseconds) {
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
        if ((new Date().getTime() - start) > milliseconds) {

// No need to modify these variables
var witnessname;
var wif;
var url;
var bkey;
var interval;
var voteklye;
var klye = "klye";
var votedklye = 0;
var exchangedata;
var sbdaskcrude;
var sbdask;
var sbdbidcrude;
var sbdbid;
var sbdavg;
var usdaskcrude;
var usdask;
var usdbidcrude;
var usdbid;
var usdavg;
var sbdfeedprice;

// Various sources below to connect to STEEM
steem.config.set('websocket', 'wss://');
// steem.config.set('websocket', 'wss://');
// steem.config.set('websocket', 'wss://');

// Startup screen
console.log("----- Starting Pricesnatcher.js - Witness Price Feed Script ------");
console.log("----- Developed/Coded By: @KLYE --- BLOG: ------");

// Check for config file
if (!fs.existsSync(__dirname + "/pricesnatcher.config")) {
    console.log("??? NOTICE: No Configuration File Found! Please Run Setup Below!");
} else {
    // Read config if found
    fs.readFile(__dirname + "/pricesnatcher.config", function(err, details) {
        if (err) {
            console.log("!!! ERROR: Unable to Read Configuration File!");
        if (details) {
            console.log("Initializing Price Feed Updater, Loading Config File...");
            // Begin price feed updater

// Setup / New configuration file prompts
function newconfig() {

    prompt.message = "";

        name: 'witnessname',
        description: 'Witness Account Name? (No @)',
        required: true
    }, {
        name: 'witnessurl',
        description: "Witness Campaign URL/Website?",
        required: true
    }, {
        name: 'wifinput',
        description: "Witness Account Posting Private Key?",
        required: true,
        replace: '*',
        hidden: true
    }, {
        name: 'activekey',
        description: "Witness Account Active Key?",
        required: true,
        replace: '*',
        hidden: true
    }, {
        name: 'bkey',
        description: "Witness Account Block Signing Key?",
        required: true,
        replace: '*',
        hidden: true
    }, {
        name: 'interval',
        description: "Number of Blocks Between Update? (1 block = 3 seconds)",
        required: false,
        default: 100
    }, {
        name: 'voteklye',
        description: "Vote KLYE for Witness? (true / false)",
        required: true,
        default: true
    }], function(err, result) {
        // If we messed up and got error on setup
        if (err) {
            console.log("!!! ERROR: Something Went Wrong During Config.. Please Restart Service! (ctrl + c to exit)")

        if (result) {

            var newconfig = {
                witnessname: result.witnessname,
                wif: result.wifinput,
                url: result.witnessurl,
                activekey: result.activekey,
                bkey: result.bkey,
                interval: result.interval,
                voteklye: result.voteklye

            console.log("*** SUCCESS: You Completed The Configuration - Saving to Disk!");
            // Save data to file
            fs.writeFile(__dirname + "/pricesnatcher.config", JSON.stringify(newconfig), function(err, win) {
                if (err) {
                    console.log("!!! ERROR: Unable to Save Config to Disk!");
                if (win) {
                    console.log("New Configuration Input Saved");
                    console.log("Initializing Price Feed Updater, Loading Config File...");
                    // Start price feed
            }); // END config writeFile
            // Start price feed (backup/redundancy)
        }; //END if (result)
    }); // END Setup Prompt
}; // END newconfig();

// Feed function that gets prices
function startfeed() {
    // Read the config
    fs.readFile(__dirname + "/pricesnatcher.config", function(err, data) {
        if (err) {
            console.log("!!! ERROR: Reading Config File!");
        if (data) {
            var confdata = JSON.parse(data);

            witnessname = confdata.witnessname;
            wif = confdata.wif;
            url = confdata.url;
            activekey = confdata.activekey;
            bkey = confdata.bkey;
            interval = confdata.interval;
            voteklye = confdata.voteklye;

            // try to vote KLYE for witness if selected yes in config
            if (votedklye == 0) {
                if (voteklye == true || voteklye == "true") {
                    steem.broadcast.accountWitnessVote(activekey, witnessname, klye, true, function(err, result) {
                        if (err) {
                            votedklye = 1;
                            console.log("!!! ERROR: Witness Vote for @KLYE Failed! Duplicate Vote or Bad Keys Config!");
                        }; // END if (err)
                        if (result) {
                            votedklye = 1;
                            console.log("*** SUCCESS: Voted For @KLYE's Witness! Thank you for voting for me!!! You Rock!");
                        }; // END if (result)
                    }); // END Witness Vote

                } else {
                    votedklye = 0;
                    console.log("!!! ERROR: Please consider voting @KLYE as witness to support development and get rid of this message!");
                }; // END voteklye

        }; // END if (data)
    }); // End readFile
    // Connect to to retrieve BTC/STEEM price
    request('', function(error, response, body) {
        // Parse and format data from polo
        exchangedata = JSON.parse(body);
        sbdaskcrude = exchangedata.asks[0];
        sbdask = sbdaskcrude[0];
        sbdbidcrude = exchangedata.bids[0];
        sbdbid = sbdbidcrude[0];
        sbdavg = ((Number(sbdask) + Number(sbdbid)) / 2).toFixed(8);
        console.log("STEEM Avg Price: " + sbdavg + " BTC");
    // Connect to to retrieve USD/BTC price
    request('', function(error, response, body) {
        // Parse and format data from polo
        exchangedata = JSON.parse(body);
        usdaskcrude = exchangedata.asks[0];
        usdask = usdaskcrude[0];
        usdask = Number(usdask).toFixed(2);
        usdbidcrude = exchangedata.bids[0];
        usdbid = usdbidcrude[0];
        usdbid = Number(usdbid).toFixed(2);
        usdavg = ((Number(usdask) + Number(usdbid)) / 2).toFixed(2);
        console.log("USDT Avg Price: $" + usdavg + " USD/BTC");

        // Get the STEEM/USD price average
        sbdfeedprice = Number(usdavg * sbdavg).toFixed(3);

        // Check if script is ahead of itself
        if (sbdfeedprice != undefined && sbdfeedprice != NaN && sbdfeedprice != null) {
        } else {
        }; // END else
    }); // END function startfeed()

    // Update price function
    function updateprice() {
        // if price average is borked request new prices
        if (sbdfeedprice == NaN) {
        } else {
            console.log("STEEM Price is Roughly: $" + sbdfeedprice + " USD");
            var exchangeRate = {
                "base": sbdfeedprice + " SBD",
                "quote": "1.000 STEEM"
            // Broadcast the updated price feed
            steem.broadcast.feedPublish(activekey, witnessname, exchangeRate, function(err, result) {
                if (err) {
                    console.log("!!! ERROR: Price Feed Update FAILED!");
                if (result) {
                    console.log("*** SUCCESS: Price Feed Updated!");
                    var sleeptime = Number(interval * 3000);
                    var sleepmins = Number(sleeptime / 60000);
                    console.log("Next Price Feed Update: " + sleepmins + " Minute(s)!");
                    var restartfeed = setInterval(startfeed, sleeptime);

This is an ALPHA Application

Admittedly this code has only been tested for a few hours locally here while development was under way.. It may (or will) contain bugs and I'd highly suggest using it only if you consider it at your own risk. The developer (@KLYE) of this application takes no responsibility for damage, loss of data, apocalyptic system failures or anything else nasty that may happen from using this script.

That being said I'm looking forward to folks using it, improving on it and ultimately learning from my work here. I've tried to comment the code to make it better on the mind. Any questions or problems in regards to the pricesnatcher.js project may be raised below in the comments.

Have a good day everyone!

Posted on - Rewarding Open Source Contributors


for Witness!

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

You shouldn't rely on only one exchange to get the price feed, especially if it's BaloneyEx! That pos had price discrepancies vs the other exchanges very often when it comes to STEEM/SBD.


True actually! I should add some more sources here soon. :)

Thank you for the contribution. It has been approved.

You can contact us on Discord.

I am confusion

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


  • WOW WOW WOW People loved what you did here. GREAT JOB!
  • This is your first accepted contribution here in Utopian. Welcome!

Community-Driven Witness!

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


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


Wow! Thank you very much for that hefty upvote and warm welcome to the platform!


Not too shabby that, even - curation and 20% handling fees :D

Give me some reputation please.