How to make a bitcoin telegram bot in Golang
Hey There!
So I’ve been having these 3 things in my head for a couple of months right now:
- Golang: Because I wanted to learn a new Backend language
- Telegram: Because f@!$ Whatsapp
- Bitcoin: Because f@!$
The policeprinted money
So, I got an idea, and you will not be able to guess what it was.
That’s right, merging all 3 into a single project.
Table of Contents
Bitcoin telegram bot
Since I’ve created a couple of bots for the last
Hands on
Bot father
Telegram has a
You can also play a little bit more with @BotFather. For example, you can use the /setcommands to define the uses your bot has on the / icon:
/price - gets BTC actual price /historic - gets a percentage between Today's and Yesterday's price /summary - gets both the price and historic values

Bitcoin API
After getting the TOKEN, I needed Bitcoin’s price and, as far as I knew, I wasn’t going to hardcode it into a Bot or hot-swap its value manually. So, I looked for an API that could do that for me.

(We all look up things like this, don’t let the impostor syndrome tell you otherwise.)
With a simple CURL, we can get a JSON with the prices. So I decided to use this:

A little bit of code
If you read my previous posts, I’ve been researching and testing how GO modules work. I don’t like convoluted files that make things hard to find, so my folder structure looks like this:

Model
I began by writing a model for Bitex’s response:
package model
type Price struct {
Last float32 `json:"last"`
PriceBeforeLast float32 `json:"price_before_last"`
Open float32 `json:"open"`
High float32 `json:"high"`
Low float32 `json:"low"`
Vwap float32 `json:"vwap"`
Volume float32 `json:"volume"`
Bid float32 `json:"bid"`
Ask float32 `json:"ask"`
}
I then utilized it on another module that was only intended for the API Call.
API Call
package utils
import (
"encoding/json"
"net/http"
"github.com/tomassirio/bitcoinTelegram/model"
)
func GetApiCall() (*model.Price, error) {
resp, err := http.Get("https://bitex.la/api-v1/rest/btc_usd/market/ticker")
p := &model.Price{}
if err != nil {
return p, err
}
err = json.NewDecoder(resp.Body).Decode(p)
return p, err
}
Lovely, GO handles the REST requests like a boss.
Handler
The handler is a bit sloppy written. I’ve been using JavaScript, which I’m definitely not too keen on, to create Discord Bots. So, I tried to emulate my previous handlers in GO – we have this now:
package handler
import (
"github.com/tomassirio/bitcoinTelegram/commands"
tb "gopkg.in/tucnak/telebot.v2"
)
func LoadHandler(b *tb.Bot) map[string]func(m *tb.Message) {
commandMap := make(map[string]func(m *tb.Message))
commandMap["/price"] = func(m *tb.Message) {
res, _ := commands.GetPrice()
b.Send(m.Chat, "BTC's Current price is: U$S "+res)
}
commandMap["/historic"] = func(m *tb.Message) {
res, g, _ := commands.GetHistoric()
b.Send(m.Chat, "BTC's Price compared to yesterday is: "+res)
b.Send(m.Chat, g)
}
commandMap["/summary"] = func(m *tb.Message) {
p, h, _ := commands.GetSummary()
b.Send(m.Chat, "BTC's Current price is: U$S "+p+"\nBTC's Price compared to yesterday is: "+h)
}
return commandMap
}
What’s most remarkable about this handler is that it’s basically a Map from String to a function. This will make sense once we get to the main function.
Commands
I only created three commands for this bot as it wasn’t a deep project (it was mostly just for fun). So, please bear with the simplicity of them for now:
func GetPrice() (string, error) {
p, err := utils.GetApiCall()
return fmt.Sprintf("%.2f", p.Last), err
}
func GetHistoric() (string, *tb.Animation, error) {
p, err := utils.GetApiCall()
l := p.Last
o := p.Open
his := ((l - o) / o) * 100
if !math.Signbit(float64(his)) {
g := &tb.Animation{File: tb.FromURL("https://i.pinimg.com/originals/e4/38/99/e4389936b099672128c54d25c4560695.gif")}
return "%" + fmt.Sprintf("%.2f", ((l-o)/o)*100), g, err
} else {
g := &tb.Animation{File: tb.FromURL("http://www.brainlesstales.com/bitcoin-assets/images/fan-versions/2015-01-osEroUI.gif")}
return "-%" + fmt.Sprintf("%.2f", -1*((l-o)/o)*100), g, err
}
}
func GetSummary() (string, string, error) {
p, err := utils.GetApiCall()
l := p.Last
o := p.Open
his := ((l - o) / o) * 100
if !math.Signbit(float64(his)) {
return fmt.Sprintf("%.2f", p.Last), "%" + fmt.Sprintf("%.2f", ((l-o)/o)*100), err
} else {
return fmt.Sprintf("%.2f", p.Last), "-%" + fmt.Sprintf("%.2f", -1*((l-o)/o)*100), err
}
}
Telegram Config
'Member that Token we got from @BotFather? Oooh, I 'member. Of course, there’s another module for that. How do you think we could find these things if there were no structure?
type Config struct {
Token string
}
func LoadConfig() *Config {
// load .env file from given path
// we keep it empty it will load .env from current directory
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
return &Config{Token: os.Getenv("TOKEN")}
}
I’m not going to copy the contents of the .env file, but I will show you the .env.example:
TOKEN=REPLACE_WITH_TOKEN
I really hope you weren’t expecting anything else.
The main file
Our Bot is almost built, now we have to tell Go, “Dude, we need this up and running:”
func main() {
b, err := tb.NewBot(tb.Settings{
// You can also set custom API URL.
// If field is empty it equals to "https://api.telegram.org".
Token: config.LoadConfig().Token,
Poller: &tb.LongPoller{Timeout: 10 * time.Second},
})
if err != nil {
log.Fatal(err)
return
}
for k, v := range handler.LoadHandler(b) {
b.Handle(k, v)
log.Println(k + "✅ Loaded!")
}
b.Start()
}
So, basically, the program basically the TOKEN from the Config module, checks that there are no errors, and (here comes my favorite part) we cycle through the command map on the Handler module in order to load every single command onto the Bot.
Let’s look at it again since it was so satisfying:

