diff --git a/#database.py# b/#database.py# deleted file mode 100644 index 297a4dd..0000000 --- a/#database.py# +++ /dev/null @@ -1,35 +0,0 @@ -import json -import asyncio -from config import config -db = config['database'] - -def write_file(data): - with open(db, 'w') as f: - f.write(data) - -def get_stocks(user): - with open(db) as f: - data = json.loads(f.read()) - - if user in data.keys(): - user_data = data[user] - return user_data['portfolio'] - else: - data[user] = {"portfolio": {}} - write_file(json.dumps(data)) - return get_stocks(user) - -def add_stock(user, stock, amount): - with open(db) as f: - data = json.loads(f.read()) - if user in data.keys(): - print(data.keys()) - if stock in data[user]['portfolio'].keys(): - data[user]['portfolio'][stock] += amount - else: - data[user]['portfolio'][stock] = amount - write_file(json.dumps(data)) - return True - else: - get_stocks(user) - return add_stock(user, stock, amount) diff --git a/.#database.py b/.#database.py deleted file mode 120000 index 38440b9..0000000 --- a/.#database.py +++ /dev/null @@ -1 +0,0 @@ -socks@meme-machine.555521:1612898779 \ No newline at end of file diff --git a/database.py b/database.py index b0cfb91..f5063f2 100644 --- a/database.py +++ b/database.py @@ -21,13 +21,11 @@ def get_stocks(user): data = json.loads(f.read()) data = dict(data) - print("USER" + str(user)) if user in list(data.keys()): user_data = data[user] return user_data['portfolio'] else: - print(data) - data[user] = {"portfolio": {}} + data[user] = {"portfolio": {}, "watchlist": {}} write_file(json.dumps(data)) return get_stocks(user) @@ -35,8 +33,6 @@ def add_stock(user, stock, amount): with open(db) as f: data = dict(json.loads(f.read())) - print(data) - print(type(data)) if user in data.keys(): if stock in data[user]['portfolio'].keys(): data[user]['portfolio'][stock] = str(Decimal(amount) + Decimal( data[user]['portfolio'][stock] )) @@ -48,3 +44,63 @@ def add_stock(user, stock, amount): else: get_stocks(user) return add_stock(user, stock, amount) + + +def delete_stock(user, stock): + with open(db) as f: + data = json.loads(f.read()) + + if user in data.keys(): + # user exists + portfolio = data[user]['portfolio'] + if stock in portfolio.keys(): + # stock exists + del portfolio[stock] + data[user]['portfolio'] = portfolio + write_file(json.dumps(data)) + return get_stocks(user) + + +def get_watchlist(user): + with open(db) as f: + data = json.loads(f.read()) + + if user not in data.keys(): + get_stocks(user) + get_watchlist(user) + + return data[user]['watchlist'] + +def watch(user, stock, est_price=0): + with open(db) as f: + data = json.loads(f.read()) + + if user not in data.keys(): + get_stocks(user) + add_to_watchlist(user, list_name, stock) + + if not stock_exists(stock): + return False + + watchlist = data[user]['watchlist'] + watchlist[stock] = str(Decimal(est_price)) + data[user]['watchlist'] = watchlist + write_file(json.dumps(data)) + + return True + + +def unwatch(user, stock): + with open(db) as f: + data = json.loads(f.read()) + + if user not in data.keys(): + get_stocks(user) + return + + if not stock_exists: return + + watchlist = data[user]['watchlist'] + del watchlist[stock] + data[user]['watchlist'] = watchlist + write_file(json.dumps(data)) diff --git a/main.py b/main.py index 8bf422a..524a01b 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,10 @@ import discord -import database, table +import database, table, yfi +import table2 as t2 from discord.ext import commands from config import config +from decimal import Decimal +import typing intents = discord.Intents.default() @@ -16,22 +19,119 @@ async def ping(ctx): await ctx.send("pong!") +@bot.command(aliases=['pf']) +async def portfolio(ctx): + user = str(ctx.message.author) + return await ctx.send(str( "```" + table.generate_table(database.get_stocks(user)) + "```" )) + +@bot.command() +async def pf2(ctx): + user = str(ctx.message.author) + portfolio = database.get_stocks(user) + data = [] + for stock in portfolio.keys(): + data.append([ + stock, + Decimal(portfolio[stock]), + round(float(Decimal(portfolio[stock]) * Decimal(yfi.get_current_price(stock))), 2) + ]) + + data.append(["Total", "", round( sum([x[2] for x in data]), 2) ] ) + + image = t2.generate_table( + headers = ["Ticker", "Shares", "Value ($)"], + data = data, + title = str(user + "'s Portfolio") + ) + + + await ctx.send(file=discord.File(image, 'table.png')) + image.close() + @bot.command() async def add(ctx, stock, amount): + user = str(ctx.message.author) + stock = stock.upper() try: float(amount) except ValueError: await ctx.send("amoutn not a number") return - user = str(ctx.message.author) if database.add_stock(user, stock, amount): return await ctx.send(str( "```" + table.generate_table(database.get_stocks(user)) + "```" )) else: return await ctx.send("Stock **{0}** does not exist!".format(stock)) +@bot.command(aliases=['del']) +async def delete(ctx, stock): + stock = stock.upper() + user = str(ctx.message.author) + return await ctx.send(str( "```" + table.generate_table(database.delete_stock(user, stock)) + "```" )) +@bot.command(aliases=['wl']) +async def watchlist(ctx): + user = str(ctx.message.author) + wlist = database.get_watchlist(user) + return await ctx.send( str ( "```" + table.watchlist_table(wlist) + "```") ) + +@bot.command(aliases=['w']) +async def watch(ctx, stock, est_price: typing.Optional[int]): + + if not est_price: + est_price = 0 + + user = str(ctx.message.author) + stock = stock.upper() + + try: + float(est_price) + except ValueError: + await ctx.send("Estimated price not a number") + return + + if database.watch(user, stock, est_price): + return await ctx.send("Updated watchlist") + else: + return await ctx.send("Stock **{0}** does not exist!".format(stock)) + + +@bot.command(aliases=['uw']) +async def unwatch(ctx, stock): + user = str(ctx.message.author) + stock = stock.upper() + database.unwatch(user, stock) + return await ctx.send("Updated watchlist") + + +@bot.command() +async def wl2(ctx, user: typing.Optional[discord.Member]): + + if not user: + user = str(ctx.message.author) + else: + print(str(user)) + user = str(user) + + watchlist = database.get_watchlist(user) + data = [] + for stock in watchlist.keys(): + data.append([ + stock, + yfi.get_current_price(stock), + Decimal(watchlist[stock]), + ]) + + image = t2.generate_table( + headers = ["Ticker", "Value ($)", "Est. Price ($)"], + data = data, + title = str(user + "'s Watchlist"), + bg = 'lightgreen', border='limegreen' + ) + + await ctx.send(file=discord.File(image, 'table.png')) + image.close() bot.run(config['apikey']) diff --git a/stonks.txt b/stonks.txt index 4f23499..03dbd94 100644 --- a/stonks.txt +++ b/stonks.txt @@ -1 +1 @@ -{"Katte#3575": {"portfolio": {"AAPL": "0.37795852", "GME": "6.43", "AMD": "0.2661378", "AMZN": "0.00534034", "ETH-USD": "0.02", "HMMJ.TO": "14.14"}}, "Haedrien#6134": {"portfolio": {"UAMY": "150", "GME": "92.922", "ZOM": "100", "otlk": "100", "zsan": "100", "CTRM": "13.48"}}, "Forchex#1473": {"portfolio": {"AMC": "12", "GME": "19.7", "TGB": "56.52"}}, "Stonks#4179": {"portfolio": {"TANH": "100", "MICT": "100", "CEPU": "100", "NEXT": "100", "FTK": "100", "AVCO": "100", "CJJD": "100"}}} +{"Katte#3575": {"portfolio": {"AAPL": "0.37795852", "GME": "6.43", "AMD": "0.2661378", "AMZN": "0.00534034", "ETH-USD": "0.02", "HMMJ.TO": "14.14", "BTC-USD": "0.00038396"}, "watchlist": {"AAPL": "150", "GME": "0", "AMD": "0", "AMZN": "0"}}, "Haedrien#6134": {"portfolio": {"UAMY": "150", "GME": "92.922", "ZOM": "100", "otlk": "100", "zsan": "100", "CTRM": "13.48"}, "watchlist": {}}, "Forchex#1473": {"portfolio": {"AMC": "12", "GME": "19.7", "TGB": "56.52"}, "watchlist": {}}, "Stonks#4179": {"portfolio": {"TANH": "100", "MICT": "100", "CEPU": "100", "NEXT": "100", "FTK": "100", "AVCO": "100", "CJJD": "100", "GLDG": "100", "ORLA": "100"}, "watchlist": {}}} \ No newline at end of file diff --git a/table.png b/table.png new file mode 100644 index 0000000..eb4fb83 Binary files /dev/null and b/table.png differ diff --git a/table.py b/table.py index 5d667b8..aa1025d 100644 --- a/table.py +++ b/table.py @@ -1,26 +1,12 @@ from tabulate import tabulate from decimal import Decimal -import yfinance as yf - - -def get_current_price(ticker): - yf_obj = yf.Ticker(ticker) - todays_data = yf_obj.history(period='1d') - return round(todays_data['Close'][0], 2) - - -stonks = { - 'MSFT': 4.3, - 'AAPL': 13, - 'GME' : 212 -} - +import yfi as y def generate_table(stonks): table_data = [] total = 0 for ticker in stonks.keys(): - price = get_current_price(ticker) + price = y.get_current_price(ticker) shares_count = stonks[ticker] table_data.append([ticker, shares_count, round(Decimal(price) * Decimal(stonks[ticker]), 2)]) total += (Decimal(price) * Decimal(stonks[ticker])) @@ -28,3 +14,18 @@ def generate_table(stonks): table_data.append(['Total', '', round(total, 2)]) return str( tabulate(table_data, ['Ticker', 'Shares', 'Value ($)'], tablefmt="pretty") ) + + +def watchlist_table(watchlist): + + table_data = [] + header = ['Ticker', 'Current Price ($)', 'Estimated Price ($)'] + + for stonk in watchlist.keys(): + table_data.append([ + stonk, + y.get_current_price(stonk), + watchlist[stonk], + ]) + + return str( tabulate( table_data, header, tablefmt="pretty" ) ) diff --git a/table2.py b/table2.py new file mode 100644 index 0000000..24eddcd --- /dev/null +++ b/table2.py @@ -0,0 +1,76 @@ +import matplotlib.pyplot as plt +import matplotlib, io +from datetime import datetime + + +def generate_table(headers, data, title="", bg='skyblue', border='steelblue'): + timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S") + + font = {'family' : 'monospace', + 'weight' : 'normal', + 'size' : 12} + + matplotlib.rc('font', **font) + + title_text = title + footer_text = timestamp + fig_background_color = bg + fig_border = border + + column_headers = headers + + + if data: + cell_text = [] + for row in data: + cell_text.append([x for x in row]) + else: + cell_text = [["No Data"] + ["" for x in range(len(headers)-1)]] + + + # Create the figure. Setting a small pad on tight_layout + # seems to better regulate white space. Sometimes experimenting + # with an explicit figsize here can produce better outcome. + + image_height = (( 0.9375 + ( 0.40625 * ( len(data) + 1) ) ) * 160) + image_width = 6 * 160 + + plt.figure(linewidth=2, + edgecolor=fig_border, + facecolor=fig_background_color, + tight_layout={'pad':1}, + dpi=160, + figsize=(image_width/160, image_height/160) + ) + + # Add a table at the bottom of the axes + the_table = plt.table(cellText=cell_text, + colLabels=column_headers, + loc='center')# Scaling is the only influence we have over top and bottom cell padding. + + # Make the rows taller (i.e., make cell y scale larger). + the_table.scale(1, 2) + + # Hide axes + ax = plt.gca() + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + + # Hide axes border + plt.box(on=None) + + # Add title + plt.suptitle(title_text) + + # Add footer + plt.figtext(((image_width - 15)/image_width), 1-((image_height - 15)/image_height), footer_text, horizontalalignment='right', size=12, weight='light') + + # Force the figure to update, so backends center objects correctly within the figure. + # Without plt.draw() here, the title will center on the axes and not the figure. + plt.draw() + + # Create image. plt.savefig ignores figure edge and face colors, so map them. + image_buffer = io.BytesIO() + plt.savefig(image_buffer, format='png') + image_buffer.seek(0) + return image_buffer diff --git a/yfi.py b/yfi.py new file mode 100644 index 0000000..ec78026 --- /dev/null +++ b/yfi.py @@ -0,0 +1,8 @@ +import yfinance as yf + +def get_current_price(ticker): + yf_obj = yf.Ticker(ticker) + todays_data = yf_obj.history(period='1d') + return round(todays_data['Close'][0], 2) + +