# app.py # Import required libraries import streamlit as st import yfinance as yf from datetime import date, timedelta import pandas as pd import numpy as np import matplotlib.pyplot as plt import io # Optional: Install 'ta' library for technical indicators (uncomment if needed) # !pip install ta # Set Streamlit page configuration st.set_page_config( page_title='📈 Indian Stock Data Downloader and Volume Analyzer', layout='wide', initial_sidebar_state='expanded' ) # Set the title of the app st.title('📈 Indian Stock Data Downloader and Volume Analyzer') # Sidebar for user inputs st.sidebar.header('🔧 Configuration') # File uploader for 'stock_list.csv' uploaded_file = st.sidebar.file_uploader( "📂 Upload your stock list CSV", type=["csv"], help="The CSV file should contain 'Symbol' and 'Company Name' columns." ) if uploaded_file is not None: try: # Read the uploaded CSV file into a DataFrame stock_df = pd.read_csv(uploaded_file) # 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: {', '.join(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:', options=list(stock_dict.keys()), default=list(stock_dict.keys())[:5] # Select first 5 stocks by default ) # Date input widgets for date range selection default_start_date = date.today() - timedelta(days=365) # Past year start_date = st.sidebar.date_input('📅 Start Date', default_start_date) end_date = st.sidebar.date_input('📅 End Date', date.today()) # Ensure that start_date is before end_date if start_date > end_date: st.sidebar.error("❌ Start Date must be before End Date.") # 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 and Analyze Data button if st.sidebar.button('📥 Download and Analyze Data'): if selected_stocks: for company_name in selected_stocks: ticker = stock_dict[company_name] # Append '.NS' or '.BO' for NSE or BSE stocks if not already present if not (ticker.endswith('.NS') or ticker.endswith('.BO')): # Default to NSE; modify as needed ticker += '.NS' # Fetch data from Yahoo Finance try: with st.spinner(f"⏳ Fetching data for {company_name} ({ticker})..."): 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 available_options = [option for option in data_options if option in stock_data.columns] if not available_options: st.warning(f"No selected data options available for **{company_name}** ({ticker}).") continue stock_data = stock_data[available_options] st.subheader(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) if 'Close' and 'Volume' are selected if 'Close' in stock_data.columns and 'Volume' in stock_data.columns: stock_data['Amount'] = stock_data['Close'] * stock_data['Volume'] else: stock_data['Amount'] = np.nan # OBV in terms of Amount if 'OBV (Amount)' in indicators and 'Amount' in stock_data.columns: # 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 and 'Close' in stock_data.columns: delta = stock_data['Close'].diff() up = delta.clip(lower=0) down = -1 * delta.clip(upper=0) roll_up = up.rolling(window=14).mean() roll_down = down.rolling(window=14).mean() RS = roll_up / roll_down stock_data['RSI'] = 100.0 - (100.0 / (1.0 + RS)) # 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 and 'Close' in stock_data.columns: exp1 = stock_data['Close'].ewm(span=12, adjust=False).mean() exp2 = stock_data['Close'].ewm(span=26, adjust=False).mean() stock_data['MACD'] = exp1 - exp2 stock_data['MACD_Signal'] = stock_data['MACD'].ewm(span=9, adjust=False).mean() stock_data['MACD_Hist'] = stock_data['MACD'] - stock_data['MACD_Signal'] # Plot MACD fig_macd, ax = plt.subplots(figsize=(12, 4)) ax.plot(stock_data['Date'], stock_data['MACD'], label='MACD', color='purple') ax.plot(stock_data['Date'], stock_data['MACD_Signal'], label='Signal', color='red') ax.bar(stock_data['Date'], stock_data['MACD_Hist'], 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 for Volume if 'Volume' is selected if 'Volume' in stock_data.columns: 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' ) else: st.warning("⚠️ Please select at least one stock.") except Exception as e: st.error(f"❌ Error processing the uploaded file: {e}") else: st.info("🔍 Please upload your `stock_list.csv` file to get started.") st.markdown(""" **Sample `stock_list.csv` Format:** ```csv Symbol,Company Name TCS,Tata Consultancy Services INFY,Infosys Limited RELIANCE,Reliance Industries HDFCBANK,HDFC Bank ICICIBANK,ICICI Bank ``` You can create your own CSV file following the above format. Ensure that the CSV has headers `Symbol` and `Company Name`. **Sample CSV Download:** [Download Sample `stock_list.csv`](https://huggingface.co/spaces/riteshcp/Indian_Futures_OBV_Downloader/resolve/main/sample_stock_list.csv) """)