292 lines
9.7 KiB
Python
292 lines
9.7 KiB
Python
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)
|
|
|