Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

documentation changes #54

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions dinero/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pylint: disable=invalid-escape
"""
Module level docstring for Stock Dashboard Application

Expand All @@ -21,6 +22,7 @@
$ streamlit run app.py

"""
# Importing required libraries
import streamlit as st
import pandas as pd

Expand All @@ -38,6 +40,7 @@
#st.set_theme('dark')
st.set_page_config(layout="wide")

# Defining colors for better readability
HEADING_COLOR = "#86B6F6"
NEWS_ARTICLE_COLOR = "#E3DFFD"
NEWS_ARTICLE_DATE_COLOR = "#89CFF3"
Expand All @@ -47,6 +50,7 @@
NEGATIVE_COLOR = "#D24545" # Red
HIGHLIGHT_COLOR_BLUE = "#AEDEFC"

# Dictionaries created to MAP elements with HTML strings
kpi_description_mapping = {
"MA" : f'''The <span style='color:{NEGATIVE_COLOR}'><b>Moving Average (MA)
</b></span> helps <span style='color:{HIGHLIGHT_COLOR_BLUE}'><i>smooth out
Expand Down Expand Up @@ -139,30 +143,39 @@

st.image("frontend/logo.png", use_column_width=True)

# Sidebar content
st.sidebar.markdown(f'''<h1 style='color:{NEWS_ARTICLE_DATE_COLOR}; text-align: center;'>
📊 Welcome the the Stock Analysis Platform!</h1>''',
unsafe_allow_html=True)
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR}; text-align: center;'>
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR};'>
Click on the various tabs to dive deep into stock data and
news headlines! 💼📰</h2>''',
unsafe_allow_html=True)
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR}; text-align: center;'>
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR};'>
Use the filters to select company, date range,
and technical indicators, to ensure you get
tailored insights! 📅🔍</h2>''',
unsafe_allow_html=True)
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR}; text-align: center;'>
st.sidebar.markdown(f'''<h2 style='color:{NEWS_ARTICLE_COLOR};'>
Understand the sentiment and keywords of
news events, and analyze their correlation
with stock price movements! 📈🔍</h2>''',
unsafe_allow_html=True)


st.sidebar.markdown('''<hr class="horizontal-line">''', unsafe_allow_html=True)
st.sidebar.markdown('''Refer to our [tool guide](examples/tool_guide_for_user.md)
for detailed instructions on how to use the stock analysis tool''')
st.sidebar.markdown('''
Refer to our documentation for more information on these complex financial terms:
[Documentation](https://drive.google.com/file/d/1H8gJ8gjN8jLVqtD8mAAAB5-VOmehDnhr/view?usp=sharing)
''')

# Creating streamlit tabs
tab1, tab2, tab3, tab4 = st.tabs(["📈 Stock Performance Overview",
"🔍 Explore Stock Technical Indicators",
"📰 Latest News Headlines and Articles",
"💡 Explore More Tickers or Update Data!"])

# Tab 1: Stock Performance Overview
with tab1:

company_option = st.selectbox('Choose the Company Stock you Wish to View!',
Expand Down Expand Up @@ -210,7 +223,7 @@
movements.
''', unsafe_allow_html=True)


# Tab 2: Explore Stock Technical Indicators
with tab2:
st.markdown(f'''<h2 style='color:{HEADING_COLOR}; text-align: center;'>
LEVERAGING TECHNICAL INDICATORS</h2>''', unsafe_allow_html=True)
Expand Down Expand Up @@ -240,6 +253,7 @@
with st.expander("🛈 What do These Numbers Mean?"):
st.markdown(kpi_chart_info_mapping[kpi_name], unsafe_allow_html=True)

