trading-chatbot / src /tools /chart_generator.py
Aarya003's picture
Upload folder using huggingface_hub
4464b01 verified
import yfinance as yf
import mplfinance as mpf
import pandas as pd
from pathlib import Path
from typing import Optional
import matplotlib
matplotlib.use('Agg') # Use non-interactive backend
def generate_multimodal_chart(ticker: str, timeframe: str = "daily", save_dir: str = "data", end_date: Optional[str] = None) -> Optional[str]:
"""
Fetches OHLCV data for a ticker and generates a high-resolution .png candlestick chart
with volume and moving averages plotted for VLM analysis. Supports point-in-time data for backtesting.
Args:
ticker (str): The stock symbol (e.g., 'AAPL').
timeframe (str): 'daily' or 'weekly'.
save_dir (str): The directory to save the generated image.
end_date (str, optional): The point-in-time cutoff (YYYY-MM-DD) for backtesting.
Returns:
Optional[str]: The absolute path to the saved .png file, or None if failed.
"""
save_path = Path(save_dir)
save_path.mkdir(parents=True, exist_ok=True)
# Configure period and interval based on timeframe
if timeframe.lower() == "weekly":
period = "2y"
interval = "1wk"
file_suffix = "weekly"
else:
period = "6mo"
interval = "1d"
file_suffix = "daily"
try:
# Fetch data
if end_date:
# For backtesting, we need more control over the date range
df = yf.download(ticker, end=end_date, period=period, interval=interval, progress=False)
else:
df = yf.download(ticker, period=period, interval=interval, progress=False)
if df.empty:
print(f"Error: No data found for {ticker}.")
return None
# Clean up column names for mplfinance (yfinance returns multi-index sometimes)
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.droplevel(1)
# Ensure required columns exist
required_cols = ['Open', 'High', 'Low', 'Close', 'Volume']
if not all(col in df.columns for col in required_cols):
print(f"Error: Missing required OHLCV columns for {ticker}.")
return None
# Setup plot style and parameters
mc = mpf.make_marketcolors(up='g', down='r', edge='i', wick='i', volume='in', ohlc='i')
s = mpf.make_mpf_style(marketcolors=mc, gridstyle=':', y_on_right=False)
# Output file path
output_file = save_path / f"{ticker.upper()}_{file_suffix}_chart.png"
# Plot and save
mpf.plot(
df,
type='candle',
volume=True,
mav=(20, 50), # Plot 20-period and 50-period moving averages
style=s,
title=f"{ticker.upper()} {timeframe.capitalize()} Chart",
ylabel='Price ($)',
ylabel_lower='Volume',
savefig=dict(fname=str(output_file), dpi=300, bbox_inches='tight')
)
return str(output_file.absolute())
except Exception as e:
print(f"Failed to generate chart for {ticker}: {str(e)}")
return None
if __name__ == "__main__":
# Test the function
res = generate_multimodal_chart("NVDA", "daily")
if res:
print(f"Successfully saved chart to: {res}")