stock-tracker-discord/main.py
2021-03-19 17:24:38 +00:00

252 lines
6.3 KiB
Python

import discord
import table, yfi
import table2 as t2
from discord.ext import commands
import config as cfg
from decimal import Decimal
import typing
import inspect
if cfg.use_mongodb:
import mongo as database
print("[*] Using MongoDB Database")
else:
import flatfile as database
print("[*] Using FlatFile Database")
intents = discord.Intents.default()
bot = commands.Bot(command_prefix=cfg.command_prefix, intents=intents)
@bot.command()
async def ping(ctx):
await ctx.send("pong!")
@bot.command(aliases=["stock", "t", "s"])
async def ticker(ctx, stock):
user = str(ctx.message.author)
stock = stock.upper()
data = yfi.stock_info(stock)
await ctx.send(
inspect.cleandoc(
"""**{ticker}**
Bid: {bid}
Ask: {ask}
""".format(
ticker=stock, bid=data["bid"], ask=data["ask"]
)
)
)
image = t2.generate_chart(stock, yfi.stock_history(stock))
await ctx.send(file=discord.File(image, "chart.png"))
image.close()
@bot.command(aliases=["pft"])
async def portfolio_text(ctx):
user = str(ctx.message.author)
return await ctx.send(
str("```" + table.generate_table(database.get_stocks(user)) + "```")
)
@bot.command(aliases=["pf"])
async def portfolio(ctx):
user = str(ctx.message.author)
portfolio = database.get_stocks(user)
yesterday_portfolio_value = {}
current_portfolio_value = {}
data = []
for stock in portfolio.keys():
delta, old_price = yfi.get_delta(stock, return_old_price=True)
current_price = yfi.get_current_price(stock)
data.append(
[
stock,
Decimal(portfolio[stock]),
round(float(Decimal(portfolio[stock]) * Decimal(current_price)), 2),
str(round(delta, 2)) + "%",
]
)
yesterday_portfolio_value[stock] = Decimal(portfolio[stock]) * Decimal(
old_price
)
current_portfolio_value[stock] = Decimal(portfolio[stock]) * Decimal(
current_price
)
yesterday_portfolio_total_value = sum(
[yesterday_portfolio_value[stock] for stock in yesterday_portfolio_value]
)
current_portfolio_total_value = sum(
[current_portfolio_value[stock] for stock in current_portfolio_value]
)
# TODO: Raises ZeroDivisionError if user has no stocks
total_delta = 100 * (
(current_portfolio_total_value - yesterday_portfolio_total_value)
/ yesterday_portfolio_total_value
)
data.append(
[
"Total",
"",
round(sum([x[2] for x in data]), 2),
str(round(total_delta, 2)) + "%",
]
)
image = t2.generate_table(
headers=["Ticker", "Shares", "Value ($)", "24h"],
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
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=["wlt"])
async def watchlist_text(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, *stocks):
user = str(ctx.message.author)
stocks = [stock.upper() for stock in stocks]
for stock in stocks:
database.unwatch(user, stock)
return await ctx.send("Updated watchlist")
@bot.command(aliases=["wl"])
async def watchlist(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]),
str(round(yfi.get_delta(stock), 2)) + "%",
]
)
image = t2.generate_table(
headers=["Ticker", "Value ($)", "Est. Price ($)", "24h"],
data=data,
title=str(user + "'s Watchlist"),
bg="lightgreen",
border="limegreen",
)
await ctx.send(file=discord.File(image, "table.png"))
image.close()
@bot.command(aliases=["opt"])
async def options(ctx, stock, money, exp_price):
user = str(ctx.message.author)
stock = stock.upper()
try:
money = float(money)
exp_price = float(exp_price)
except ValueError:
return await ctx.send("amoutn not a number")
best_price, prices = yfi.options_chain(stock, money, exp_price)
output = inspect.cleandoc("```")
for price in prices:
if price[0] == best_price[0]:
output = (
output
+ "\n"
+ "* Buy strike ${} to make ${:.2f}".format(price[0], price[1])
)
elif price[1] < -5000:
pass
else:
output = (
output
+ "\n"
+ " Buy strike ${} to make ${:.2f}".format(price[0], price[1])
)
output = output + "```"
print(len(output))
return await ctx.send(output)
bot.run(cfg.api_key)