Hosting it
I used my Raspberry 4 to host this bot (as well as the others), but you can use Heroku, AWS, Gcloud, or just an old computer that you’re not using right now.
To host it you will need:
- A computer, service, or server where you can host the bot
- Git
- Golang v1.13
- A device with Telegram (to use it)
First, open a Terminal and copy these commands (Linux & Mac devices):
cd ~
git clone https://github.com/tomassirio/BitcoinTelegramBot.git
cd ./BitcoinTelegramBot
mv .env.example .env
go get github.com/tomassirio/bitcoinTelegram
go run main.go
Warning: This won’t work unless you replace REPLACE_WITH_TOKEN on the
.envfile with the Token granted by@BotFather
Usage
Now, head over to Telegram and look for the Bot you created on @BotFather. Then, use any of the 3 commands that were configured:
* /price : Get's bitcoin's Last price
* /historic : Gets a percentage between Today's and Yesterday's price
* /summary : Gets both the price and historic values

You can also can this bot to your favorite group (or any group whatsoever) by tapping on the chat’s options, and the Add to Group Button:

Final words
I really hope you enjoyed reading this post as much as I did writing it. I don’t consider myself a good developer, but that’s exactly why I’m writing these posts. You don’t need to be an expert in order to share your experiences with other people.
If you want to check out the repository, you can do so by going to the following link.
You can:
- Fork it and do your own version of it.
- Tweak it and create a pull request to merge it to the original version.
- Do whatever you want with it because it’s open-source.
- If you want to leave a Star on it, I’ll be really grateful since it will help me in my professional career.
- If you want to buy me a beer, the link is in the footer of the repository.
As always, happy coding!