In this guide, we're going to create our own system for monitoring the Bitcoin price and sending notifications when certain conditions are met (for instance, notify me if the price of Bitcoin passes $15,000).
The primary purpose of this guide is to provide an introduction to IFTTT, but we'll also learn a little bit of Python as well.
What is IFTTT?
IFTTT stands for "if this then that". It's a platform that allows users to connect services and perform actions based on inputs and outputs from those services. Let me explain using a few examples. With IFTTT you can monitor a Google Drive folder, and send an email whenever a new file is added. Or, monitor the weather and send a Tweet if there's a chance of rain. The possibilities are nearly endless.
How this project works
Before diving in, it might help to look at a high-level overview of how this project works.
We'll create a config file that defines a few price rules.
We'll use a Raspberry Pi to run a script every minute that checks the price of Bitcoin.
If the Bitcoin price matches any of our price rules, we'll send a request to an IFTTT webhook.
When the IFTTT webhook receives the request, it will send a notification on our phone.
If you don't happen to have a Raspberry Pi laying around, there are other options. I'm using a Pi simply because I have one set up and running continuously on my desk.
Click My Applets in main menu, then New Applets. From here, click on the word this. In our case, this is going to be a trigger that is activated by a web request.
The action is what happens when the conditional is met. In our case, when IFTTT receives a particular web request, we want to send a notification to our phone.
To configure the action click the word that.
Then search through the actions for "notifications", and select it. Then click Connect.
Now we're going to configure our action. We have two options at present: regular notifications or rich notifications. We're going to use normal notifications, so click Send a notification from the IFTTT app.
Now we'll choose the message we want to use for the notification. There are two possible messages:
BTC price rises above the threshold
Bitcoin is now above $10,000. BTC price: $10,230.
BTC price drops below the threshold
Bitcoin is now below $10,000. BTC price: $9,999.
So our message is going to look like this:
Bitcoin is now {{Value1}}. BTC price: {{Value2}}.
Value1 will be a single string that says either: "above {threshold}" or "below {threshold}". Value2 will be "{price}".
In order to send the web request to trigger the notification, we'll need to authenticate. To authenticate, we'll use an IFTTT secret key.
To find your key, click this link, and then click documentation. This page should show your key. Make sure to use key (not my fake one) in the script later on.
There are many ways this step could be accomplished, but since this tutorial is primarily about getting started with IFTTT, I'm going to use the absolute simplest method.
We'll use a text file to store price alert rules. And it should look something like this:
> $11,000
< $9,000
Assuming the current price is $10,000, our app will alert when a new price is seen that is either above $11,000 or below $9,000.
So let's go ahead and create this file on our Raspberry Pi. To do so, we'll create the file locally, then copy it to the Pi.
Open Terminal
To complete this guide, you'll need access to a Terminal.
Create the price alert file
The file must be called price-alert-rules.txt and include rules similar to the example above. Obviously adjusted because as you're reading this the price is probably well over $200k 😂. Use your preferred text editor to create this file, and remember the location.
This is where things get fun. We'll write a Python script that will be executed every minute (using cron). This script will ping the coinmarketcap API, check the Bitcoin price, then send a notification if any of our price rules are met.
Note: Since this tutorial is not primarily about Python, I'm not going to explain the script line by line. I will, however, do my best to provide useful comments in the script.
So create a file called checkbtc.py and include the following:
#!/usr/bin/env python3
import operator
import re
import requests
import os
# The endpoint we'll hit to get btc price info.
TICKER_URL = 'https://api.coinmarketcap.com/v1/ticker/bitcoin/'
# Get the location for our price alerts config.
CONFIG = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'price-alert-rules.txt',
)
# The name of our IFTTT web request event.
IFTTT_EVENT = 'btc_price_alert'
# Our IFTTT secret key. Protect this if you don't want attackers to send
# you notifications.
IFTTT_KEY = 'h_OzPlgU26r5vl_d30aEF0euqEYmsWW4R34AtYhapan'
# The endpoint we'll use to send trigger price alert notifications.
IFTTT_URL = (
'https://maker.ifttt.com/trigger/{0}/with/key/{1}'
.format(IFTTT_EVENT, IFTTT_KEY)
)
class PriceRule:
"""Handle individual price rules.
This class parses, validates, compares, and sends notifications for
individual price rules.
"""
# Map the operator symbol to the corresponding Python comparison operator
OPERATOR_MAP = {'>': operator.gt, '<': operator.lt}
# Map the operator symbol to the corresponding word
WORD_MAP = {'>': 'above', '<': 'below'}
def __init__(self, original_line):
"""Initialize PriceRule.
This requires a single line from the price rules config file.
Args:
original_line (str): A single line from the price rules config.
"""
self.original_line = original_line
self.parse_line(original_line)
def parse_line(self, line):
"""Parse the price rule config line.
This parses the config line, validates it, then sets required instance
variables.
Args:
line (str): config line.
Raises:
ValueError: If the config line is invalid.
"""
# Remove whitespace surrounding the line.
line = line.strip()
# Get the opreator symbol. We assume the operator symbol is the first
# non-whitespace character.
operator_symbol = line[0]
# The remainder of the line is the threshold. Remove any non numeric
# characters.
threshold = re.sub(r'[^\d]', '', line[1:].strip())
# Ensure the operator symbol makes sense.
if operator_symbol not in ['>', '<']:
raise ValueError('Line must start with > or <.')
# Ensure the threshold can be converted to float.
try:
threshold = float(threshold)
except TypeError:
raise ValueError('Line must contain a valid price.')
# If all is well, set required instance variables.
self.operator_symbol = operator_symbol
self.operator = self.OPERATOR_MAP[operator_symbol]
self.threshold = threshold
def matches(self, value):
"""Check if value matches our price rule condition.
Assuming the operator is ">" or "greater than",
self.operator(value, self.threshold)
is the equivalent of:
value > self.threshold
Args:
value (float): The btc price.
"""
return self.operator(value, self.threshold)
def notify(self, btc_price):
"""Construct and send a notification for this price rule.
This doesn't check whether or not the price rule condition is met, it
just sends the notification.
Args:
btc_price (float): The btc price :)
"""
# Get the correct operator word. e.g. "above" for ">".
word = self.WORD_MAP[self.operator_symbol]
# Construct the data dict to send to the IFTTT webhook
data = {
'value1': '{0} ${1:,.2f}'.format(word, self.threshold),
'value2': '${:,.2f}'.format(btc_price)
}
# Send the webhook, which then triggers the mobile notification
requests.post(IFTTT_URL, json=data)
def delete(self):
"""Delete the line from the config file.
This assumes that once a notification has fired, it should not continue
firing.
There's probably a nicer way to do this.
"""
new_lines = []
# Copy all lines from the original config, exclude this price rule.
with open(CONFIG) as config_file:
for line in config_file:
if line == self.original_line:
continue
new_lines.append(line)
# Write all lines (except this one) to the config file.
with open(CONFIG, 'w') as config_file:
for line in new_lines:
config_file.write('{0}'.format(line))
def load_price_rules():
"""Load the price rules config file, create a PriceRule for each line.
Returns:
list: A list of PriceRule objects.
"""
rules = []
with open(CONFIG) as config_file:
for line in config_file:
rules.append(PriceRule(line))
return rules
def get_btc_price():
"""Hit the coinmarketcap API, get the btc price.
Returns:
float: btc price.
Raises:
RuntimeError: if request fails or response is invalid.
"""
try:
response = requests.get(TICKER_URL)
return float(response.json()[0]['price_usd'])
except (IndexError, KeyError):
raise RuntimeError('Could not parse API response.')
def check_btc():
# Get the bitcoin price
btc_price = get_btc_price()
# Iterate through each price rule, and check for matches.
for rule in load_price_rules():
# If we find a match, send the notification and delete the rule.
if rule.matches(btc_price):
rule.notify(btc_price)
rule.delete()
if __name__ == '__main__':
check_btc()
This will land you in your home directory (/home/pi), which is where your config and script reside. If you'd like you can confirm these two files exist by running ls.
At this point, you'll want to add some reasonable price rules, and then wait! After your price rule notifications fire, you'll need to add new ones by editing the price-rules-config.txt file.
Improvements
Obviously this is a demo project, but I wanted to highlight a few things we could improve on:
Use secret management to lock down the IFTTT key.
Develop a better system for creating and managing price rules.
All in all, I hope you learned something from this guide. Please leave a comment below if you have any questions or feedback!