How To Make A Cryptocurrency Trading Bot With Golang

A Quick Disclaimer: I'm a programmer and have very little experience trading. Please do your own research before using the algorithm I create for the cryptocurrency trading bot or any other algorithm. Only trade with money you can afford to lose.

In this guide I will show you how to create  a cryptocurrency trading bot with Go. I highly recommend an IDE such as Goland but you can use a simple text editor if you would like. Feel free to take a look at my guide on how to develop with Go on Linux if you don’t have Go installed.

With that out of the way we can move on to the good part. I will be creating my own index, a very simple index, which goes up or down depending on the quantity of sell and buy orders placed. Basically I will only look at orders that are 2% above or below the latest fill order price and use those to make an index. I will use Bittrex for trading as it offers a lot of trade pairs and will focus on BTC-VTC as I believe in both coins and would like to hold either no matter what my bot does.  My index is basically order rate relative to last price multiplied by the number of VTC the order is for. If the latest price is 0.000100 and a buy order for 10000 VTC is placed at 0.000102 my index would go up by 10200 points.

(0.000102/0.000100)*10000 = 10200

This is a really simple index and someone bidding 10000 VTC 2% higher than latest fill price should maybe have a larger impact? However, to keep things simple I decided to just go with this implementation. If someone was to sell 10000 for 2% less than latest price my index would decrease by 10200 in the same way.

Ah and did I mention that my index resets every minute? I wanted my bot to make minute by minute decisions so I reset the index to 0 every minute.  But enough details, let’s get started with some code.

I used a library called go-bittrex but the current version does not support websockets which will give us real time data. There is a fork of go-bittrex that implements a function for websockets and I have decided to go with that instead. In addition to this library you will also need an API key and secret which you will find on the Settings page under the menu API Keys. I activated everything except Withdraw capabilities just in case my keys get compromised. Once you have your keys we can take a look at the example code on the go-bittrex project page:

package main

import (
	"fmt"
	"github.com/toorop/go-bittrex"
)

const (
	API_KEY    = "YOUR_API_KEY"
	API_SECRET = "YOUR_API_SECRET"
)

func main() {
	// Bittrex client
	bittrex := bittrex.New(API_KEY, API_SECRET)

	// Get markets
	markets, err := bittrex.GetMarkets()
	fmt.Println(err, markets)
}

If you run the code above you should see a long list of all the key-pairs.

