Skip to content

use yahooapi insteadsss #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ FUSION_SECRET_KEY=
TENOR_API_KEY=
HASHING_SECRET="changeme" # change this to a random string
ALPHA_VANTAGE_API_KEY=
RAPIDAPI_KEY=

LAVALINK_HOST="0.0.0.0"
LAVALINK_PORT=1234
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -156,3 +156,5 @@ pickle/
config.json

*.out

*.removeme
2 changes: 1 addition & 1 deletion ui/gambling.py
Original file line number Diff line number Diff line change
@@ -486,6 +486,6 @@ def play_slots(amount, multii):
outcome_message = f"You got a match! You won {amount_won}$!"
else:
amount_won = (-amount) * multii
outcome_message = f"Unlucky! You lost {amount}$."
outcome_message = f"Unlucky! You lost {amount_won}$."

return result, outcome_message, amount_won
86 changes: 41 additions & 45 deletions ui/papertrading.py
Original file line number Diff line number Diff line change
@@ -2,22 +2,19 @@
import asyncio
import aiohttp
import json
import os
from datetime import datetime
from discord import ui
from discord.ui import Button, button, View

from utils import DBClient

db = DBClient.db

# Configuration Constants
# TODO: put this in a config file
ALPHA_VANTAGE_API_KEY = os.getenv('ALPHA_VANTAGE_API_KEY')
RAPIDAPI_KEY = os.getenv('RAPIDAPI_KEY')
MIN_TRADE_AMOUNT = 1
MAX_TRADE_AMOUNT = 1000
TRADE_COOLDOWN = 5
DEMO_MODE = False
DEMO_MODE = True
MOCK_PRICES = {
"AAPL": 175.50,
"GOOGL": 140.25,
@@ -28,7 +25,6 @@
"NVDA": 820.30,
"AMD": 175.25
}

