Spaces:
Runtime error
Runtime error
# app.py | |
# Import required libraries | |
import streamlit as st | |
import yfinance as yf | |
from datetime import date | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import pandas_ta as ta # For technical indicators | |
import os | |
# Set the title of the app | |
st.title('Indian Stock Data Downloader and Volume Analyzer') | |
# Sidebar for user inputs | |
st.sidebar.header('Select Stocks and Options') | |
# Path to your CSV file (adjusted for HF) | |
csv_file_path = 'stock_list.csv' # Ensure this file is uploaded to HF | |
# Check if the file exists | |
if not os.path.isfile(csv_file_path): | |
st.error(f"The stock list file was not found. Please upload 'stock_list.csv' to your app.") | |
else: | |
# Read the CSV file into a DataFrame | |
stock_df = pd.read_csv(csv_file_path) | |
# Ensure that the required columns are present | |
required_columns = {'Symbol', 'Company Name'} | |
if not required_columns.issubset(stock_df.columns): | |
st.error(f"The CSV file must contain the following columns: {required_columns}") | |
else: | |
# Create a dictionary mapping company names to stock symbols | |
stock_dict = pd.Series(stock_df['Symbol'].values, index=stock_df['Company Name']).to_dict() | |
# Multiselect widget for stock selection | |
selected_stocks = st.sidebar.multiselect('Select Stocks:', list(stock_dict.keys())) | |
# Date input widgets for date range selection | |
start_date = st.sidebar.date_input('Start Date', date(2021, 1, 1)) | |
end_date = st.sidebar.date_input('End Date', date.today()) | |
# Checkbox for selecting data options | |
st.sidebar.header('Data Options') | |
data_options = st.sidebar.multiselect( | |
'Select Data to Download:', | |
['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume'], | |
default=['Open', 'High', 'Low', 'Close', 'Volume'] | |
) | |
# Technical Indicators selection | |
st.sidebar.header('Technical Indicators') | |
indicators = st.sidebar.multiselect( | |
'Select Technical Indicators to Calculate:', | |
['OBV (Amount)', 'RSI', 'MACD'] | |
) | |
# Download button | |
if st.sidebar.button('Download Data'): | |
if selected_stocks: | |
for company_name in selected_stocks: | |
ticker = stock_dict[company_name] | |
# Append '.NS' if not already present for NSE stocks | |
if not ticker.endswith('.NS') and not ticker.endswith('.BO'): | |
ticker += '.NS' | |
# Fetch data from Yahoo Finance | |
try: | |
stock_data = yf.download(ticker, start=start_date, end=end_date) | |
# Check if data is returned | |
if stock_data.empty: | |
st.warning(f"No data found for {company_name} ({ticker}) in the selected date range.") | |
continue | |
# Filter data based on selected options | |
stock_data = stock_data[data_options] | |
st.write(f"**Data for {company_name} ({ticker}):**") | |
st.dataframe(stock_data) | |
# Reset index to get 'Date' as a column | |
stock_data = stock_data.reset_index() | |
# Calculate Amount (Close * Volume) | |
stock_data['Amount'] = stock_data['Close'] * stock_data['Volume'] | |
# OBV in terms of Amount | |
if 'OBV (Amount)' in indicators: | |
# Calculate direction | |
stock_data['Daily_Return'] = stock_data['Close'].pct_change() | |
stock_data['Direction'] = stock_data['Daily_Return'].apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0)) | |
stock_data['OBV_Amount'] = (stock_data['Amount'] * stock_data['Direction']).cumsum() | |
# Plot OBV in Amount | |
fig_obv_amount, ax = plt.subplots(figsize=(12, 4)) | |
ax.plot(stock_data['Date'], stock_data['OBV_Amount'], label='OBV (Amount)', color='orange') | |
ax.set_xlabel('Date') | |
ax.set_ylabel('On-Balance Volume (Amount)') | |
ax.set_title(f"{company_name} OBV (Amount)") | |
ax.legend() | |
st.pyplot(fig_obv_amount) | |
# RSI | |
if 'RSI' in indicators: | |
stock_data['RSI'] = ta.rsi(stock_data['Close'], length=14) | |
# Plot RSI | |
fig_rsi, ax = plt.subplots(figsize=(12, 4)) | |
ax.plot(stock_data['Date'], stock_data['RSI'], label='RSI', color='green') | |
ax.set_xlabel('Date') | |
ax.set_ylabel('RSI') | |
ax.set_title(f"{company_name} RSI") | |
ax.axhline(70, color='red', linestyle='--') | |
ax.axhline(30, color='blue', linestyle='--') | |
ax.legend() | |
st.pyplot(fig_rsi) | |
# MACD | |
if 'MACD' in indicators: | |
macd = ta.macd(stock_data['Close']) | |
stock_data = pd.concat([stock_data, macd], axis=1) | |
# Plot MACD | |
fig_macd, ax = plt.subplots(figsize=(12, 4)) | |
ax.plot(stock_data['Date'], stock_data['MACD_12_26_9'], label='MACD', color='purple') | |
ax.plot(stock_data['Date'], stock_data['MACDs_12_26_9'], label='Signal', color='red') | |
ax.bar(stock_data['Date'], stock_data['MACDh_12_26_9'], label='Histogram', color='grey') | |
ax.set_xlabel('Date') | |
ax.set_ylabel('MACD') | |
ax.set_title(f"{company_name} MACD") | |
ax.legend() | |
st.pyplot(fig_macd) | |
# Calculate moving averages | |
stock_data['Volume_MA_5'] = stock_data['Volume'].rolling(window=5).mean() | |
stock_data['Volume_MA_20'] = stock_data['Volume'].rolling(window=20).mean() | |
# Plotting price and volume | |
fig, ax1 = plt.subplots(figsize=(12, 6)) | |
# Plot the closing price | |
ax1.plot(stock_data['Date'], stock_data['Close'], color='blue', label='Close Price') | |
ax1.set_xlabel('Date') | |
ax1.set_ylabel('Close Price', color='blue') | |
ax1.tick_params(axis='y', labelcolor='blue') | |
# Create a second y-axis for volume | |
ax2 = ax1.twinx() | |
ax2.bar(stock_data['Date'], stock_data['Volume'], color='gray', alpha=0.3, label='Volume') | |
# Plot moving averages of volume | |
ax2.plot(stock_data['Date'], stock_data['Volume_MA_5'], color='red', label='5-Day MA') | |
ax2.plot(stock_data['Date'], stock_data['Volume_MA_20'], color='green', label='20-Day MA') | |
ax2.set_ylabel('Volume', color='gray') | |
ax2.tick_params(axis='y', labelcolor='gray') | |
# Add legends and title | |
fig.legend(loc='upper left', bbox_to_anchor=(0.15, 0.85)) | |
plt.title(f"{company_name} Price and Volume Chart with Moving Averages") | |
fig.tight_layout() | |
st.pyplot(fig) | |
# Volume analysis | |
stock_data['Volume_Pct_Change'] = stock_data['Volume'].pct_change() * 100 | |
average_volume = stock_data['Volume'].mean() | |
current_volume = stock_data['Volume'].iloc[-1] | |
volume_trend = 'increasing' if current_volume > average_volume else 'decreasing' | |
st.subheader(f"Volume Analysis for {company_name}") | |
st.write(f"- **Average Volume:** {average_volume:,.0f}") | |
st.write(f"- **Current Volume:** {current_volume:,.0f}") | |
st.write(f"- **Volume is currently {volume_trend}.**") | |
# Convert data to CSV | |
csv = stock_data.to_csv(index=False).encode('utf-8') | |
# Download button for CSV | |
st.download_button( | |
label=f"Download {company_name} Data as CSV", | |
data=csv, | |
file_name=f"{ticker}_{start_date}_{end_date}.csv", | |
mime='text/csv' | |
) | |
except Exception as e: | |
st.error(f"Error fetching data for {company_name} ({ticker}): {e}") | |
else: | |
st.warning("Please select at least one stock.") | |