Back to search

Track Bitcoin prices on a live graph with Python

  • Olayinka Omole
June 24th, 2018
You will need Python 3+ installed on your machine. Basic knowledge of Python, Flask and JavaScript will be helpful.

Graphs and charts are great for representing information in a clear and concise way. They can be used in various apps to show data to users when needed. Quickly changing data can be better represented using realtime graphs and charts as users can quickly see both current and historical data easily.

In this tutorial, we will be making use of Pusher Channels, Plotly and Flask to build a simple app for displaying the price of a Bitcoin in a realtime graph and bar chart.

Here is what the final app will look like:

python-live-graph-bitcoin-demo

Prerequisites

To follow along properly, basic knowledge of Python, Flask and JavaScript (ES6 syntax) is needed. You will also need to install Python and virtualenv locally.

Virtualenv is a tool that helps us create isolated Python environments. This makes it possible for us to install dependencies (like Flask) in an isolated environment, and not pollute our global packages directory. To install virtualenv:

    pip install virtualenv

Setup and configuration

Installing Flask

As stated earlier, we will be developing using Flask, a web framework for Python. In this step, we will activate a virtual Python environment and install Flask for use in our project.

To activate a virtual environment:

    mkdir realtime-graph
    cd realtime-graph
    virtualenv .venv
    source .venv/bin/activate

Note: To activate the virtual environment on a Windows machine, you would need to enter the path to the activate file (in .venv/Scripts) in Powershell / command prompt. You can find more info here.

To install Flask:

    pip install flask

We will also need the Requests library. Let us install it now:

    pip install requests

Setting up Pusher

Pusher is a service that makes it easy for us to supercharge our web and mobile applications with realtime updates. We will be using it primarily for powering the realtime updates to our graphs. Head over to Pusher.com and register for a free account, if you don’t already have one.

Next, create an app on the dashboard and copy out the app credentials (App ID, Key, Secret and Cluster), as we would be needing these in our app.

Now we can install the Pusher Python library to help our backend communicate with the Pusher service:

    pip install pusher

Installing Plotly

Plotly is a tool that helps to easily display visual data on the web. According to their website:

Plotly creates leading open source tools for composing, editing, and sharing interactive data visualization via the Web.

We will be making use of Plotly to create our graph and chart. To install Plotly to our app:

    pip install plotly

File and folder structure

Here is the folder structure for the app. We will only limit it to things necessary so as to avoid bloat. Let us go ahead and create the following files and folders:

        ├── realtime-graph
            ├── app.py
            └── templates
                └── index.html

The templates folder contains our index.html template file, while app.py will house all our server-side code.

Building the backend

Now, we can start writing server-side code to perform our various app functions. Our app will get the prices for Bitcoin every 10 seconds. We will use Pusher to broadcast an event, along with the new prices every time data is retrieved.

We will start by importing the needed modules, configuring the Pusher object, and initialising some needed variables:

    # ./app.py
    from flask import Flask, render_template
    from apscheduler.schedulers.background import BackgroundScheduler
    from apscheduler.triggers.interval import IntervalTrigger
    from pusher import Pusher
    import requests, json, atexit, time, plotly, plotly.graph_objs as go

    # create flask app
    app = Flask(__name__)

    # configure pusher object
    pusher = Pusher(
        app_id='YOUR_APP_ID',
        key='YOUR_APP_KEY',
        secret='YOUR_APP_SECRET',
        cluster='YOUR_APP_CLUSTER',
        ssl=True
    )

    # define variables for data retrieval
    times = []
    currencies = ["BTC"]
    prices = {"BTC": []}

In the code block above, first we import the needed modules and libraries, including the Pusher and Plotly libraries. We also configure the Pusher object with the credentials gotten from the Pusher dashboard. Remember to replace YOUR_APP_ID and similar values with the actual values for your own app.

Some variables are also defined to hold values we will need later in our app. times stores the values of the time when we retrieve price data in a list. currencies holds the list of currencies we will be fetching data for. In our case, this is just BTC but you can add any number of currencies you want. prices is a dictionary that holds the list of prices for currency defined.

Next, let us define a simple route to serve our app’s view:

    # ./app.py
    # ...

    @app.route("/")
    def index():
        return render_template("index.html")

In the code block above, we use Flask’s render_template() function to serve index.html from the ./templates folder on the index route.

Now we can get to the core of our app, which is creating a function that will retrieve Bitcoin prices and then broadcast that data in graph and chart form. Let us update app.py with the function:

    # ./app.py
    # ...

    def retrieve_data():
        # create dictionary for saving current prices
        current_prices = {}
        for currency in currencies:
            current_prices[currency] = []
        # append new time to list of times
        times.append(time.strftime('%H:%M:%S'))

        # make request to API and get response as object
        api_url = "https://min-api.cryptocompare.com/data/pricemulti?fsyms={}&tsyms=USD".format(",".join(currencies))
        response = json.loads(requests.get(api_url).content)

        # append new price to list of prices for graph
        # and set current price for bar chart
        for currency in currencies:
            price = response[currency]['USD']
            current_prices[currency] = price
            prices[currency].append(price)

        # create an array of traces for graph data
        graph_data = [go.Scatter(
            x=times,
            y=prices.get(currency),
            name="{} Prices".format(currency)
        ) for currency in currencies]

        # create an array of traces for bar chart data
        bar_chart_data = [go.Bar(
            x=currencies,
            y=list(current_prices.values())
        )]

        data = {
            'graph': json.dumps(list(graph_data), cls=plotly.utils.PlotlyJSONEncoder),
            'bar_chart': json.dumps(list(bar_chart_data), cls=plotly.utils.PlotlyJSONEncoder)
        }

        # trigger event
        pusher.trigger("crypto", "data-updated", data)