class StockPortfolioView(View):
def __init__(self, authorid):
super().__init__(timeout=None)
@@ -39,7 +35,7 @@ def __init__(self, authorid):
async def buy_stocks(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user.id != self.authorid:
return await interaction.response.send_message("This isn't your trading session!", ephemeral=True)

current_time = datetime.now().timestamp()
if self.authorid in self.last_trade_time:
time_diff = current_time - self.last_trade_time[self.authorid]
@@ -48,7 +44,7 @@ async def buy_stocks(self, interaction: discord.Interaction, button: discord.ui.
f"Please wait {TRADE_COOLDOWN - int(time_diff)} seconds before trading again!",
ephemeral=True
)

self.last_trade_time[self.authorid] = current_time
await interaction.response.send_modal(BuyStocksModal(self.authorid))

@@ -73,28 +69,25 @@ async def sell_stocks(self, interaction: discord.Interaction, button: discord.ui
async def view_portfolio(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user.id != self.authorid:
return await interaction.response.send_message("This isn't your trading session!", ephemeral=True)

c = db["trading"]
portfolio = c.find_one({"user_id": interaction.user.id, "guild_id": interaction.guild.id})

if not portfolio or not portfolio.get("positions", {}):
return await interaction.response.send_message("You don't have any positions yet!", ephemeral=True)

c_users = db["users"]
user = c_users.find_one({"id": interaction.user.id, "guild_id": interaction.guild.id})

embed = discord.Embed(title="Your Portfolio", color=0x00ff00)
embed.add_field(name="Available Balance", value=f"${user['wallet']:,.2f}", inline=False)

total_value = 0

for symbol, position in portfolio["positions"].items():
price = await get_stock_price(symbol)
if price:
current_value = position["shares"] * price
total_value += current_value
profit_loss = current_value - (position["shares"] * position["average_price"])

embed.add_field(
name=f"{symbol}",
value=f"Shares: {position['shares']}\n"
@@ -103,7 +96,6 @@ async def view_portfolio(self, interaction: discord.Interaction, button: discord
f"P/L: ${profit_loss:.2f} ({(profit_loss/current_value)*100:.1f}%)",
inline=False
)

embed.add_field(name="Total Portfolio Value", value=f"${total_value:.2f}", inline=False)
embed.add_field(name="Total Account Value", value=f"${(total_value + user['wallet']):.2f}", inline=False)
await interaction.response.send_message(embed=embed, ephemeral=True)
@@ -119,7 +111,6 @@ def __init__(self, authorid):
async def on_submit(self, interaction: discord.Interaction):
if interaction.user.id != self.authorid:
return await interaction.response.send_message("This isn't your trading session!", ephemeral=True)

symbol = self.symbol.value.upper()
try:
shares = float(self.shares.value)
@@ -132,30 +123,30 @@ async def on_submit(self, interaction: discord.Interaction):
return await interaction.response.send_message("Please enter a valid number of shares!", ephemeral=True)

price = await get_stock_price(symbol)

if not price:
return await interaction.response.send_message("Invalid stock symbol or API error!", ephemeral=True)

total_cost = price * shares

c = db["users"]

user = c.find_one({"id": interaction.user.id, "guild_id": interaction.guild.id})
if not user or user["wallet"] < total_cost:
return await interaction.response.send_message(
f"Insufficient funds! You need ${total_cost:,.2f} but have ${user['wallet']:,.2f}",
ephemeral=True
)

c = db["trading"]
portfolio = c.find_one({"user_id": interaction.user.id, "guild_id": interaction.guild.id})

portfolio = c.find_one({"user_id": interaction.user.id, "guild_id": interaction.guild.id})

if not portfolio:
portfolio = {
"user_id": interaction.user.id,
"guild_id": interaction.guild.id,
"positions": {}
}
c.insert_one(portfolio)

if symbol in portfolio["positions"]:
current_position = portfolio["positions"][symbol]
new_shares = current_position["shares"] + shares
@@ -169,19 +160,16 @@ async def on_submit(self, interaction: discord.Interaction):
"shares": shares,
"average_price": price
}

c.update_one(
{"user_id": interaction.user.id, "guild_id": interaction.guild.id},
{"$set": {"positions": portfolio["positions"]}}
)

user["wallet"] -= total_cost
c = db["users"]
c.update_one(
{"id": interaction.user.id, "guild_id": interaction.guild.id},
{"$set": {"wallet": user["wallet"]}}
)

await interaction.response.send_message(
f"Successfully bought {shares} shares of {symbol} at ${price:.2f} per share.\n"
f"Total cost: ${total_cost:.2f}\n"
@@ -193,62 +181,50 @@ class SellStocksModal(ui.Modal, title="Sell Stocks"):
def __init__(self, authorid):
super().__init__()
self.authorid = authorid

symbol = ui.TextInput(label="Stock Symbol", placeholder="e.g. AAPL", min_length=1, max_length=5)
shares = ui.TextInput(label="Number of Shares", placeholder="e.g. 10")

async def on_submit(self, interaction: discord.Interaction):
if interaction.user.id != self.authorid:
return await interaction.response.send_message("This isn't your trading session!", ephemeral=True)

symbol = self.symbol.value.upper()
try:
shares = float(self.shares.value)
if shares <= 0:
raise ValueError("Shares must be positive")
except ValueError:
return await interaction.response.send_message("Please enter a valid number of shares!", ephemeral=True)

c = db["trading"]
portfolio = c.find_one({"user_id": interaction.user.id, "guild_id": interaction.guild.id})

if not portfolio or symbol not in portfolio["positions"]:
return await interaction.response.send_message("You don't own this stock!", ephemeral=True)

current_position = portfolio["positions"][symbol]
if current_position["shares"] < shares:
return await interaction.response.send_message(
f"You don't have enough shares! You own {current_position['shares']} shares.",
ephemeral=True
)

price = await get_stock_price(symbol)
if not price:
return await interaction.response.send_message("Invalid stock symbol or API error!", ephemeral=True)

total_value = price * shares

new_shares = current_position["shares"] - shares
if new_shares == 0:
del portfolio["positions"][symbol]
else:
portfolio["positions"][symbol]["shares"] = new_shares

c.update_one(
{"user_id": interaction.user.id, "guild_id": interaction.guild.id},
{"$set": {"positions": portfolio["positions"]}}
)

c = db["users"]
user = c.find_one({"id": interaction.user.id, "guild_id": interaction.guild.id})
user["wallet"] += total_value
c.update_one(
{"id": interaction.user.id, "guild_id": interaction.guild.id},
{"$set": {"wallet": user["wallet"]}}
)

profit_loss = (price - current_position["average_price"]) * shares

await interaction.response.send_message(
f"Successfully sold {shares} shares of {symbol} at ${price:.2f} per share.\n"
f"Total value: ${total_value:.2f}\n"
@@ -257,13 +233,13 @@ async def on_submit(self, interaction: discord.Interaction):
ephemeral=True
)

async def get_stock_price(symbol):
async def get_stock_price_av(symbol):
"""Get current stock price using Alpha Vantage API or mock data"""
if DEMO_MODE and symbol in MOCK_PRICES:
return MOCK_PRICES[symbol]

url = f"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={symbol}&apikey={ALPHA_VANTAGE_API_KEY}"

async with aiohttp.ClientSession() as session:
try:
async with session.get(url) as response:
@@ -274,17 +250,38 @@ async def get_stock_price(symbol):
except:
return None

async def get_stock_price(symbol):
"""Get current stock price using Yahoo Finance API via RapidAPI or mock data."""
if DEMO_MODE and symbol in MOCK_PRICES:
return MOCK_PRICES[symbol]

url = f"https://apidojo-yahoo-finance-v1.p.rapidapi.com/stock/v2/get-summary?symbol={symbol}&region=US"
headers = {
"x-rapidapi-host": "apidojo-yahoo-finance-v1.p.rapidapi.com",
"x-rapidapi-key": RAPIDAPI_KEY
}

async with aiohttp.ClientSession() as session:
try:
async with session.get(url, headers=headers) as response:
data = await response.json()
if "price" in data and "regularMarketPrice" in data["price"]:
return float(data["price"]["regularMarketPrice"]["raw"])
return None
except Exception as e:
print(f"Error fetching stock price: {e}")
return None

async def start_paper_trading(ctx):
"""
Command to start paper trading session
Usage: !trade or /trade
"""
c = db["users"]
user = c.find_one({"id": ctx.author.id, "guild_id": ctx.guild.id})

if not user:
return await ctx.send("get outa here brokie")

embed = discord.Embed(
title="Paper Trading",
description="Welcome to paper trading! Trade stocks with your existing balance.\n"
@@ -302,6 +299,5 @@ async def start_paper_trading(ctx):
value="\n".join([f"{symbol}: ${price:.2f}" for symbol, price in MOCK_PRICES.items()]),
inline=False
)

view = StockPortfolioView(ctx.author.id)
await ctx.send(embed=embed, view=view)
await ctx.send(embed=embed, view=view)