gitschwifty/pywit

View on GitHub
pywit/pricefeeds.py

Summary

Maintainability
A
2 hrs
Test Coverage
import requests
import time

from .config import Configuration
from .interface import SteemExplorer
from .logger import Logger


class PriceFeed():
    def __init__(self, stm: SteemExplorer):
        self.stm = stm
        self.conf = stm.conf
        self.log = stm.log
        self.min_spread = 2.0

    def get_pair(self, pair):
        self.log.add_func("PriceFeed:get_pair")
        if pair == "SU":
            # steem/usd- full price
            sb = self.get_prices(1)
            bu = self.get_pair("BU")
            btu = self.get_pair("BTU")

            #multiply and average and voila
            su = []
            for i in sb:
                p = float(i) * bu
                su.append(p)
                p = float(i) * btu
                su.append(p)

            #print prices in su
            for i in su:
                logstr = "STEEM to USD Price: {:.4f} USD per STEEM".format(i)
                self.log.log(logstr, 2)

            avg = self.get_avg(su)
            logstr = "Final STEEM to USD Price: {:.3f} USD per STEEM".format(
                avg)
            self.log.log(logstr, 1)

            self.log.pop_func()
            return avg

        elif pair == "BTU":
            # btc/tether/usd price: gets bt and tu and returns b/u
            bt = self.get_pair("BT")
            tu = self.get_pair("TU")

            # multiply and return
            btu = bt * tu
            logstr = ("Bitcoin to USD Price (Proxied through USDT):"
                " {:.4f} USD per BTC").format(
                btu)
            self.log.log(logstr, 2)

            self.log.pop_func()
            return btu

        elif pair == "BU":
            # btc/usd
            p = self.get_prices(2)[0]
            logstr = "Bitcoin to USD Price: {:.4f} USD per BTC".format(p)
            self.log.log(logstr, 2)

            self.log.pop_func()
            return p

        elif pair == "BT":
            # btc/usdt
            p = self.get_prices(3)

            for i in p:
                logstr = "Bitcoin to USDT Price: {:.4f} USDT per BTC".format(i)
                self.log.log(logstr, 2)

            # list prices off
            avg = self.get_avg(p)
            logstr = "Average Bitcoin to USDT Price: {:.4f} USDT per BTC".format(
                avg)
            self.log.log(logstr, 2)

            self.log.pop_func()
            return avg

        elif pair == "TU":
            # usdt/usd
            p = self.get_prices(4)

            for i in p:
                logstr = "USDT to USD Price: {:.4f} USD per USDT".format(i)
                self.log.log(logstr, 2)

            avg = self.get_avg(p)
            logstr = "Average USDT to USD Price: {:.4f} USD per USDT".format(
                avg)
            self.log.log(logstr, 2)

            self.log.pop_func()
            return avg

        else:
            # error
            self.log.log('Error: Invalid Pair Type', 1)
            self.log.pop_func()

    # same order as get_pair
    def get_prices(self, pair):
        self.log.add_func("PriceFeed:get_prices")
        if pair == 1:
            # steem/btc prices
            prices = []

            try:
                self.log.log("Querying Bittrex", 2)
                try:
                    r = requests.get(
                        'https://bittrex.com/api/v1.1/public/getmarketsummary?market=BTC-STEEM',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['result'][0]
                        prices.append(float(d['Last']))
                        logstr = "Bittrex: {:.8f} BTC/STEEM".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)

                self.log.log("Querying Binance", 2)
                try:
                    r = requests.get(
                        'https://api.binance.com/api/v1/ticker/24hr', timeout=30)
                    if r.status_code == 200:
                        d = [x for x in r.json() if x['symbol'] == 'STEEMBTC'][0]
                        prices.append(float(d['lastPrice']))
                        logstr = "Binance: {:.8f} BTC/STEEM".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
                

                self.log.log("Querying Poloniex", 2)
                try:
                    r = requests.get(
                        'https://poloniex.com/public?command=returnTicker',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['BTC_STEEM']
                        prices.append(float(d['last']))
                        logstr = "Poloniex: {:.8f} BTC/STEEM".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
                

                if len(prices) == 3:
                    diff = self.get_percent_difference(prices[0], prices[2])
                    difftwo = self.get_percent_difference(prices[1], prices[2])
                    diffavg = (diff + difftwo) / 2

                    if diffavg > self.min_spread:
                        prices.pop()
                        self.log.log("Removed Poloniex for high variance.", 2)
            except KeyError:
                self.log.log("Key Error Occured.", 1)
                self.log.pop_func()
                return
            self.log.pop_func()
            return prices
        elif pair == 2:
            # btc/usd straight prices
            prices = []
            # only bittrex to query

            try:
                self.log.log("Querying Bittrex", 2)
                try:
                    r = requests.get(
                        'https://bittrex.com/api/v1.1/public/getmarketsummary?market=USD-BTC',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['result'][0]
                        prices.append(float(d['Last']))
                        logstr = "Bittrex: {:.4f} BTC/USD".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
            except KeyError:
                self.log.log("Key Error Occured.", 1)
                self.log.pop_func()
                return
            self.log.pop_func()
            return prices
        elif pair == 3:
            # btc/usdt price
            prices = []

            try:
                self.log.log("Querying Poloniex", 2)
                try:
                    r = requests.get(
                        'https://poloniex.com/public?command=returnTicker',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['USDT_BTC']
                        prices.append(float(d['last']))
                        logstr = "Poloniex: {:.4f} USDT/BTC".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)

                self.log.log("Querying Bittrex", 2)
                try:
                    r = requests.get(
                        'https://bittrex.com/api/v1.1/public/getmarketsummary?market=USDT-BTC',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['result'][0]
                        prices.append(float(d['Last']))
                        logstr = "Bittrex: {:.4f} USDT/BTC".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)

                self.log.log("Querying Binance", 2)
                try:
                    r = requests.get(
                        'https://api.binance.com/api/v1/ticker/24hr', timeout=30)
                    if r.status_code == 200:
                        d = [x for x in r.json() if x['symbol'] == 'BTCUSDT'][0]
                        prices.append(float(d['lastPrice']))
                        logstr = "Binance: {:.4f} USDT/BTC".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
            except KeyError:
                self.log.log("Key Error Occured.", 1)
                self.log.pop_func()
                return
            self.log.pop_func()
            return prices
        elif pair == 4:
            # usdt/usd price
            # btc/usdt price
            prices = []

            try:
                self.log.log("Querying Bittrex", 2)
                try:
                    r = requests.get(
                        'https://bittrex.com/api/v1.1/public/getmarketsummary?market=USD-USDT',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['result'][0]
                        prices.append(float(d['Last']))
                        logstr = "Bittrex: {:.4f} USD/USDT".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
            
                self.log.log("Querying Kraken", 2)
                try:
                    r = requests.get(
                        'https://api.kraken.com/0/public/Ticker?pair=USDTZUSD',
                        timeout=30)
                    if r.status_code == 200:
                        d = r.json()['result']['USDTZUSD']
                        prices.append(float(d['c'][0]))
                        logstr = "Kraken: {:.4f} USD/USDT".format(prices[-1])
                        self.log.log(logstr, 2)
                except requests.exceptions.RequestException as e:
                    self.log.log("A request exception occurred.", 1)
                
            except KeyError:
                self.log.log("Key Error Occured.", 1)
                self.log.pop_func()
                return
            self.log.pop_func()
            return prices
        else:
            # error
            print("Error: Invalid Pair Type Passed.")
            self.log.pop_func()

    def get_avg(self, d):
        self.log.add_func("PriceFeed:get_avg")
        avg = 0
        for i in d:
            avg += i
        self.log.pop_func()
        return avg / len(d)

    def get_percent_difference(self, num, numTwo):
        self.log.add_func("PriceFeed:get_percent_difference")
        diff = num - numTwo
        if diff < 0:
            diff = -diff
        perc = (diff)/((num + numTwo)/2) * 100
        self.log.pop_func()
        return perc

    def do_feed(self, pnow):
        self.log.add_func("PriceFeed:do_feed")
        p = self.get_pair("SU")
        per = self.get_percent_difference(self.last_price, p)
        if per > self.min_spread or self.pub_today == 24 or pnow:
            if per < 25 and self.last_price != 0:
                self.stm.pubfeed(p)
                self.last_price = p
                logstr = "Published feed %.3f USD/Steem." % p
                self.log.log(logstr, 1)
                self.pub_today = 0
            else:
                logstr = ("Percent difference {:.2f}% greater than 25%," 
                    " not publishing.").format(
                    per)
                self.log.log(logstr, 1)
        else:
            logstr = ("Percent difference {:.2f}% lower than minimum spread" 
                " {:.2f}%, not publishing.").format(
                per, self.min_spread)
            self.log.log(logstr, 1)
            self.pub_today += 1
        self.log.pop_func()

    def run_feeds(self, slptime=6000, spread=2.0, pnow=False):
        self.log.add_func("PriceFeed:run_feeds")
        if self.stm.locked():
            if not self.stm.unlock_wallet():
                print("You must unlock your wallet to run price feed.")
                return
        self.pub_today = 0
        self.min_spread = spread
        self.last_price = self.stm.get_price_feed()
        logstr = ("Running price feeds with minimum spread {:.2f}"
                " and sleep time {:.2f} minutes.").format(
            self.min_spread, (slptime / 60))
        self.log.log(logstr, 1)
        while True:
            try:
                self.do_feed(pnow)
                if pnow:
                    pnow = False
                time.sleep(slptime)
            except KeyboardInterrupt:
                self.log.pop_func()
                print(" ")
                return