Part 4: Adding live STEEM/SBD tickers

in #utopian-io6 years ago (edited)

banner.png

This tutorial is part of a series where different aspects of quickly creating and deploying STEEM web applications by using the Django framework as well as Beem are discussed. Knowledge of programming with Python is advised, as well as HTML and CSS, Javascript and Bootstrap.


Repository

https://github.com/django/django

What will I learn

  • Fetching STEEM and SBD ticker prices
  • Create an APIview and path
  • Parse the prices into a html
  • Automatically updating the ticker prices
  • Pitfalls with regards to scaling

Requirements

  • Python 3.7
  • Django 2.1.5
  • Beem 0.20.17
  • Gunicorn 19.9.0
  • Git
  • Heroku
  • Pipenv

Difficulty

  • basic

Tutorial

Preface

Django allows for quick development of web applications and since it uses Python as it's main programming language it also allows for easy combition with the steem-python library to develop STEEM web applications. This part is a continuation on Part 2 and continues with the code: Github. In this tutorial a live STEEM/SBD ticker will be added to the blog page.

Setup

Download the base files via Github and branch to commit e3b2d6f86b3191f9ca448ddcac43ab41f2bdc7cd to follow along side the tutorial. Install the virtual environment from the Lockfile, enter the virtual environment and install the django rest-framework that will be used for this tutorial.

$ cd ~/
$ git clone https://github.com/Juless89/django-steem-blog.git
$ cd django-steem-blog
$ git checkout e3b2d6f86b3191f9ca448ddcac43ab41f2bdc7cd
$ pipenv install
$ pipenv shell
(django-steem_blog) $ pip install djangorestframework==3.9.1

Register the rest_framework inside settings.py.

INSTALLED_APPS = [
    .
    .
    'rest_framework',   # new
}

Run the server, it should look as following:

(django-steem_blog) $ python manage.py runserver

Screenshot 2019-02-05 16.38.31.png

Fetching STEEM and SBD ticker prices

Ticker prices can either be fetched directly from a specific exchange or another option is to use the weighted average of all exchanges via a service like coinmarketcap.com. This website hosts an API that can be accessed for current ticker prices.

To display the ticker prices on the webpage an Ajax call can be made to the API directly and process the data requested. A cleaner solution would be to make this call inside a python function to process the data and only return the required data via an APIview to Ajax to parse to html. The file services.py is used to house any additional python functions.

# posts/services.py

# Get request for coinmarketcap, returns a string of the current price
def get_market_price(token):
    api_url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(token)
    response = requests.get(api_url)

    if response.status_code == 200:
        return json.loads(response.content.decode('utf-8'))[0]['price_usd']
    else:
        return None

This function requests the data for a specific ticker from coinmarketcap.com and returns only the price_usd data variable. When the response fails None is returned.

Create an APIview and path

The django rest_framework is build to handle everything with regard to RESTful API. For this tutorial the same could be accomplished by returning the data from get_market_price in a Jsonrepsonse. It is good practise to use the framework as it allows for many additional features like user authentication when this is required.

Import the APIView and response from the framework, create a new APIView TickerData and overwrite the get method. Also import get_market_price from services.py.

# posts/view.py

from .services import get_market_price
from rest_framework.views import APIView
from rest_framework.response import Response

# APIview for coinmarketcap STEEM and SBD ticker prices.
class TickerData(APIView):
    # Unused user authentication classes
    authentication_classes = []
    permission_classes = []

    # Retrieve STEEM and SBD market prices, return a dict
    def get(self, request, format=None):
        data = {
            "STEEM": '{:.3f}'.format(float(get_market_price('steem'))),
            "SBD": '{:.3f}'.format(float(get_market_price('steem-dollars'))),
        }

        return Response(data)

Register the path 'api/ticker/data/' where the api can be accessed inside urls.py.

# pages/urls.py
from .views import TickerData

urlpatters = [
  .
  path('api/ticker/data/', TickerData.as_view()),
  .
]

