The Internal Market- Now Automated

I finally got around to automating my interaction with the internal market. What I have done is created a script that will take all my hive and sell it on the internal market for HBD. Due to hive just bing a bit too downwards trendy for my taste, I decided that saving in HBD rather than Hive might be a good move for some time.

I'm exploring a new way of writing, separating it out and giving more detailed explanations rather than dumping code and explaining it within the comments.

let axios = require("axios")
let hive = require("@hiveio/hive-js")
let logger = require("node-color-log")

We have axios to make requests to http servers, hive to make transactions on hive(eventually I'd like to stop using hive as a dependency and make my own library for it to learn more about signing and JS) and logger to log in a cleaner way.


let username = "rishi556"
let activeKey = ""
let node = "https://api.deathwing.me"
let refreshHours = 1

Then we have our variables that we use for configuration. Most are self explanatory. Refresh Hours is how many hours to wait before refreshing the order. Because we are attempting to have the lowest ask without selling at the bid price, refreshing more often will be better if we are dealing with large amount of HIVE. Because I'm poor and don't have too much usually I set mines to work every 2.5 minutes(this example shows it running once every hour). The internal market doesn't get too much use and usually there can be time periods of longer than 5 minute without any activity so setting it a lot higher has no benefit.


async function getOpenSellOrders() {
  let call = { id: 0, jsonrpc: "2.0", method: "call", params: ["condenser_api", "get_open_orders", [username]] }
  let result = await axios.post(node, call)
  let orders = result.data.result
  orders = orders.filter((a) => { return a.for_sale === 1 })
  return orders
}

Then we need to get our own sell orders. We are filtering them to make sure they are sell orders because I don't care about my hbd -> hive orders, only hive -> hbd. I need to get these orders because I want to cancel them. Yes, it would be better to check if I had the lowest order and not cancel in that case, but this is quicker and easier to implement so I went with this. Rather than using hivejs for this, I just used an axios post request because it easier than reading the documentation for hivejs.


async function cancelOrders(orders) {
  if (orders.length === 0) {
    return true
  }
  let ids = Array.from(orders, (a) => { return a.orderid })
  let ops = []
  for (let i in ids) {
    ops.push(["limit_order_cancel", { "owner": username, "orderid": ids[i] }])
  }
  hive.broadcast.send({ operations: ops, extensions: [] }, { active: activeKey }, (error, result) => {
    if (error) {
      return false
    }
    return true
  })
}

Then we have a function to cancel orders. If we are able to cancel them successfully(or there are no orders to cancel) we return true, and if we fail, we return false.

All orders have an id associated with them thats unique to that person, and you can't have 2 open orders with the same id. With our getOpenSellOrders() function, we are able to get all those orders and thus we get the order ids with them as well.

The op to cancel an open order would be ["limit_order_cancel", { "owner": "rishi556", "orderid": 1 }] and we are able to have multiple ops in one transaction(this helps us out because we don't need to have a lot of trx to cancel multiple orders, we can do it all in one) so we push them to an array. Then using the send feature of hivejs we can broadcast the op. Because this chain is actually designed better than some others out there and this action deals with funds, we need to sign this with our active key.


Date.prototype.addHours = function(h) {
  this.setTime(this.getTime() + (h*60*60*1000))
  return this
}

I found this on stack overflow to deal with the native js date to add time to another time. I'm used to using libraries and recently I've been trying to not use them if not necessary for small things like this and so we need this.


async function startProcess() {
  let orders = await getOpenSellOrders()
  let cancelled = cancelOrders(orders)
  if (!cancelled) {
    logger.error(`Couldn't cancel orders. Exiting.`)
    return
  }
  setTimeout(async () => {
    let call = { id: 0, jsonrpc: "2.0", method: "call", params: ["condenser_api", "get_ticker", []] }
    let result = await axios.post(node, call)
    let ticker = result.data.result
    let lowestAsk = ticker.lowest_ask
    call = { id: 0, jsonrpc: "2.0", method: "call", params: ["condenser_api", "get_accounts", [[username]]] }
    result = await axios.post(node, call)
    let balance = parseFloat(result.data.result[0].balance.split(" "))
    if (balance === 0) {
      logger.info(`0 balance. Exiting.`)
      return
    }
    let minToReceive = (balance * lowestAsk) - 0.001
    if (minToReceive < 0.001) {
      logger.info(`Not enough balance for sale. Exiting.`)
      return
    }
    minToReceive = minToReceive.toFixed(3) + " HBD"
    let amountToSell = result.data.result[0].balance
    let expiration = new Date().addHours(refreshHours).toISOString().replace("Z", "")
    let op = ["limit_order_create", { "owner": username, "amount_to_sell": amountToSell, "min_to_receive": minToReceive, "fill_or_kill": false, "expiration": expiration, "orderid": Math.floor(Math.random() * 1000000) }]
    let ops = [op]
    hive.broadcast.send({ operations: ops, extensions: [] }, { active: activeKey }, (error, result) => {
      if (error) {
        logger.error(`Couldn't place order.`)
      }
      logger.info(`Placed order to sell ${amountToSell} for ${minToReceive}.`)
    })
  }, 1000 * 4)
}

Here's the big boy doing all the work. First off we get the orders and then cancel them. If we aren't able to successfully cancel, we stop because something went wrong. Then we wait 4 seconds so that way the cancellations go through and we have the HBD to relist on our account. We then need to get info on the internal market, and the post request to get that is { id: 0, jsonrpc: "2.0", method: "call", params: ["condenser_api", "get_ticker", []] }. We'll get a response like the following :

{
   "id":0,
   "jsonrpc":"2.0",
   "result":{
      "hbd_volume":"3544.493 HBD",
      "highest_bid":"0.13938253536831835",
      "hive_volume":"25176.475 HIVE",
      "latest":"0.14274004192872117",
      "lowest_ask":"0.13992720145597087",
      "percent_change":"-0.00421342861105539"
   }
}

With this we can see the volume and the lowest ask. What we need to do is to have an order who's lowest_ask is lower than the current one. To do that, we multiply our current hive balance by the lowest ask, then subtract 0.001 off that so that ours will be lower. Our hive balance is the amount_to_sell and the the number we get from the previous calculation is min_to_receive. Now we just need two final pieces to build the overall operation. We need an expiration time, which is when the order will automatically cancel itself. I don't know what the max value that we can set for this is, but here we want to kill the order if it's been longer than refreshHours hours and so we can do that by adding that to the current date. The format that it needs to be in is 2020-11-24T20:32:39 YYYY-MM-DDTHH-mm-SS with the time being UTC. We also need an order id. Order id is an integer that just can't coincide with another open order from the same account. To generate one, I just generate a random number between 0 and 999,999. That should stop any collisions. I don't exactly know what fill_or_kill is, but if its what I assume it is from trading elsewhere(and its name), if it doesn't get all filled immediately, the order will automatically get killed. This would be useful for dumping but we don't want that so we set it to false. Then we use all the info to generate an operation which should look like this: ["limit_order_create", { "owner": "rishi556", "amount_to_sell": "1.000 HIVE", "min_to_receive": "1.000 HBD", "fill_or_kill": false, "expiration": "2020-11-24T20:32:39", "orderid": 1 }]. With all that in place, we can broadcast the same way as we did cancelling. And there we go, we have an automated the selling of Hive into HBD.


startProcess()
setInterval(() => {
  startProcess()
}, 1000 * 60 * 60 * refreshHours)

Because we want the script to work automatically once every refreshHours hours we use the interval to run startProcess() at that.


Wanna see the bot in action? Just send any amount of hive to my account and as long as its running, it'll magically place an order for it to be converted to HBD. There's not too much to it. It's just doing each step that I would manually be doing but instead doing it automatically and without any input required from me making my life even easier. If anyone wants, I can throw tis on a git repo so you can enjoy it as well.


I do take requests. If theres something small that you'd like to see automated, just ask. I might not get around to it for a while(or I might decline it if its too large) but as long as its a reasonable request(I can get it the code written up in under an hour) I'm willing to show you how to get some automation done. It doesn't even have to be hive related. Can be anything.

H2
H3
H4
3 columns
2 columns
1 column
6 Comments
Ecency