[{LTC BTC Litecoin Bitcoin 0.01435906 BTC-LTC true false https://bittrexblobstorage.blob.core.windows.net/public/6defbc41-582d-47a6-bb2e-d0fa88663524.png} {DOGE...

Now, it might look a bit weird and that’s because we are simply using print on our object called markets. If we actually took the time to loop through our markets we could take the pieces we want and format it in a better, more readable way. Let’s try to get our account balances and format it a bit better. Make sure you have replaced your api keys with YOUR_API_KEY and YOUR_API_SECRET in the script above. We will replace the code under //Get markets with our own code. My changed code looks like this:

// Get markets
// Get balances
balances, err := bittrex.GetBalances()
if err == nil {
   for _, b := range balances {
      fmt.Println(b.Currency, b.Available, "/", b.Balance, " Deposit:", b.CryptoAddress)
   }
} else {
   fmt.Println(err)
}

This code will loop through all the balances in our account and print the cryptocurrency, how much we have available for trading, how much we have in total and our deposit address if there is one. If you don’t see any balances it could be because you don’t have anything in your account or you might have the wrong api keys. The output for my account looks like the following:

ARK 0 / 0 Deposit: 
BTC 0.01160229 / 0.01160229 Deposit: 1KqNRbFyi9b2Ej248BMnskCcR82Vdenk7a
BTG 0 / 0 Deposit: GYi1VdAJ892Dwkx5JgRHeXUyMk9PYhBLWW
CVC 0 / 0 Deposit: 
LTC 0 / 0 Deposit: LKPnskMDSsKyPMyPibGDVcFgQiqJme1igR
NAV 0 / 0 Deposit: 
QRL 0 / 0 Deposit: 
RISE 0 / 0 Deposit: 
SC 0 / 0 Deposit: 
SNT 0 / 0 Deposit: 
SYS 0 / 0 Deposit: 
UBQ 0 / 0 Deposit: 
VTC 522.26812636 / 522.26812636 Deposit: 
XVG 0 / 0 Deposit:

You can take a look at the bittrex object to see what other methods are available, I doubt I have had a chance to explore them all.

Goland Hints for Cryptocurrency Trading Bot

The Code of a Cryptocurrency Trading Bot

When I set up my trading bot I added a few constants that work with my index to trigger sells or buys and also limits how much I need to gain or lose before selling, buying or cancelling an order. Here are my constants:

const (
   API_KEY       = ""
   API_SECRET    = ""
   BUY_STRING    = "BTC"
   SELL_STRING   = "VTC"
   MARKET_STRING = BUY_STRING + "-" + SELL_STRING
   MIN_GAIN      = 0.02
   MAX_LOSS      = 0.02
   ORDER_RANGE      = 0.02

   BUY_TRIGGER    = 10000.0
   SELL_TRIGGER   = -10000.0
   ORDER_VARIANCE = 0.02
)

I also need some variables that will keep track of balances, orders, prices, my index, if I have an open order and so on. I also added a bool called readyToRun which is set to false for the first 60 seconds as my script gathers data and it also disables all trading if I lose connection to Bittrex. I also added a highIndex and a lowIndex to get an idea for what the max and min are in one minute for my index.

var (
   balances     []bittrex.Balance
   orders       []bittrex.Order
   ticker       = bittrex.Ticker{}
   lastPrice    float64
   lastBuyPrice = 0.00
   buySellIndex = 0.00
   openOrder    = false
   readyToRun   = false

   highIndex = 0.00
   lowIndex  = 0.00
)

The main function is what is initially called when you start running my program. This function will call all other functions.

func main() {

   // Bittrex client
   bittrexClient := bittrex.New(API_KEY, API_SECRET)

   go updateStats(bittrexClient)

   // A Simple Trading Strategy
   // We create our own buy/sell index, this resets with every buy and sell
   // If we buy and incur a 2% loss we sell at current ask
   // If we buy and make at least a 2% profit and our index is sell we sell
   // If we place an order and it does not clear and market moves -+2% we cancel
   // Every trade has a 0.25% fee

   ch := make(chan bittrex.ExchangeState, 16)

   go subscribeMarket(bittrexClient, ch)

   for st := range ch {
      // Order placed
      for _, b := range st.Buys {
         //log.Println("Buy: ", b.Quantity, " for ", b.Rate, " as ", b.Type)
         quantity, _ := b.Quantity.Float64()
         rate, _ := b.Rate.Float64()
         calculateIndex(true, quantity, rate)
      }
      for _, s := range st.Sells {
         //log.Println("Sell: ", s.Quantity, " for ", s.Rate, " as ", s.Type)
         quantity, _ := s.Quantity.Float64()
         rate, _ := s.Rate.Float64()
         calculateIndex(false, quantity, rate)
      }
      // Order actually fills
      for _, f := range st.Fills {
         //log.Println("Fill: ", f.Quantity, " for ", f.Rate, " as ", f.OrderType)
         // We could say that lastPrice is technically the fill price
         lastPrice, _ = f.Rate.Float64()
      }
      log.Printf("BuySellIndex:     %.4f\n", buySellIndex)
      decideBuySell(bittrexClient)
   }
}

Here we create a new bittrex client with our api keys and then use this to perform further actions. We call updateStats as a goroutine, this means it will run asynchronously with the rest of our program. To learn more about goroutines I would recommend checking out Go By Example. The rest of the code will be executed no matter what happens with updateStats. The next thing we do is to make a channel to handle messages received from Bittrex over our websocket connection. The subscribeMarket function will set up a websocket connection that uses the channel that was created and our for loop at the end of the script will handle any incoming messages. The messages I care about are buys, sells and fills. Buys and sells are just orders, a fill is when one of these orders goes through making it “official” so to speak. I use the buys and sells to calculate my index using the calculateIndex function. Any fill is used to update or lastPrice so that we are always acting with the most recent price when deciding to buy or sell. Finally we decide if we should buy or sell anything.

func subscribeMarket(b *bittrex.Bittrex, ch chan bittrex.ExchangeState) {
      log.Println("Connecting to:", MARKET_STRING)
      err := b.SubscribeExchangeUpdate(MARKET_STRING, ch, nil)
      if err != nil {
         log.Println("Error:", err)
      }
      log.Println("Reconnecting....")
      go subscribeMarket(b, ch)
}

The above code handles our websocket connection via the bittrex-go library. If it should end or error for some reason we try reconnecting. This function is poorly written but works. I would sometimes lose the websocket connection and might need to come back and update this function if I figure out how to reconnect in a better way.

To buy or to Sell?

func decideBuySell(b *bittrex.Bittrex) {
   if openOrder {
      // Should we close the open order?
      for _, o := range orders {
         ppu, _ := o.PricePerUnit.Float64()
         log.Printf("Order percent: %.4f\n", ppu/lastPrice)
         if ppu/lastPrice > (1.00+ORDER_VARIANCE) || ppu/lastPrice < (1.00-ORDER_VARIANCE) {
            log.Println("Canceled order: ", o.OrderUuid)
            b.CancelOrder(o.OrderUuid)
            // We assume we only have one order at a time
         }
      }
   }
   // If we have no open order should we buy or sell?
   if !openOrder {
      if buySellIndex > BUY_TRIGGER {
         log.Println("BUY TRIGGER ACTIVE!")
         for _, bals := range balances {
            bal, _ := bals.Balance.Float64()
            if BUY_STRING == bals.Currency {
               //log.Printf("Bal: %.4f %s == %s\n", bal/lastPrice, SELL_STRING, bals.Currency)
            }
            if bal > 0.01 && BUY_STRING == bals.Currency && lastPrice > 0.00 {
               // Place buy order
               log.Printf("Placed buy order of %.4f %s at %.8f\n=================================================\n", (bal/lastPrice)-5, BUY_STRING, lastPrice)
               order, err := b.BuyLimit(MARKET_STRING, decimal.NewFromFloat((bal/lastPrice)-5), decimal.NewFromFloat(lastPrice))
               if err != nil {
                  log.Println("ERROR ", err)
               } else {
                  log.Println("Confirmed: ", order)
               }
               lastBuyPrice = lastPrice
               openOrder = true
            }
         }
      } else if buySellIndex < SELL_TRIGGER {
         log.Println("SELL TRIGGER ACTIVE!")
         for _, bals := range balances {
            bal, _ := bals.Balance.Float64()
            if SELL_STRING == bals.Currency {
               //allow := "false"
               //if allowSell() {
               // allow = "true"
               //}
               //log.Printf("Bal: %.4f %s == %s && %s\n", bal, BUY_STRING, bals.Currency, allow)
            }
            if bal > 0.01 && SELL_STRING == bals.Currency && lastPrice > 0.00 && allowSell() {
               // Place sell order
               log.Printf("Placed sell order of %.4f %s at %.8f\n=================================================\n", bal, BUY_STRING, lastPrice)
               order, err := b.SellLimit(MARKET_STRING, decimal.NewFromFloat(bal), decimal.NewFromFloat(lastPrice))
               if err != nil {
                  log.Println("ERROR ", err)
               } else {
                  log.Println("Confirmed: ", order)
               }
               openOrder = true
            }
         }
      }
   }
}
func allowSell() bool {
   if lastBuyPrice > 0 {
      gain := lastPrice / lastBuyPrice
      if gain < (1.00 - MAX_LOSS) {
         return true
      }
      if gain < (1.00 + MIN_GAIN) {
         return false
      }
   }
   return true
}

The functions above is a big part of the simple algorithm I created. The first part of the function checks if we have an open order. I decided that if I place an order and the market moves +- 2% then I want to cancel any order because it will most likely never fill. The 2% might be a bit high but it works well as a safety measure as most of my orders tend to fill quickly. Buying or selling is only triggered if my index hits 10000 or -10000 and then some additional checks are run. I implemented the allowSell function to make sure that my bot only sells if there is a gain or loss of more than the Bittrex trading fee of 0.25%. In my code I set the margin to be at least +-2%.

func calculateIndex(buy bool, q float64, r float64) {
   // q is quantity VTC
   // r is the rate
   percent := 0.00
   // Calculate percentage of rate
   if r > 0 && q > 0 && lastPrice > 0 && readyToRun {
      percent = lastPrice / r
      if buy {
         //log.Printf("Buy percent: %.4f\n", percent)
         //log.Printf("Buy quantity: %.4f\n", q)
         if percent > (1.00 - ORDER_RANGE) && percent < (1.00 + ORDER_RANGE) {
            buySellIndex = buySellIndex + (percent * q)
         }
      } else {
         //log.Printf("Sell percent: %.4f\n", percent)
         //log.Printf("Sell quantity: %.4f\n", q)
         if percent > (1.00 - ORDER_RANGE) && percent < (1.00 + ORDER_RANGE) {
            percent = percent - 2.00 // Reverse percent, lower is higher
            buySellIndex = buySellIndex + (percent * q)
         }
      }
   }
   if buySellIndex > highIndex {
      highIndex = buySellIndex
   }
   if buySellIndex < lowIndex {
      lowIndex = buySellIndex
   }
   // Reset really high or low numbers due to startup
   if highIndex > 5000000.00 || lowIndex < -5000000.00 {
      highIndex = 0.00
      lowIndex = 0.00
      buySellIndex = 0.00
   }
}

Here is the calculateIndex function which does exactly what it says. It is what my bot uses to decide to buy or sell. At the bottom I implemented a reset for my indexes as I would sometimes see very high or low values. This happend when launching my program as a lot of orders come through the websocket right away. This is also why my program waits 60 seconds to start. My index is calculated every time there is a message via the websocket. This can happen several times per second and on each update my program will decide to buy/sell. This allows the bot to be very responsive and act instantly.

func updateStats(b *bittrex.Bittrex) {
   var err error = nil
   for {
      go func(b *bittrex.Bittrex) {
         balances, err = b.GetBalances()
         orders, err = b.GetOpenOrders(MARKET_STRING)
         ticker, err = b.GetTicker(MARKET_STRING)
         if err != nil {
            log.Println("Error:", err)
            // Pause calculations in case of error
            readyToRun = false
         }

         log.Printf("====================================\n")
         log.Printf("Last price:       %v\n", ticker.Last)
         log.Printf("Index:           %.4f\n", buySellIndex)
         log.Printf("High Index:       %.4f\n", highIndex)
         log.Printf("Low Index:           %.4f\n", lowIndex)
         lastPrice, _ = ticker.Last.Float64()
         buySellIndex = 0.00

         log.Printf("Bid:         %v\n", ticker.Bid)
         log.Printf("Ask:         %v\n", ticker.Ask)

         // Do we have an open order?
         openOrder = len(orders) > 0

         for _, o := range orders {
            log.Println("Pending order: ", o.OrderType, " Quanitity: ", o.QuantityRemaining, "/", o.Quantity, " Price: ", o.PricePerUnit)
         }

         // Where do we have balances
         for _, b := range balances {
            bal, _ := b.Balance.Float64()
            if bal > 0.00 {
               log.Printf("%s:          %v %s %v\n", b.Currency, b.Available, "/", b.Balance)
            }
         }
         log.Printf("====================================\n")

      }(b)
      <-time.After(60 * time.Second)
      // Wait 60 to init and collect data
      readyToRun = true
   }
}

Finally we have the updateStats function. This function loops every 60 seconds and updates the orders, balances, last price and resets my index to 0. I also configured it to print out useful data for tweaking my variables or debugging the application.

All of the code I have shared with you above is available on Github and is MIT licensed so that you are free to take the code and modify it for your own needs. I also recommend testing some of the calculations in a scratch file, I made an example scratch file that I used to make sure my calculations did what I thought they would.

This seemed like a good topic to write about. I hope my example will help someone else learn. I would love to hear your feedback, criticism and hopefully improvements to the code in the comments below.

Thanks for reading!

Update: Turns out the first cryptocurrency trading bot I ever made was not profitable at all. Initially it made some good trades but then it kept losing money. I tried to tweak my current algorithm and ran it for a week loosing 30% or about 300 euro. At the moment I shut the bot down and have plans to make a new, better trading bot in the future.

How To Protect Your Cryptocurrencies

Please note that I own a Ledger Nano s and include affiliate links in this article. I was not hired/paid to write this article.

Whether you are new to cryptocurrencies or not it is important to safeguard your savings. When buying cryptocurrencies you typically go through an exchange such as Coinbase, Binance or Bittrex. An exchange is fine for buying and selling but if you plan to keep cryptocurrency for a long time it would be much safer to store it on a hardware wallet such as the Ledger Nano S or the Trezor. I wanted to write this article to outline some of the things that any user should be aware of.

Tips For Keeping Your Cryptocurrencies Safe

Make sure to protect your passwords, seeds and keys. As with any website you should never use the same password for multiple logins. The best way to keep you protected is to use an offline program like KeePass to store all logins in an encrypted file. Because I know that this is not optimal for everyone I would at least recommend to manage different passwords with your browser or a service like LastPass. Note that these types of services become targets of attacks and are sometimes hacked. The safest way to protect your passwords is to store them offline in an encrypted file.

Seeds for wallets are usually a bunch of words that you are told to write down. It is extremely important that you protect these words as they act as a master key for your wallet. That means that anyone with these words can transfer your cryptocurrencies without any other information. I highly recommend that you keep seeds offline, never copy these words. Write them down on a piece of paper and put it in a safe place. I personally like to keep two physical places, perhaps you keep one at home and one at your parents house or a safety deposit box. Never ever take a picture as a backup. Remember, services like Dropbox or Apple have been hacked in the past and it can happen again.

Phising Is Still A Problem

Beware of spoofed domains, domains that look like they are the real deal but are actually phising sites. Something that has become a problem lately is that scammers register domains such as Bìnance.com or Binançe.com. If you look closely you will see that the i and c in the above examples are actually special characters and therefore a completely different domain. Please note that Binance was simply an example, it could happen to any domain. These sites look exactly like the real deal and it is hard for even an expert to tell the difference. My recommendation for protecting yourself against these scams is to simply type in the domain name yourself. Never go to a website via Google search results or links from pages on other website.

Hardware wallets

As I mentioned in the beginning of my article, one of the best ways to protect your cryptocurrencies is with a hardware wallet. There are two hardware wallets that I feel safe recommending at the moment, the Ledger Nano S or the Trezor. I personally use the Ledger Nano S for my own cryptocurrencies. Similar to a software wallet you will have a seed, a bunch of words that you will need to protect. As stated before, put it in a safe place and make a copy to put in a safety deposit box. Never take a picture of your seed words and never store it on your computer. I cover two hardware wallets but I want to note that there are more options out there.

Now, you might wonder how a hardware wallet works. You simply connect it to your computer via a USB cable. On my computer I run a small application that talks to my ledger. This will allow me to view my balance and transactions as long as a input my pin. I can initiate transactions using the software but will need to approve the transaction using my ledger.

I highly recommend that you buy the Ledger Nano S directly from Ledger as there have been reports of scams via places like email. Some have reported premade seeds (your seed card should be blank) or in a rare case the hardware may have been tampered with.

A Final Word

These are some focus points that I have personally picked out. I assume that you already keep yourself protected from viruses by keeping your system and applications up to date. If you are dealing with large amounts of cryptocurrencies I would suggest that you might consider having a dedicated computer to handling your cryptocurrencies and nothing else.

I hope you find this article helpful and I would love to hear feedback, I am sure I missed something that would be good to mention.

CryptoKitties – A Game Played On The Blockchain

I bought kitties on CryptoKitties when popularity seemed to peak back in December 2017. At the same time Ethereum hit a $1000 and Bitcoin shot up to $20,000. So I did what any sane person would do and transferred 1 ETH to buy and sell digital cats. It was interesting because this digital economy reminded me a lot of games like Travian that have in game economies, or an even more relevant site would be Neopets which has items you can buy and sell using points you earn from playing games. It’s actually where I got interested in HTML as I learned how to customize the look of my shop.

Back to digital cats. The fact that you could create games on the blockchain was revolutionary and I wanted to try it. I wanted to learn how it works and be a part of history. In the end my account has 41 kittens. I put some up for sale but I want to keep a few forever. The site may go away one day but the fact that I own a cat will always be stored on the Ethereum blockchain which is pretty cool. Although the cat is just a hash or an id, if you look at my account on the blockchain all you will see is a bunch of transactions with the only thing hinting at kitties being the name of the smart contract.

How does CryptoKitties work?

CryptoKitties is a game played on the blockchain using smart contracts. Players initially have to buy a cat using Ethereum which costs real money. They can then choose to breed their cat with someone else’s cat or buy a second cat to breed with. Breeding will create a new cat with traits based on the previous generations of cats or sometimes random mutations. Players can also decide to sire their cats for others to breed with or sell the cats they have. But be careful, every time you breed your cats their breed times will decrease.

Everything you do in CryptoKitties will cost gas, gas is what is used to pay for work executed on the blockchain and is paid with Ethereum. In order to use a site like CryptoKitties you will need a browser plugin like MetaMask that acts as a wallet for your ethereum. There are also browsers that support communication with the Ethereum Blockchain.

The most valuable kitties are those with a low generation and preferably some rare traits. The gen 0 kitties were pretty expensive so I decided not to buy one. But please keep in mind that the gen 0 kitties are the only kitties that are limited. There will be an unlimited amount of kitties for all others, the slowest breeding time is one week and when this is reached you can simply keep breeding over and over again.

What did I learn?

I think it’s awesome that people are creating games on the blockchain. However, I think we have a long way to go before we can actually have anything decent going. I imagine that one day this blockchain technology will be much faster and efficent. This would allow us to instantly buy and sell on the blockchain. This would make games much more interactive and we could buy and sell digital goods in a secure way similar to how games like second life work today.

If you are interested in learning how to program games on the blockchain there is a free code school that teaches you how to do this called CryptoZombies.

I tried mining Vertcoin for 1 month

…And I plan to keep mining.

It has been a fun experience and I would recommend it to anyone who is interested in learning how mining Vertcoin works. I have a gaming PC at home which has a pretty powerful graphics card, the Nvidia 1080Ti. Before I started mining I would turn this beast off to save money on my power bill. However, these days it runs 24/7 as I would save less money by turning it off.

Why start mining Vertcoin?

First of all, only try mining cryptocurrency if you either pay for your own electricity or have discussed this with however does. Mining can get expensive, especially if you have multiple graphics cards.

The reason why I started mining was pretty simple. Over the last year I had taken a greater interest in cryptocurrency and felt the itch to develop something. I had set up my own Bitcoin node and started making applications that would parse and analyse the blockchain. By the way, if you want to get more in depth there is a pretty awesome tutorial on how you can create your own blockchain and cryptocurrency with Go.

I moved from Bitcoin to Vertcoin as the blockchain is much smaller than the 160GB beast that Bitcoin has. It’s just easier to work with and more portable. Vertcoin also follows Bitcoin with implementations like Lightning that will speed up transactions and make them much cheaper. The main difference between Vertcoin and Bitcoin is Vertcoin’s ASIC resistance. Bitcoin is currently very hard to mine and requires an investment of at least a few thousands of dollars for specialized miners to get started. This is not something that the average person can buy. Vertcoin uses more memory heavy algorithms which makes it perfect for mining with a graphics card.

Of course this has also had some negative side effects as miners started buying every graphics card they could get their hands on. This has resulted in much higher prices and a lack of availability for PC gamers. I hope that this is a temporary side effect.

How much did I earn?

I have earned a total of 40 VTC as can be seen on my mining address here: VcMhEJrnYKNjTSrkazwJXgLHVRB5vKuouv. This is about $120 in todays value. Since I am living in Germany at the moment my electricity bill is a bit high but comes in at less than half of my rewards. I did this without mining full time, I paused my mining almost every day and played some games for an hour or two. I plan to keep my VTC to save them or use them to test future projects that I think of. I still have 3 days left before I have actually mined for a full month.

How do you mine Vertcoin?

I run a public node that can be seen here, anyone is free to mine on it http://185.201.144.162:9181/static/. I have also written a guide on how to mine VTC over at VTCPool.io.

The developers have made mining Vertcoin super easy, I run the One Click Miner on my Windows 10 PC without the need to configure anything.