import asyncio import discord from discord.ext import commands from urllib import request import json, requests import time import random import statistics class Cryptocoin(object): """Voor al uw crypto currency advies.""" def __init__(self, bot): self.bot = bot self.voice_states = {} def __check(self, ctx): #Todo: Is dit het geld-verdienen kanaal? return True #borrowed from: http://jmduke.com/posts/basic-linear-regressions-in-python/ def basic_linear_regression(self, x, y): # Basic computations to save a little time. length = len(x) sum_x = sum(x) sum_y = sum(y) # Sx^2, and Sxy respectively. sum_x_squared = sum(map(lambda a: a * a, x)) sum_of_products = sum([x[i] * y[i] for i in range(length)]) # Magic formulae! a = (sum_of_products - (sum_x * sum_y) / length) / (sum_x_squared - ((sum_x ** 2) / length)) b = (sum_y - a * sum_x) / length return a, b #Relative Strength Index (RSI) def rsi(self, datapoints): totalGain = 0.0001 totalLoss = 0.0001 n_deltas = len(datapoints)-1 for x in range(0, n_deltas): delta = datapoints[x+1] - datapoints[x] if delta > 0: totalGain += delta else: totalLoss -= delta #losses should also be positive RS = (totalGain / n_deltas) / (totalLoss / n_deltas) return 100 - ( 100 / (1 + RS) ) #get the stability based on the standard deviation #the closer to 1, the better. (can be < 0, by the way. sue me.) def getCoinStability(self, history): histMean = statistics.mean(history) if(histMean == 0): return 0 return 1 - (statistics.stdev(history) / histMean) def getCoinPrice(self, coinId, currencyId="USD", time="now"): if (time == "now"): #for the most current price, don't use the history API url = "https://min-api.cryptocompare.com/data/price?tsyms=" + currencyId + "&fsym=" + coinId else: url = "https://min-api.cryptocompare.com/data/pricehistorical?tsyms=" + currencyId + "&fsym=" + coinId + "&ts=" + str(time) response = requests.get(url) try: priceData = json.loads(response.content.decode('utf-8')) if (time == "now"): return priceData[currencyId] else: return priceData[coinId][currencyId] except: return -1 #dermines the expected growth of coin def analyseCoin(self, coinId): N_DATAPOINTS = 12 TIME_BETWEEN_DATAPOINTS = 86400 * 7 #one week #Get the price history: history = [] for j in range(0, N_DATAPOINTS-1): history.append(self.getCoinPrice(coinId, "USD", int(time.time()) - (N_DATAPOINTS-j)*TIME_BETWEEN_DATAPOINTS)) history.append(self.getCoinPrice(coinId, "USD")) #now #Check the growth. Do some linear regression growFactorLongTerm, dummy = self.basic_linear_regression(range(0, N_DATAPOINTS), history) growFactorShortTerm, dummy = self.basic_linear_regression(range(0, 3), [ history[N_DATAPOINTS-3], history[N_DATAPOINTS-2], history[N_DATAPOINTS-1] ]) if (history[N_DATAPOINTS-1] == 0): growPercentageLongTerm = 0 growPercentageShortTerm = 0 else: growPercentageLongTerm = growFactorLongTerm / history[N_DATAPOINTS-1] growPercentageShortTerm = growFactorShortTerm / history[N_DATAPOINTS-1] growPercentage = growPercentageLongTerm*0.3 + growPercentageShortTerm*0.7 #weighted average stability = self.getCoinStability(history) return growPercentage, stability, history #TODO: # - iets met stabiliteit? # - https://en.wikipedia.org/wiki/Head_and_shoulders_(chart_pattern) # - neural networks??? #will return some random advice about a semi-random crypto coin def getRandomCoinAdvice(self): #get all the coins! coinlistUrl = "https://min-api.cryptocompare.com/data/all/coinlist" coinlistResponse = requests.get(coinlistUrl) popularCoins = [ {"Symbol" : "BTC", "Name" : "BitCoin"}, {"Symbol" : "ETH", "Name" : "Ethereum"}, {"Symbol" : "ETC", "Name" : "Ethereum Classic"}, {"Symbol" : "LTC", "Name" : "LiteCoin"}, {"Symbol" : "XMR", "Name" : "Monero"}, {"Symbol" : "XRP", "Name" : "Ripple"}, {"Symbol" : "DOGE", "Name" : "Dogecoin"}, {"Symbol" : "NLG", "Name" : "Gulden"} ] if (coinlistResponse.ok): coinlistData = json.loads(coinlistResponse.content.decode('utf-8')) coinlist = [] for coin in coinlistData["Data"]: coinlist.append({ "Symbol" : coinlistData["Data"][coin]["Symbol"] , "Name" : coinlistData["Data"][coin]["CoinName"] }) #Analyse until you've found something interesting for i in range(0, 99): #pick a random coin if (random.randint(0, 4) == 4): #kans van 1 op 5 dat we naar een populaire coin kijken randIndex = random.randint(0, len(popularCoins)-1) tempId = popularCoins[randIndex]["Symbol"] tempName = popularCoins[randIndex]["Name"] else: randIndex = random.randint(0, len(coinlist)-1) tempId = coinlist[randIndex]["Symbol"] tempName = coinlist[randIndex]["Name"] #analyse: growPercentage, stability, tempHistory = self.analyseCoin(tempId) #For the first few iterations we're picky if (growPercentage > 0.1 and stability > 0.5): return (tempName + " (" + tempId + ") gaat to the moon!") if (growPercentage > 0.06 and stability > 0.25): return ("Ik zou zeker een paar " + tempName + " (" + tempId + ") kopen.") if (i > 2): #Later, negative advices are also acceptable... if (growPercentage < -0.2): return ("Ik zou zeker " + tempName + " (" + tempId + ") afraden!") if (growPercentage > 0.015 and stability > 0.15): return ("Ken je " + tempName + " (" + tempId + ") al? Best leuk") if(i > 4): #After a while, we're happy to give less useful advice if (growPercentage > 0.008): return (tempName + " (" + tempId + ") kan interessant worden...") if (growPercentage < -0.06): return ("Als je toevallig " + tempName + " (" + tempId + ") hebt: verkopen.") if(i > 5): #Anything goes. We're desperate. if (tempHistory[ len(tempHistory)-1 ] == 0): return (tempId + " is echt niks waard...") if (growPercentage > 0.005): return (tempName + " (" + tempId + ") is een crypto currency. Wist je dat?") time.sleep(0.1) #don't overload the API return "Sorry. De crypto adviezen zijn uitverkocht vandaag." else: raise Exception("API error") #user functions below @commands.command(pass_context=True) @asyncio.coroutine def coinprice(self, ctx, coinId: str, currencyId: str="USD"): """Geeft de huidige prijs van de desbetreffende crypto currency Bijv: !coinprice BTC Of voor de echte (Erik) Hollanders: !coinprice NLG EUR """ allowedCurrencies = ["USD", "EUR", "JPY", "GBP", "CNY", "CAD", "BTC"] coinId = coinId.upper() currencyId = currencyId.upper() if (currencyId not in allowedCurrencies): yield from ctx.channel.send("Valuta " + currencyId + " ken ik niet. :disappointed: ") return price = self.getCoinPrice(coinId, currencyId) if (price == -1): yield from ctx.channel.send("Die cryptocoin ken ik niet... :frowning2: ") return yield from ctx.channel.send(coinId + " is nu " + str(price) + " " + currencyId + " waard.") @commands.command(pass_context=True) @asyncio.coroutine def coinadvice(self, ctx, coinId: str=""): """Voor al uw adviezen in monopolygeld Vraag Stroop's mening over een specifieke coin: !coinadvice NLG Of vraag gewoon advies in het algemeen: !coinadvice (Over deze laatste optie moet soms even nagedacht worden) Stroopwafel en zijn development team nemen geen verantwoordelijkheid voor eventuele financiele schade en verwoeste levens. """ #Geen specieke coin? Doe random. if(coinId == ""): yield from ctx.channel.send( self.getRandomCoinAdvice() ) return coinId = coinId.upper() growPercentage, coinStability, coinHistory = self.analyseCoin(coinId) coinRsi = self.rsi(coinHistory) #TODO, get more recent data to feed the RSI message = "" if (growPercentage < -0.04): if (coinRsi > 70): message = "Sell! Sell! Sell! Aan " + coinId + " heb je niks meer." elif (coinStability < 0.3): message = coinId + " takelt op lange termijn af en is instabiel. Net als je moeder." elif (coinRsi < 30): message = "Op de lange termijn is " + coinId + " waardeloos, maar wacht nog even met verkopen." else: message = "Als je " + coinId + " hebt, verkopen die handel. Daar heb je op de lange termijn niks aan." elif (growPercentage < 0): message = coinId + " gaat geen winnaar worden. " if (coinRsi > 70): message += "Ditchen." elif (coinRsi < 30): message += "Maar hou hem nog even vast." elif (growPercentage < 0.025): if (coinStability > 0.6): message = coinId + " lijkt redelijk stabiel. " if (coinRsi < 30): message += "Bovendien een goed moment om te kopen." elif (coinRsi > 70): message = "Ik zou " + coinId + " verkopen." else: message = "Niks bijzonders, die " + coinId elif (growPercentage < 0.08): if (coinStability > 0.45): message = coinId + " is een stabiele groeier. " if (coinRsi < 30): message += "Nu kopen!" elif (coinStability < 0.2): message = coinId + " groeit lekker, maar is instabiel." else: message = coinId + " is aan het groeien... " if (coinRsi > 70): message += "Hij lijkt overbought, dus je kan nu verkopen." else: if (coinRsi < 30 and coinStability > 0.4): message = "TO THE MOON! Nu " + coinId + " kopen!!" elif (coinStability > 0.7): message = coinId + " is op de lange termijn erg sterk en stabiel!" elif (coinRsi < 30): message = "Ik raad sterk aan om " + coinId + " te kopen." elif (coinRsi < 70): message = coinId + " groeit wel erg hard. Wellicht overbought?" else: message = coinId + " gaat toenemen in waarde... " if (coinStability < 0.3): message += "Denk ik?" yield from ctx.channel.send(message)