In the code block above, we define a function retrieve_data() that does the following:

  1. Makes a request to a remote API to retrieve current Bitcoin prices. We make use of the CryptoCompare API and the Requests library.
  2. Generates traces for the graph and bar chart using the Plotly plotly.graph_objs.Scatter and plotly.graph_objs.Bar.
  3. Encode the graph and bar chart data as JSON using the Plotly Json Encoder.
  4. Trigger a data-updated event using the configured pusher object, broadcasting the needed data on the crypto channel.

We use the configured pusher object for broadcasting events on specific channels. To broadcast an event, we use the trigger() method with the following syntax:

    pusher.trigger('a_channel', 'an_event', {'some': 'data'})

Note: You can find the docs for the Pusher Python library here.

Pusher also grants us the ability to trigger events on various types of channels including Public, Private and Presence channels. Read about them here.

Scheduling the data retrieval function

A major part of our app is making sure our data retrieval functions runs at a 10 second interval, so as to keep users updated of the most current prices. To create this schedule, we make use of AppScheduler. To install AppScheduler:

    pip install apscheduler

The following piece of code will register the job and run our retrieve_data() function every 10 seconds:

    # ./app.py
    # ...

    # create schedule for retrieving prices
    scheduler = BackgroundScheduler()
    scheduler.start()
    scheduler.add_job(
        func=retrieve_data,
        trigger=IntervalTrigger(seconds=10),
        id='prices_retrieval_job',
        name='Retrieve prices every 10 seconds',
        replace_existing=True)
    # Shut down the scheduler when exiting the app
    atexit.register(lambda: scheduler.shutdown())

Running the Flask app

Finally, to start the app in debug mode, while disabling the auto reloader:

    # ./app.py
    # ...

    # run Flask app
    app.run(debug=True, use_reloader=False)

Note: We disable the auto reloader so as to prevent our scheduled function from running twice at every interval. You can read more on this here.

Creating our app view

We will now write some markup and JavaScript code to display the graph and chart to our users. Editing the index.html file:

    <!-- ./templates/index.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>CryptoLiveChart!</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
        <style>
            .chart {
                height: 800px;
            }
        </style>
    </head>
    <body>
    <section class="section">
        <div class="container">
            <h1 class="title">Welcome to <strong>Crypto</strong>LiveChart!</h1>
            <p class="subtitle">View live prices for <strong>Bitcoin</strong> and <strong>Ethereum</strong> in real time!</p>
            <hr>
            <div class="columns">
                <div class="column">
                    <h5 class="title is-6">Prices (in USD)</h5>
                    <div id="price_chart" class="chart">
                        Graph
                    </div>
                </div>
                <div class="column">
                    <h5 class="title is-6">Market Cap</h5>
                    <div id="market_cap_chart" class="chart">
                        Bar Chart
                    </div>
                </div>
            </div>
        </div>
    </section>
    </body>
    </html>

The above code contains the basic markup for the homepage. We imported Bulma (a cool CSS framework) to take advantage of some pre-made styles.

Next, we will write some JavaScript code to display our charts:

    <!-- ./templates/index.html -->
    <!-- ... -->

      <!-- D3.js -->
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
      <!-- jQuery -->
      <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
      <!-- Plotly.js -->
      <script src="https://d14fo0winaifog.cloudfront.net/plotly-basic.js"></script>
      <!-- import Pusher-js library -->
      <script src="https://js.pusher.com/4.1/pusher.min.js"></script>
      <script type="text/javascript">
          // connect to Pusher
          const pusher = new Pusher('YOUR_APP_KEY', {
            cluster: 'YOUR_APP_CLUSTER', // gotten from Pusher app dashboard
            encrypted: true // optional
          });
          // subscribe to crypto channel
          const channel = pusher.subscribe('crypto')
          // listen for relevant events
          channel.bind('data-updated', data => {
              const graph = JSON.parse(data.graph);
              Plotly.newPlot('price_chart', graph);
              const bar_chart = JSON.parse(data.bar_chart);
              Plotly.newPlot('market_cap_chart', bar_chart);
          });
      </script>
    </body>
    </html>

In the code above, first we import the needed libraries - D3.js, Plotly and Pusher. Then we do the following:

  1. Connect to our Pusher app by creating an instance with new Pusher(). Remember to replace YOUR_APP_KEY and YOUR_APP_CLUSTER with the actual values gotten from your dashboard.
  2. Subscribe to the crypto channel on which we will be broadcasting events with pusher.subscribe()
  3. We bind the data-updated event on the channel and define a callback function to plot our graph and chart anytime data is received.

And that’s it! To run our app:

    python app.py

Conclusion

In this tutorial we have learned how to create beautiful realtime charts and graphs in our Flask Apps using Plotly and Pusher. You can check out the Plotly Python documentation to see how to create other graphs quickly in Python!

You can find the entire code for this tutorial on GitHub.

  • Channels

© 2018 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 28 Scrutton Street, London EC2A 4RP.