# Tab 3: Latest News Headlines and Articles
with tab3:
st.markdown(f'''<h2 style='color:{HEADING_COLOR}; text-align:
center;'>BEYOND HEADLINES : DECODING NEWS SENTIMENT</h2>'''
Expand Down Expand Up @@ -327,6 +341,7 @@

st.markdown('<hr class="horizontal-line">', unsafe_allow_html=True)

# Tab 4: Explore More Tickers or Update Data!
with tab4:
selected_ticker = st.text_input('➕ Add New Ticker')
selected_time = st.text_input('''(Optional) 🕒 Input a time period
Expand Down
30 changes: 11 additions & 19 deletions dinero/backend/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
from backend.stock_data_manager import get_stock_data
from backend.kpi_manager import get_technical_indicator

TIME_BUTTONS = [
{'step': 'all', 'label': 'All'},
{'count': 3, 'step': 'year', 'stepmode': 'backward', 'label': '3 Year'},
{'count': 1, 'step': 'year', 'stepmode': 'backward', 'label': '1 Year'},
{'count': 6, 'step': 'month', 'stepmode': 'backward', 'label': '6 Month'},
{'count': 1, 'step': 'month', 'stepmode': 'backward', 'label': '1 Month'},
{'count': 1, 'step': 'year', 'stepmode': 'todate', 'label': '1 Year To Date'}
]

def plot_stock_price(ticker_symbol):
"""
Plot a candlestick chart for the given stock ticker symbol.
Expand Down Expand Up @@ -42,15 +51,7 @@ def plot_stock_price(ticker_symbol):
fig_candlestick.update_layout(title=f'Candlestick Chart',
xaxis_title="Date", yaxis_title="Price")
fig_candlestick.update_layout(hovermode="x unified")
time_buttons = [
{'step': 'all', 'label': 'All'},
{'count': 3, 'step': 'year', 'stepmode': 'backward', 'label': '3 Year'},
{'count': 1, 'step': 'year', 'stepmode': 'backward', 'label': '1 Year'},
{'count': 6, 'step': 'month', 'stepmode': 'backward', 'label': '6 Month'},
{'count': 1, 'step': 'month', 'stepmode': 'backward', 'label': '1 Month'},
{'count': 1, 'step': 'year', 'stepmode': 'todate', 'label': '1 Year To Date'}
]
fig_candlestick.update_xaxes(rangeselector={'buttons': time_buttons})
fig_candlestick.update_xaxes(rangeselector={'buttons': TIME_BUTTONS})
fig_candlestick.update_yaxes(autorange=True, fixedrange = False)

return fig_candlestick
Expand Down Expand Up @@ -113,15 +114,6 @@ def plot_kpis(stock_fig, ticker_symbol, length, kpi_name):
kpi_fig.update_traces(xaxis='x1')
kpi_fig.update_layout(title=f'{kpi_name} for {ticker_symbol}',
xaxis_title="Date", yaxis_title="Price")

time_buttons = [
{'step': 'all', 'label': 'All'},
{'count': 3, 'step': 'year', 'stepmode': 'backward', 'label': '3 Year'},
{'count': 1, 'step': 'year', 'stepmode': 'backward', 'label': '1 Year'},
{'count': 6, 'step': 'month', 'stepmode': 'backward', 'label': '6 Month'},
{'count': 1, 'step': 'month', 'stepmode': 'backward', 'label': '1 Month'},
{'count': 1, 'step': 'year', 'stepmode': 'todate', 'label': '1 Year To Date'}
]
kpi_fig.update_xaxes(rangeselector={'buttons': time_buttons})
kpi_fig.update_xaxes(rangeselector={'buttons': TIME_BUTTONS})
kpi_fig.update_yaxes(autorange=True, fixedrange = False)
return kpi_fig
Empty file added dinero/output.txt
Empty file.
73 changes: 52 additions & 21 deletions dinero/tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
"""

import unittest
from unittest import mock
from streamlit.testing.v1 import AppTest
import pandas as pd


@mock.patch('backend.processing.get_sentiments')


class TestStreamlitApp(unittest.TestCase):
"""
Expand Down Expand Up @@ -42,20 +48,29 @@ class TestStreamlitApp(unittest.TestCase):
- update_data_for_new_ticker: Test the update of data for a newly added
ticker in the Streamlit application.
"""

def test_smoke_app(self):
mocked_sentiment_dataframe = pd.DataFrame({"Date": ["2022-02-02"],
"Title": ["Mock Data News"],
"Link" : ["www.google.com"],
"Compound Sentiment Score": [0.2],
"Positive Sentiment Score": [0.2],
"Negative Sentiment Score": [0.2],
"Neutral Sentiment Score": [0.2]})
def test_smoke_app(self,mock_get_sentiment):
"""
Test the basic functionality of the Streamlit application.
This test checks if the application loads without raising any exceptions.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
assert not at.exception

def test_number_and_titles_of_tabs(self):
def test_number_and_titles_of_tabs(self,mock_get_sentiment):
"""
This test verifies if the titles of the tabs match the expected labels.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()

expected_labels = ["📈 Stock Performance Overview",
"🔍 Explore Stock Technical Indicators",
Expand All @@ -65,27 +80,31 @@ def test_number_and_titles_of_tabs(self):
for i, expected_label in enumerate(expected_labels):
assert at.tabs[i].label == expected_label

def test_stock_options(self):
def test_stock_options(self,mock_get_sentiment):
"""
This test verifies if there are atleast five company tickers and the
functionality of selecting stock options.This test also verifies
if the action on a select button successfully runs in the application.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
assert len(at.tabs[0].selectbox[0].label) >= 5

at.tabs[0].selectbox[0].select_index(0).run()
assert not at.exception

def test_technical_indicator_options(self):
def test_technical_indicator_options(self,mock_get_sentiment):
"""
Test the technical indicator options in the Streamlit application
and checks the selection and value of technical indicators. This test
also verifies if the action on a select button successfully
runs in the application.
"""
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()

at = AppTest.from_file("../app.py", default_timeout=20).run()
at = AppTest.from_file("../app.py").run()
assert at.tabs[1].selectbox[0].label == 'Select Technical Indicator'
assert at.tabs[1].selectbox[0].options == ["MA", "RSI", "ROC", "BBP"]

Expand All @@ -97,67 +116,79 @@ def test_technical_indicator_options(self):
assert not at.exception
assert at.tabs[1].selectbox[0].value == "RSI"

def test_technical_indicator_length(self):
def test_technical_indicator_length(self,mock_get_sentiment):
"""
Test the input of technical indicator length in the Streamlit application
to checks the input of a numerical value for the technical
indicator length. This test also verifies if any valid user input
would run successfully in the application.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
assert at.tabs[1].number_input[0].label == 'Input a length'
at.tabs[1].number_input[0].set_value(5).run()
assert not at.exception

def test_number_of_days_input(self):
def test_number_of_days_input(self,mock_get_sentiment):
"""
Test the input of the number of days in the Streamlit application and
this test verifies the input of a numerical value for the number of days.
This test also verifies if any valid user input would run s
successfully in the application.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
at.tabs[2].number_input[0].set_value(50).run()
assert not at.exception

def test_percentage_change_option(self):
def test_percentage_change_option(self,mock_get_sentiment):
"""
Test the input of the percentage change in the Streamlit application
and this test verifies the input of a numerical value for the the
percentage change in stock price. This test also verifies if any valid
user input would run successfully in the application.
"""
at = AppTest.from_file("../app.py", default_timeout=10).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
at.tabs[2].number_input[1].set_value(-5).run()
assert not at.exception

def test_add_new_company_ticker_input(self):
def test_add_new_company_ticker_input(self,mock_get_sentiment):
"""
Test the input of a new company ticker in the Streamlit application.
This test verifies if any valid user input would run successfully in
the application.
"""
at = AppTest.from_file("../app.py", default_timeout=20).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
assert at.tabs[3].text_input[0].label == '➕ Add New Ticker'
assert at.tabs[3].text_input[0].set_value('AMZN').run()
assert not at.exception

def test_add_new_ticker_time_period_input(self):
def test_add_new_ticker_time_period_input(self,mock_get_sentiment):
"""
Test the input of time period for a new ticker in the Streamlit application.
This test checks the input of a time period for a newly added ticker symbol
and verifies if any valid user input would run successfully in the application.
"""
at = AppTest.from_file("../app.py", default_timeout=20).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
at.tabs[3].text_input[1].set_value('5d').run()
assert not at.exception

def update_data_for_new_ticker(self):
def update_data_for_new_ticker(self,mock_get_sentiment):
"""
Test the update of data for a newly added ticker in the Streamlit application.
This test verifies the functionality of updating data for a newly added ticker.
"""
at = AppTest.from_file("../app.py", default_timeout=20).run()
mock_get_sentiment.return_value = self.mocked_sentiment_dataframe
at = AppTest.from_file("../app.py").run()
at = AppTest.from_file("../app.py").run()
assert at.tabs[3].button[0].label == "🔁 Click to Update Ticker Data to the Most Recent"
at.tabs[3].button[0].click().run()
assert not at.exception
Expand Down
13 changes: 3 additions & 10 deletions dinero/tests/test_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

from backend.visualization import (
plot_stock_price,
plot_kpis
plot_kpis,
TIME_BUTTONS
)

class TestVisualization(unittest.TestCase):
Expand Down Expand Up @@ -48,16 +49,8 @@ def test_plot_stock_price_selector_view_adjustment(self):
and if y-axis range is set to auto.
"""
stock_price_fig = plot_stock_price('MSFT')
time_buttons = [
{'step': 'all', 'label': 'All'},
{'count': 3, 'step': 'year', 'stepmode': 'backward', 'label': '3 Year'},
{'count': 1, 'step': 'year', 'stepmode': 'backward', 'label': '1 Year'},
{'count': 6, 'step': 'month', 'stepmode': 'backward', 'label': '6 Month'},
{'count': 1, 'step': 'month', 'stepmode': 'backward', 'label': '1 Month'},
{'count': 1, 'step': 'year', 'stepmode': 'todate', 'label': '1 Year To Date'}
]
self.assertEqual(len(stock_price_fig.layout.xaxis.rangeselector.buttons),
len(time_buttons))
len(TIME_BUTTONS))
self.assertTrue(stock_price_fig.layout.yaxis.autorange)
self.assertFalse(stock_price_fig.layout.yaxis.fixedrange)

Expand Down
Loading