Access the path directly to see if everything is working. http://127.0.0.1:8000/api/ticker/data/

Screenshot 2019-02-05 17.09.03.png

Parse the prices into a html

In order to fetch and parse the data into the html Ajax is required. This code needs to be inserted into album.html between <script></script> tags. The ticker prices will be displayed in the header so place the <scripts></scripts> tags below <header></header>

Additionally a div tag has to be created with an id so that is can be referenced to. Add a new div tag inside the container that is in the header. Behind the the <a></a> tag. Set its id to ticker and the class to navbar-brand.

# templates/album.html
<div id="ticker" class="navbar-brand"></div>

<header>
  <div class="collapse bg-dark" id="navbarHeader">

  </div>
  <div class="navbar navbar-dark bg-dark shadow-sm">
    <div class="container d-flex justify-content-between">
      <a href="#" class="navbar-brand d-flex align-items-center">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2" focusable="false" aria-hidden="true"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>
        <strong>Blog</strong>
      </a>
      <div id="ticker" class="navbar-brand"></div>
    </div>
  </div>
</header>

To perform a Ajax GET request use the following code structure. The endpoint is the path to the APIView. When the request is successful a data object is returned. Which can be accessed by adding a . and the name of the requested variable. In this case data.STEEM and data.SBD. A string is created by concatenating the variables with text strings. $('#ticker').html(string); inserts the created string into the div tag with id=ticker.

# templates/album.html

var endpoint = '/api/ticker/data'

$.ajax({
  method: "GET",
  url: endpoint,
  success: function(data){
    var string = 'STEEM $' + data.STEEM + ' SBD $' + data.SBD
    $('#ticker').html(string);
  },
  error: function(error_data){
    console.log(error_data)
  }
})

Loading the webpage should now display the STEEM and SBD price tickers in the top right corner. http://127.0.0.1:8000

Screenshot 2019-02-05 17.25.58.png

Automatically updating the ticker prices

At the moment when the page is loaded the ticker prices are pulled from coinmarketcap's API and displayed on the webpage. Automatically refreshing the prices can be achieved with several changes to the script.

Create a function from the Ajax call get_ticker and then set an interval for this function setInterval("get_ticker();",5000). The time is in milliseconds so 1000 equals 1 second.

# templates/album.html

function get_ticker()
  {
    $.ajax({
    method: "GET",
    url: endpoint,
    success: function(data){
      var string = 'STEEM $' + data.STEEM + ' SBD $' + data.SBD
      $('#ticker').html(string);
    },
    error: function(error_data){
      console.log(error_data)
    }
  })
} 

setInterval("get_ticker();",5000); 

However, the code does not process until the first interval is met. To load the function initially on page load add the following line $(document).ready(get_ticker);

# templates/album.html

// Load on page load, then load every 5000/1000 seconds.
$(document).ready(get_ticker);
setInterval("get_ticker();",5000); 

Pitfalls with regards to scaling

Currently every time the ticker prices are reloaded an API call from the server to coinmarketcap is made. Most public APIs have a limit to how often they can be called from a unique IP address. Imagine a refresh time of 5 seconds and 100 users active on the webpage. This would mean that on average 100 calls would be made per second. For scaling it would be better to create a separate service that uploads the ticker prices into a database every x seconds and then an APIView that loads the data from the database instead.

Curriculum


The code for this tutorial can be found on Github!

This tutorial was written by @juliank.

Sort:  

Thank you for your contribution @steempytutorials.
After analyzing your tutorial we suggest the following:

  • Put more comments in the sections of your code, for example, the ajax call has no comments to help the reader understand what is developed.

  • This tutorial is a bit basic, in the next tutorial bring something more innovative.

Looking forward to your upcoming tutorials.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Thank you for your review, @portugalcoin! Keep up the good work!

Hi @steempytutorials!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Congratulations @steempytutorials! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You published more than 70 posts. Your next target is to reach 80 posts.

Click here to view your Board
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Support SteemitBoard's project! Vote for its witness and get one more award!

Hey, @steempytutorials!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!