ticker / app.py
truevis
Update app.py
182c84d
raw
history blame contribute delete
No virus
7.96 kB
import streamlit as st
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
import streamlit.components.v1 as components
# Set the page to wide mode and specify a title
st.set_page_config(layout="wide", page_title="Stock Insight Explorer", page_icon=":chart_with_upwards_trend:")
# Display the application title in the app itself
st.title('Stock Insight Explorer: Visual Analytics & Dividend Overview')
# Input field for stock symbol
stock_symbol = st.text_input('Enter Stock Symbol', value='JEPI')
# Fetch stock data
stock_data = yf.Ticker(stock_symbol)
# Get historical data for the past year
end_date = pd.Timestamp.today()
start_date = end_date - pd.DateOffset(years=1)
historical_data = stock_data.history(start=start_date, end=end_date)
# Display company name and current stock price in bold
company_name = stock_data.info['longName']
current_price = historical_data['Close'].iloc[-1]
# st.markdown(f"**Company Name:** {company_name}")
# https://finance.yahoo.com/quote/JEPQ?.tsrc=fin-srch
company_url = f"https://finance.yahoo.com/quote/{stock_symbol}?.tsrc=fin-srch"
# Use HTML anchor tag to create a hyperlink
st.markdown(f"**Company Name:** <a href='{company_url}' target='_blank'>{company_name}</a>", unsafe_allow_html=True)
st.markdown(f"**Current Price:** ${current_price:.2f}")
# Creating 3 columns for the charts
col1, col2, col3, col4 = st.columns(4)
# Closing prices chart
with col1:
st.subheader('Closing Prices Over The Past Year')
st.line_chart(historical_data['Close'])
# Volume of stock trades chart
with col2:
st.subheader('Volume of Stock Trades Over The Past Year')
st.bar_chart(historical_data['Volume'])
# Calculate 20 day and 50 day moving averages
historical_data['20 Day MA'] = historical_data['Close'].rolling(window=20).mean()
historical_data['50 Day MA'] = historical_data['Close'].rolling(window=50).mean()
# Line chart for closing price, 20 day MA, and 50 day MA
with col3:
st.subheader('Closing Price and Moving Averages')
plt.figure(figsize=(10, 5))
plt.plot(historical_data.index, historical_data['Close'], label='Close Price')
plt.plot(historical_data.index, historical_data['20 Day MA'], label='20 Day MA')
plt.plot(historical_data.index, historical_data['50 Day MA'], label='50 Day MA')
plt.legend()
plt.xlabel('Date')
plt.ylabel('Price')
plt.title('Closing Price, 20 Day MA, and 50 Day MA')
st.pyplot(plt)
# Get the dividend data
# Assuming stock_data is your Ticker object from yfinance
dividends = stock_data.dividends
# Check if there are any dividends
if not dividends.empty:
last_dividend_value = dividends.iloc[-1] # Get the last dividend value from the dividends history
else:
# Fallback to the lastDividendValue from the .info attribute if no historical dividends are found
last_dividend_value = stock_data.info.get('lastDividendValue', 0)
with col4:
st.subheader('Dividends')
markdown_output = "" # Initialize an empty string to accumulate messages
# Ensure dividends.index is in the correct format
dividends.index = pd.to_datetime(dividends.index).date
if not dividends.empty:
plt.figure(figsize=(10, 5))
dividends.plot(kind='bar')
plt.title(f'Dividends of {stock_symbol} Over Time')
plt.ylabel('Dividend Amount')
plt.xlabel('Date')
plt.xticks(rotation=45)
plt.tight_layout()
st.pyplot(plt)
# Calculate total annual dividends
today = pd.to_datetime("today")
last_year_dividends = dividends.loc[dividends.index > (today - pd.DateOffset(years=1)).date()]
total_annual_dividends = last_year_dividends.sum()
if current_price and current_price > 0:
annual_dividend_yield = (total_annual_dividends / current_price) * 100
markdown_output += f"**Annual Dividend Yield:** {annual_dividend_yield:.2f}%.\n"
else:
markdown_output += "Current price not available. Cannot calculate annual dividend yield.\n"
else:
markdown_output += "This stock does not have any dividend data available.\n"
total_annual_dividends = 0 # Define it as 0 if there are no dividends
if current_price and current_price > 0 and last_dividend_value:
dividend_yield = (last_dividend_value / current_price) * 100
markdown_output += f"**Last Dividend Yield:** {dividend_yield:.2f}%, ${last_dividend_value:.2f} per share."
else:
markdown_output += "Cannot calculate last dividend yield."
# Display all collected information in one markdown output
st.markdown(markdown_output, unsafe_allow_html=True)
# components.iframe("https://duckduckgo.com/?q=ZIM&va=i&t=hd&iar=news&df=w&ia=news")
# components.iframe("https://news.google.com/rss/search?q=ZIM&hl=en-US&gl=US&ceid=US%3Aen", height=800, scrolling=True)
# components.iframe("https://truevis.com", height=800, scrolling=True)
from unicodedata import normalize
from bs4 import BeautifulSoup
from feedparser import parse as parse_feed
def flatten_unicode_keys(entry_properties):
"""Ensures passing unicode keywords to **kwargs."""
new_properties = {}
for key, value in entry_properties.items():
key_str = key.decode('utf-8') if isinstance(key, bytes) else key
new_key = normalize('NFKD', key_str).encode('ascii', 'ignore').decode('ascii') # Decode the bytes object to string
new_properties[new_key] = value
return new_properties
TEMPLATE = """
<h2 class='title'>{title}</h2>
<a class='link' href='{link}'>{title}</a>
<span class='description'>{description}</span>
"""
def entry_to_html(entry_id, **kwargs):
new_kwargs = flatten_unicode_keys(kwargs)
new_kwargs.setdefault('title', 'No title')
new_kwargs.setdefault('link', 'No link')
new_kwargs.setdefault('description', '')
accordion_item = f"""
<div class="card">
<div class="card-header" id="heading{entry_id}">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapse{entry_id}" aria-expanded="true" aria-controls="collapse{entry_id}">
{new_kwargs['title']}
</button>
</h5>
</div>
<div id="collapse{entry_id}" class="collapse {'show' if entry_id == 0 else ''}" aria-labelledby="heading{entry_id}" data-parent="#accordion">
<div class="card-body">
<a href='{new_kwargs['link']}' target='_blank'>{new_kwargs['title']}</a>
<p>{new_kwargs['description']}</p>
</div>
</div>
</div>
"""
return accordion_item
def convert_feed_to_accordion(url):
feed = parse_feed(url)
accordion_html = '<div id="accordion">'
for i, entry in enumerate(feed.entries):
accordion_html += entry_to_html(i, **entry)
accordion_html += '</div>'
return accordion_html
# Bootstrap CSS and JS must be included in the output HTML to style the accordion correctly
bootstrap_includes = """
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
"""
# Fetch and display the accordion
url = f"https://news.google.com/rss/search?q={stock_symbol}&hl=en-US&gl=US&ceid=US%3Aen"
# print(url)
feed_accordion_html = bootstrap_includes + convert_feed_to_accordion(url)
st.markdown(f"Latest news on **{stock_symbol}**")
components.html(feed_accordion_html, height=800, scrolling=True)
# def convert_feed_to_raw_data(url):
# feed = parse_feed(url)
# raw_data = [entry for entry in feed.entries]
# return raw_data
# Fetch and display the raw RSS data
# url = f"https://news.google.com/rss/search?q={stock_symbol}&hl=en-US&gl=US&ceid=US%3Aen"
# raw_data = convert_feed_to_raw_data(url)
# print(raw_data)
# st.write(raw_data)