ticker / app.py
truevis
Update app.py
182c84d
raw
history blame
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)