Spaces:
Runtime error
Runtime error
Upload app.py
Browse files
app.py
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st # for overall GUI
|
2 |
+
from streamlit_calendar import calendar # to show calendar
|
3 |
+
from dateutil.relativedelta import relativedelta # for addition to dates
|
4 |
+
import datetime
|
5 |
+
import os # for extracting environment variable
|
6 |
+
from urllib.request import urlopen # for getting data from FMP API
|
7 |
+
import json # for parsing data from FMP API
|
8 |
+
|
9 |
+
def get_jsonparsed_data(url):
|
10 |
+
response = urlopen(url)
|
11 |
+
data = response.read().decode("utf-8")
|
12 |
+
return json.loads(data)
|
13 |
+
|
14 |
+
# Financialmodelingprep (FMP) api base url
|
15 |
+
base_url = "https://financialmodelingprep.com/api/v3/"
|
16 |
+
|
17 |
+
# Get FMP API stored as environment variable
|
18 |
+
apiKey = os.environ['FMP_API_KEY']
|
19 |
+
|
20 |
+
# Get today's date and add 3 months to it
|
21 |
+
# Convert both today's date and the 3 months later date to strings (for input into API endpoint URL later)
|
22 |
+
# This is the date range within which we want to get our earnings dates
|
23 |
+
today = datetime.datetime.today()
|
24 |
+
today_string = today.strftime('%Y-%m-%d')
|
25 |
+
future_string = (today + relativedelta(months=3)).strftime('%Y-%m-%d')
|
26 |
+
|
27 |
+
# This is the full API endpoint to get the earnings dates from today to 6 months after
|
28 |
+
url = f"{base_url}earning_calendar?from={today_string}&to={future_string}&apikey={apiKey}"
|
29 |
+
|
30 |
+
# This decorator ensures that the call to the FMP API will only run once at the start of this app
|
31 |
+
# The data will be cached after running
|
32 |
+
# Without this decorator, the API will be called each time
|
33 |
+
@st.experimental_singleton
|
34 |
+
def get_earnings_dates(url):
|
35 |
+
events = get_jsonparsed_data(url)
|
36 |
+
return events
|
37 |
+
|
38 |
+
events = get_earnings_dates(url)
|
39 |
+
|
40 |
+
|
41 |
+
with st.sidebar:
|
42 |
+
st.title("Stock Earnings π App")
|
43 |
+
st.header("Choose Tickers of Interest")
|
44 |
+
#tickers = ['GOOG', 'META', 'TSLA', 'NET', 'V', 'MA', 'BA', 'C']
|
45 |
+
|
46 |
+
# For users to enter tickers of interest
|
47 |
+
tickers_string = st.text_area('Enter all stock tickers to be included in calendar, separated by commas \
|
48 |
+
e.g. "MA, META, V, AMZN, JPM, BA"',
|
49 |
+
value = 'GOOG, META, AAPL, MSFT, NVDA, NFLX, V, MA, AMZN, TSLA, JPM, BAC, BA, MMM, NET, C, CRM, PLTR, BABA').upper()
|
50 |
+
|
51 |
+
st.write('')
|
52 |
+
st.write('')
|
53 |
+
# Where the data came from
|
54 |
+
st.markdown("## [Financial Modeling Prep API](https://intelligence.financialmodelingprep.com/pricing-plans?couponCode=damianboh&utm_campaign=damianboh&utm_medium=blog&utm_source=medium)\
|
55 |
+
\n\nEarnings Dates for all tickers are obtained from the FinancialModelingPrep API, feel free to sign up\
|
56 |
+
[here](https://intelligence.financialmodelingprep.com/pricing-plans?couponCode=damianboh&utm_campaign=damianboh&utm_medium=blog&utm_source=medium)\
|
57 |
+
if you wish.")
|
58 |
+
|
59 |
+
# Parse user input into a list
|
60 |
+
tickers_string = tickers_string.replace(' ', '')
|
61 |
+
tickers = tickers_string.split(',')
|
62 |
+
|
63 |
+
# Converts the parsed json from FMP API into a list of events to be passed into streamlit_calendar
|
64 |
+
calendar_events = []
|
65 |
+
for event in events:
|
66 |
+
if event['symbol'] in tickers:
|
67 |
+
calendar_event = {}
|
68 |
+
calendar_event['title'] = event['symbol']
|
69 |
+
if event['time'] == 'bmo': # before market opens, add sunrise symbol
|
70 |
+
calendar_event['title'] = 'β ' + calendar_event['title']
|
71 |
+
elif event['time'] == 'amc': # after market closes, add sunset symbol
|
72 |
+
calendar_event['title'] = 'π
' + calendar_event['title']
|
73 |
+
calendar_event['start'] = event['date']
|
74 |
+
calendar_events.append(calendar_event)
|
75 |
+
|
76 |
+
st.header("Stock Earnings Calendar π")
|
77 |
+
|
78 |
+
|
79 |
+
calendar_options = {
|
80 |
+
"editable": "true",
|
81 |
+
"navLinks": "true",
|
82 |
+
"headerToolbar": {
|
83 |
+
"left": "today prev,next",
|
84 |
+
"center": "title",
|
85 |
+
"right": "dayGridDay,dayGridWeek,dayGridMonth,listMonth",
|
86 |
+
},
|
87 |
+
#"initialDate": today.strftime('%Y-%m-%d'),
|
88 |
+
"initialView": "dayGridMonth"
|
89 |
+
}
|
90 |
+
|
91 |
+
|
92 |
+
custom_css="""
|
93 |
+
.fc-event-past {
|
94 |
+
opacity: 0.8;
|
95 |
+
}
|
96 |
+
.fc-event-time {
|
97 |
+
font-style: italic;
|
98 |
+
}
|
99 |
+
.fc-event-title {
|
100 |
+
font-weight: 700;
|
101 |
+
}
|
102 |
+
.fc-toolbar-title {
|
103 |
+
font-size: 2rem;
|
104 |
+
}
|
105 |
+
"""
|
106 |
+
|
107 |
+
|
108 |
+
calendar = calendar(events=calendar_events, options=calendar_options, custom_css=custom_css)
|