Add matplotlib-based chart generation with Yahoo Finance data
- Add chart_generator.py with price and candlestick chart support - Implement Yahoo Finance candle data fetching for free historical data - Update bot to generate and attach charts to stock embeds - Add matplotlib dependency to requirements.txt - Configure dual API approach: Finnhub for quotes, Yahoo for charts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
49
bot.py
49
bot.py
@@ -10,6 +10,7 @@ from config import Config
|
||||
from stock_api import YahooFinanceAPI, FinnhubAPI
|
||||
from market_hours import MarketHours
|
||||
from crypto_api import CoinGeckoAPI
|
||||
from chart_generator import ChartGenerator
|
||||
|
||||
|
||||
# Configure logging
|
||||
@@ -36,6 +37,10 @@ class StockBot(commands.Bot):
|
||||
self.stock_api = YahooFinanceAPI()
|
||||
logger.info("Using Yahoo Finance API for stock data")
|
||||
|
||||
# Always initialize Yahoo Finance for chart data (free historical data)
|
||||
self.yahoo_api = YahooFinanceAPI()
|
||||
logger.info("Using Yahoo Finance API for chart data")
|
||||
|
||||
self.scheduler = AsyncIOScheduler(timezone=pytz.timezone('America/New_York'))
|
||||
self.target_channel_ids = [int(id) for id in Config.CHANNEL_IDS]
|
||||
self.primary_ticker = Config.PRIMARY_TICKER
|
||||
@@ -254,7 +259,25 @@ class StockBot(commands.Bot):
|
||||
return
|
||||
|
||||
embed = self.create_stock_embed(stock_data)
|
||||
await channel.send(embed=embed)
|
||||
|
||||
# Generate chart using Yahoo Finance historical data
|
||||
chart_file = None
|
||||
candle_data = self.yahoo_api.get_candles(ticker, days=30)
|
||||
if candle_data:
|
||||
chart_buffer = ChartGenerator.create_price_chart(
|
||||
ticker,
|
||||
candle_data,
|
||||
stock_data.get('company_name')
|
||||
)
|
||||
if chart_buffer:
|
||||
chart_file = discord.File(chart_buffer, filename="chart.png")
|
||||
|
||||
# Send with chart attachment if available
|
||||
if chart_file:
|
||||
await channel.send(embed=embed, file=chart_file)
|
||||
else:
|
||||
await channel.send(embed=embed)
|
||||
|
||||
logger.info(f"Sent stock update for {ticker} to channel {channel_id}")
|
||||
|
||||
def create_stock_embed(self, stock_data: dict) -> discord.Embed:
|
||||
@@ -310,9 +333,8 @@ class StockBot(commands.Bot):
|
||||
embed.add_field(name="Change", value=change_str, inline=True)
|
||||
embed.add_field(name="Previous Close", value=f"${stock_data['previous_close']}", inline=True)
|
||||
|
||||
# Add FinViz daily chart
|
||||
chart_url = f"https://finviz.com/chart.ashx?t={ticker}&ty=c&ta=1&p=d&s=l"
|
||||
embed.set_image(url=chart_url)
|
||||
# Reference attached chart image
|
||||
embed.set_image(url="attachment://chart.png")
|
||||
|
||||
market_status = "🟢 Market Open" if stock_data['market_open'] else "🔴 Market Closed"
|
||||
embed.set_footer(text=f"{market_status}")
|
||||
@@ -526,7 +548,24 @@ async def get_stock_price(ctx, ticker: str = None):
|
||||
return
|
||||
|
||||
embed = bot.create_stock_embed(stock_data)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
# Generate chart using Yahoo Finance historical data
|
||||
chart_file = None
|
||||
candle_data = bot.yahoo_api.get_candles(ticker, days=30)
|
||||
if candle_data:
|
||||
chart_buffer = ChartGenerator.create_price_chart(
|
||||
ticker,
|
||||
candle_data,
|
||||
stock_data.get('company_name')
|
||||
)
|
||||
if chart_buffer:
|
||||
chart_file = discord.File(chart_buffer, filename="chart.png")
|
||||
|
||||
# Send with chart attachment if available
|
||||
if chart_file:
|
||||
await ctx.send(embed=embed, file=chart_file)
|
||||
else:
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
@bot.command(name='crypto', aliases=['c'])
|
||||
|
||||
Reference in New Issue
Block a user