- Added delete command
- added watchlists - added $pf2 and $wl2 to get image format table outputs - moving yahoo finance commands to separate file
This commit is contained in:
parent
f3a622b95f
commit
35fc806327
9 changed files with 265 additions and 60 deletions
|
@ -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)
|
|
|
@ -1 +0,0 @@
|
||||||
socks@meme-machine.555521:1612898779
|
|
66
database.py
66
database.py
|
@ -21,13 +21,11 @@ def get_stocks(user):
|
||||||
data = json.loads(f.read())
|
data = json.loads(f.read())
|
||||||
|
|
||||||
data = dict(data)
|
data = dict(data)
|
||||||
print("USER" + str(user))
|
|
||||||
if user in list(data.keys()):
|
if user in list(data.keys()):
|
||||||
user_data = data[user]
|
user_data = data[user]
|
||||||
return user_data['portfolio']
|
return user_data['portfolio']
|
||||||
else:
|
else:
|
||||||
print(data)
|
data[user] = {"portfolio": {}, "watchlist": {}}
|
||||||
data[user] = {"portfolio": {}}
|
|
||||||
write_file(json.dumps(data))
|
write_file(json.dumps(data))
|
||||||
return get_stocks(user)
|
return get_stocks(user)
|
||||||
|
|
||||||
|
@ -35,8 +33,6 @@ def add_stock(user, stock, amount):
|
||||||
|
|
||||||
with open(db) as f:
|
with open(db) as f:
|
||||||
data = dict(json.loads(f.read()))
|
data = dict(json.loads(f.read()))
|
||||||
print(data)
|
|
||||||
print(type(data))
|
|
||||||
if user in data.keys():
|
if user in data.keys():
|
||||||
if stock in data[user]['portfolio'].keys():
|
if stock in data[user]['portfolio'].keys():
|
||||||
data[user]['portfolio'][stock] = str(Decimal(amount) + Decimal( data[user]['portfolio'][stock] ))
|
data[user]['portfolio'][stock] = str(Decimal(amount) + Decimal( data[user]['portfolio'][stock] ))
|
||||||
|
@ -48,3 +44,63 @@ def add_stock(user, stock, amount):
|
||||||
else:
|
else:
|
||||||
get_stocks(user)
|
get_stocks(user)
|
||||||
return add_stock(user, stock, amount)
|
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))
|
||||||
|
|
104
main.py
104
main.py
|
@ -1,7 +1,10 @@
|
||||||
import discord
|
import discord
|
||||||
import database, table
|
import database, table, yfi
|
||||||
|
import table2 as t2
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from config import config
|
from config import config
|
||||||
|
from decimal import Decimal
|
||||||
|
import typing
|
||||||
|
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
|
|
||||||
|
@ -16,22 +19,119 @@ async def ping(ctx):
|
||||||
await ctx.send("pong!")
|
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()
|
@bot.command()
|
||||||
async def add(ctx, stock, amount):
|
async def add(ctx, stock, amount):
|
||||||
|
user = str(ctx.message.author)
|
||||||
|
stock = stock.upper()
|
||||||
try:
|
try:
|
||||||
float(amount)
|
float(amount)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await ctx.send("amoutn not a number")
|
await ctx.send("amoutn not a number")
|
||||||
return
|
return
|
||||||
|
|
||||||
user = str(ctx.message.author)
|
|
||||||
if database.add_stock(user, stock, amount):
|
if database.add_stock(user, stock, amount):
|
||||||
return await ctx.send(str( "```" + table.generate_table(database.get_stocks(user)) + "```" ))
|
return await ctx.send(str( "```" + table.generate_table(database.get_stocks(user)) + "```" ))
|
||||||
else:
|
else:
|
||||||
return await ctx.send("Stock **{0}** does not exist!".format(stock))
|
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'])
|
bot.run(config['apikey'])
|
||||||
|
|
|
@ -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": {}}}
|
BIN
table.png
Normal file
BIN
table.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
33
table.py
33
table.py
|
@ -1,26 +1,12 @@
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import yfinance as yf
|
import yfi as y
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_table(stonks):
|
def generate_table(stonks):
|
||||||
table_data = []
|
table_data = []
|
||||||
total = 0
|
total = 0
|
||||||
for ticker in stonks.keys():
|
for ticker in stonks.keys():
|
||||||
price = get_current_price(ticker)
|
price = y.get_current_price(ticker)
|
||||||
shares_count = stonks[ticker]
|
shares_count = stonks[ticker]
|
||||||
table_data.append([ticker, shares_count, round(Decimal(price) * Decimal(stonks[ticker]), 2)])
|
table_data.append([ticker, shares_count, round(Decimal(price) * Decimal(stonks[ticker]), 2)])
|
||||||
total += (Decimal(price) * Decimal(stonks[ticker]))
|
total += (Decimal(price) * Decimal(stonks[ticker]))
|
||||||
|
@ -28,3 +14,18 @@ def generate_table(stonks):
|
||||||
table_data.append(['Total', '', round(total, 2)])
|
table_data.append(['Total', '', round(total, 2)])
|
||||||
|
|
||||||
return str( tabulate(table_data, ['Ticker', 'Shares', 'Value ($)'], tablefmt="pretty") )
|
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" ) )
|
||||||
|
|
76
table2.py
Normal file
76
table2.py
Normal file
|
@ -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
|
8
yfi.py
Normal file
8
yfi.py
Normal file
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue