Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -297,7 +297,8 @@ with market_analysis:
|
|
| 297 |
fig = go.Figure()
|
| 298 |
|
| 299 |
# Add RSI line
|
| 300 |
-
fig.add_trace(go.Scatter(x=data2['Date'], y=data2['RSI'], mode='lines', name='RSI')
|
|
|
|
| 301 |
|
| 302 |
# Add overbought and oversold lines
|
| 303 |
overbought_strong = 79
|
|
@@ -448,56 +449,69 @@ with news_analysis:
|
|
| 448 |
figure.update_yaxes(fixedrange=False)
|
| 449 |
st.plotly_chart(figure)
|
| 450 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 451 |
news = events[events['Date'].between(start_date, end_date, inclusive='both')]
|
| 452 |
-
news = news[['Date', 'Raw_Headline', 'Bold_KW', '
|
| 453 |
|
| 454 |
-
|
| 455 |
-
# Extract only the date part
|
| 456 |
news['Date'] = news['Date'].dt.date
|
| 457 |
|
| 458 |
# Sort DataFrame based on the 'Date' column in descending order
|
| 459 |
news = news.sort_values(by='Date', ascending=False)
|
| 460 |
|
| 461 |
-
|
| 462 |
# Reset index to reflect the new order
|
| 463 |
news.reset_index(drop=True, inplace=True)
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
dates = list(news['Date'].unique())
|
| 468 |
-
|
|
|
|
| 469 |
dates = np.sort(dates)
|
|
|
|
| 470 |
# Reverse the array to have the latest date at index 0
|
| 471 |
dates = dates[::-1]
|
| 472 |
-
|
|
|
|
| 473 |
num_dates = len(dates)
|
| 474 |
items_per_page = min(num_dates, 5)
|
|
|
|
|
|
|
| 475 |
for i, date in paginator("Select Page Number", dates, items_per_page=items_per_page, on_sidebar=False, ukey='news_pages'):
|
|
|
|
| 476 |
st.write(f'<span style="font-size: large;"><b>Date:</b> <u>{date}</u></span>', unsafe_allow_html=True)
|
|
|
|
|
|
|
| 477 |
filtered_news = news[news['Date'] == date]
|
| 478 |
-
|
|
|
|
| 479 |
features = filtered_news['SetFeature'].sum()
|
| 480 |
headlines = filtered_news['Raw_Headline'].sum()
|
| 481 |
news_list = filtered_news['Raw_News'].sum()
|
| 482 |
sources = filtered_news['Sources'].sum()
|
| 483 |
urls = filtered_news['Urls'].sum()
|
| 484 |
|
|
|
|
| 485 |
main_container = st.container(height = 250, border=True)
|
| 486 |
-
|
| 487 |
-
|
| 488 |
col1, col2 = main_container.columns([0.7, 0.3], gap='medium')
|
| 489 |
|
| 490 |
-
#
|
| 491 |
for index, headline in enumerate(headlines):
|
|
|
|
| 492 |
col1.page_link(urls[index], label=f"**:blue[{headline}]**")
|
| 493 |
-
#
|
| 494 |
col1.write(f"<span style='font-size: small;'>By {sources[index]}</span><br>", unsafe_allow_html=True)
|
|
|
|
| 495 |
with col1:
|
| 496 |
with st.expander("Show Full Article"):
|
| 497 |
st.write(news_list[index])
|
| 498 |
|
|
|
|
| 499 |
with col2:
|
| 500 |
-
# st.divider()
|
| 501 |
with st.expander("Oil Sector Features"):
|
| 502 |
st.write(set(features))
|
| 503 |
|
|
@@ -517,26 +531,41 @@ with final_recs:
|
|
| 517 |
# The results shown here are based on our model's inference on this test data, which is available in the Colab Notebook provided along GitHub submission.
|
| 518 |
# """)
|
| 519 |
|
| 520 |
-
|
| 521 |
recs = pd.read_csv("test_recom.csv")
|
|
|
|
|
|
|
| 522 |
recs['Date'] = pd.to_datetime(recs['Date'])
|
|
|
|
|
|
|
| 523 |
recs['Date'] = recs['Date'].dt.date
|
|
|
|
|
|
|
| 524 |
rec_dates = np.sort(list(recs['Date'].unique()))
|
|
|
|
|
|
|
| 525 |
pred_date = st.selectbox("Pick the Test Date", rec_dates)
|
| 526 |
-
fp = {}
|
| 527 |
-
for index, d in enumerate(rec_dates[:-1]):
|
| 528 |
-
fr = recs[recs['Date'] == rec_dates[index+1]]
|
| 529 |
-
fr.reset_index(inplace=True, drop=True)
|
| 530 |
-
following_price = fr['Price'][0]
|
| 531 |
-
fp[d] = following_price
|
| 532 |
-
|
| 533 |
-
fp[rec_dates[-1]] = 'Not Available'
|
| 534 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
role = st.radio(
|
| 536 |
"Show recommendation summary as:",
|
| 537 |
["Active Trader", "Equity Analyst"], horizontal=True)
|
| 538 |
-
|
|
|
|
| 539 |
filter_recs = recs[recs['Date'] == pred_date]
|
|
|
|
|
|
|
| 540 |
if role == 'Active Trader':
|
| 541 |
trade_recs = filter_recs[['Date', 'Recommendations_Active_Trader', 'Price']]
|
| 542 |
# Convert back to Dictionaries from strings
|
|
@@ -547,25 +576,35 @@ with final_recs:
|
|
| 547 |
# Convert back to Dictionaries from strings
|
| 548 |
trade_recs['Recommendations_Equity_Analyst'] = trade_recs['Recommendations_Equity_Analyst'].apply(convert_str_to_list)
|
| 549 |
trade_recs.rename(columns={'Recommendations_Equity_Analyst': 'Recommendations'}, inplace=True)
|
| 550 |
-
|
| 551 |
-
|
|
|
|
|
|
|
|
|
|
| 552 |
genrec_container = st.container(border=False)
|
|
|
|
|
|
|
| 553 |
rec_col1, rec_col2, rec_col3 = genrec_container.columns(3, gap='medium')
|
| 554 |
-
|
| 555 |
-
|
| 556 |
rec_col1.write(f'<span style="font-size: large;"><b>Current Date:</b> <u>{pred_date}</u></span>', unsafe_allow_html=True)
|
|
|
|
|
|
|
| 557 |
rec_col2.write(f'<span style="font-size: large;"><b>Current Close Price:</b> {current_price}</span>', unsafe_allow_html=True)
|
|
|
|
| 558 |
rec_col3.write(f'<span style="font-size: large;"><b>Following Close Price:</b> {fp[pred_date]}</span>', unsafe_allow_html=True)
|
| 559 |
-
|
|
|
|
| 560 |
genrec_container.subheader("Generated Recommendation")
|
| 561 |
genrec_container.write(trade_recs['Recommendations'][0])
|
| 562 |
-
|
|
|
|
| 563 |
# Create the line trace for stock prices
|
| 564 |
line_stock = go.Scatter(x=events['Date'], y=events['Price'], mode='lines', name='OGDCL Close Price',
|
| 565 |
line=dict(dash='solid', color=cs.close_line_color, width=2),
|
| 566 |
# text=events['Cleaned_Headline'],
|
| 567 |
# hovertext=events['FeatureSentiment'],
|
| 568 |
-
customdata=events['
|
| 569 |
hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>',
|
| 570 |
# hoverlabel=dict(font=dict(color=events
|
| 571 |
# ['FeatureSentiment'].apply(lambda x: 'red' if x == 'Negative' else 'blue' if x == 'Neutral' else 'green'))), # Customize the line style, color, and width
|
|
@@ -590,12 +629,16 @@ with final_recs:
|
|
| 590 |
|
| 591 |
# Add all traces to the figure
|
| 592 |
figure = go.Figure(data=[line_stock], layout=layout)
|
|
|
|
| 593 |
figure.add_scatter(x=plot_sub_pos['Date'], y=plot_sub_pos['Price'], mode='markers',
|
| 594 |
marker=dict(symbol='triangle-up', size=10, color=cs.pos_impacts_color), name='Positive Impact',
|
| 595 |
customdata=plot_sub_pos['SetFeature'], hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>')
|
|
|
|
| 596 |
figure.add_scatter(x=plot_sub_neg['Date'], y=plot_sub_neg['Price'], mode='markers',
|
| 597 |
marker=dict(symbol='triangle-down', size=10, color=cs.neg_impacts_color), name='Negative Impact',
|
| 598 |
customdata=plot_sub_neg['SetFeature'], hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>',)
|
|
|
|
|
|
|
| 599 |
figure.update_layout(
|
| 600 |
title={
|
| 601 |
'text': title,
|
|
@@ -608,8 +651,8 @@ with final_recs:
|
|
| 608 |
hovermode='closest',
|
| 609 |
margin=dict(l=40, r=40, t=80, b=40),
|
| 610 |
modebar_add="togglespikelines",
|
| 611 |
-
# scrollZoom=True,
|
| 612 |
)
|
|
|
|
| 613 |
figure.update_xaxes(
|
| 614 |
rangeslider_visible=True,
|
| 615 |
rangeselector=dict(
|
|
|
|
| 297 |
fig = go.Figure()
|
| 298 |
|
| 299 |
# Add RSI line
|
| 300 |
+
fig.add_trace(go.Scatter(x=data2['Date'], y=data2['RSI'], mode='lines', name='RSI'),
|
| 301 |
+
line=dict(dash='solid', color=cs.rsi_color, width=2))
|
| 302 |
|
| 303 |
# Add overbought and oversold lines
|
| 304 |
overbought_strong = 79
|
|
|
|
| 449 |
figure.update_yaxes(fixedrange=False)
|
| 450 |
st.plotly_chart(figure)
|
| 451 |
|
| 452 |
+
# Add subheader for news section
|
| 453 |
+
st.subheader("News Events")
|
| 454 |
+
"""In this section, news events for each date in the data will be displayed along the features for that date"""
|
| 455 |
+
# Filter data for news events
|
| 456 |
news = events[events['Date'].between(start_date, end_date, inclusive='both')]
|
| 457 |
+
news = news[['Date', 'Raw_Headline', 'Bold_KW', 'SetFeature', 'Raw_News', 'Sources', 'Urls']]
|
| 458 |
|
| 459 |
+
# Extract only the date from the datetime
|
|
|
|
| 460 |
news['Date'] = news['Date'].dt.date
|
| 461 |
|
| 462 |
# Sort DataFrame based on the 'Date' column in descending order
|
| 463 |
news = news.sort_values(by='Date', ascending=False)
|
| 464 |
|
|
|
|
| 465 |
# Reset index to reflect the new order
|
| 466 |
news.reset_index(drop=True, inplace=True)
|
| 467 |
+
|
| 468 |
+
# Get all the unique dates to iterate over
|
|
|
|
| 469 |
dates = list(news['Date'].unique())
|
| 470 |
+
|
| 471 |
+
# Sort the date list
|
| 472 |
dates = np.sort(dates)
|
| 473 |
+
|
| 474 |
# Reverse the array to have the latest date at index 0
|
| 475 |
dates = dates[::-1]
|
| 476 |
+
|
| 477 |
+
# Decide number of items to display per page
|
| 478 |
num_dates = len(dates)
|
| 479 |
items_per_page = min(num_dates, 5)
|
| 480 |
+
|
| 481 |
+
# iterate over the paginator
|
| 482 |
for i, date in paginator("Select Page Number", dates, items_per_page=items_per_page, on_sidebar=False, ukey='news_pages'):
|
| 483 |
+
# Display the date
|
| 484 |
st.write(f'<span style="font-size: large;"><b>Date:</b> <u>{date}</u></span>', unsafe_allow_html=True)
|
| 485 |
+
|
| 486 |
+
# Filter data for each date in the loop
|
| 487 |
filtered_news = news[news['Date'] == date]
|
| 488 |
+
|
| 489 |
+
# Extract the details required
|
| 490 |
features = filtered_news['SetFeature'].sum()
|
| 491 |
headlines = filtered_news['Raw_Headline'].sum()
|
| 492 |
news_list = filtered_news['Raw_News'].sum()
|
| 493 |
sources = filtered_news['Sources'].sum()
|
| 494 |
urls = filtered_news['Urls'].sum()
|
| 495 |
|
| 496 |
+
# Create a container to display news for each date
|
| 497 |
main_container = st.container(height = 250, border=True)
|
| 498 |
+
|
| 499 |
+
# Create columns to display news on one side and features on the other
|
| 500 |
col1, col2 = main_container.columns([0.7, 0.3], gap='medium')
|
| 501 |
|
| 502 |
+
# Display each headline in the extracted headlines in the container
|
| 503 |
for index, headline in enumerate(headlines):
|
| 504 |
+
# Link news article's Url to the headline to redirect to the source article webpage on click
|
| 505 |
col1.page_link(urls[index], label=f"**:blue[{headline}]**")
|
| 506 |
+
# Display news source in the container
|
| 507 |
col1.write(f"<span style='font-size: small;'>By {sources[index]}</span><br>", unsafe_allow_html=True)
|
| 508 |
+
# Display news content on click
|
| 509 |
with col1:
|
| 510 |
with st.expander("Show Full Article"):
|
| 511 |
st.write(news_list[index])
|
| 512 |
|
| 513 |
+
# Display features on click
|
| 514 |
with col2:
|
|
|
|
| 515 |
with st.expander("Oil Sector Features"):
|
| 516 |
st.write(set(features))
|
| 517 |
|
|
|
|
| 531 |
# The results shown here are based on our model's inference on this test data, which is available in the Colab Notebook provided along GitHub submission.
|
| 532 |
# """)
|
| 533 |
|
| 534 |
+
# Load generated recommendations data
|
| 535 |
recs = pd.read_csv("test_recom.csv")
|
| 536 |
+
|
| 537 |
+
# Convert date column to datetime values
|
| 538 |
recs['Date'] = pd.to_datetime(recs['Date'])
|
| 539 |
+
|
| 540 |
+
# Get only the date from datetime
|
| 541 |
recs['Date'] = recs['Date'].dt.date
|
| 542 |
+
|
| 543 |
+
# Get all the unique dates to add to the selectbox and to iterate over
|
| 544 |
rec_dates = np.sort(list(recs['Date'].unique()))
|
| 545 |
+
|
| 546 |
+
# Create the date select box
|
| 547 |
pred_date = st.selectbox("Pick the Test Date", rec_dates)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
|
| 549 |
+
# Store the close price value of the following day for each date in a dictionary to call later
|
| 550 |
+
fp = {} # initialize an empty dictionary
|
| 551 |
+
for index, d in enumerate(rec_dates[:-1]): # iterate over the unique dates
|
| 552 |
+
fr = recs[recs['Date'] == rec_dates[index+1]] # get data of the following day
|
| 553 |
+
fr.reset_index(inplace=True, drop=True) # reset index
|
| 554 |
+
following_price = fr['Price'][0 # get close price
|
| 555 |
+
fp[d] = following_price # append dictionary
|
| 556 |
+
|
| 557 |
+
# As no following day data is available for the latest date in the list, assign it 'Not Available'
|
| 558 |
+
fp[rec_dates[-1]] = 'Not Available'
|
| 559 |
+
|
| 560 |
+
# Add radio buttons to select role
|
| 561 |
role = st.radio(
|
| 562 |
"Show recommendation summary as:",
|
| 563 |
["Active Trader", "Equity Analyst"], horizontal=True)
|
| 564 |
+
|
| 565 |
+
# filter data based on the date selected by the user
|
| 566 |
filter_recs = recs[recs['Date'] == pred_date]
|
| 567 |
+
|
| 568 |
+
# filter required data based on the role selected by the user
|
| 569 |
if role == 'Active Trader':
|
| 570 |
trade_recs = filter_recs[['Date', 'Recommendations_Active_Trader', 'Price']]
|
| 571 |
# Convert back to Dictionaries from strings
|
|
|
|
| 576 |
# Convert back to Dictionaries from strings
|
| 577 |
trade_recs['Recommendations_Equity_Analyst'] = trade_recs['Recommendations_Equity_Analyst'].apply(convert_str_to_list)
|
| 578 |
trade_recs.rename(columns={'Recommendations_Equity_Analyst': 'Recommendations'}, inplace=True)
|
| 579 |
+
|
| 580 |
+
# reset index after filteration
|
| 581 |
+
trade_recs.reset_index(inplace=True, drop=True)
|
| 582 |
+
|
| 583 |
+
# create container to display generated recommendations
|
| 584 |
genrec_container = st.container(border=False)
|
| 585 |
+
|
| 586 |
+
# create columns to display date, current close price, and following day close price side-by-side
|
| 587 |
rec_col1, rec_col2, rec_col3 = genrec_container.columns(3, gap='medium')
|
| 588 |
+
|
| 589 |
+
# Show selected date
|
| 590 |
rec_col1.write(f'<span style="font-size: large;"><b>Current Date:</b> <u>{pred_date}</u></span>', unsafe_allow_html=True)
|
| 591 |
+
# Show selected date close price
|
| 592 |
+
current_price = trade_recs['Price'][0]
|
| 593 |
rec_col2.write(f'<span style="font-size: large;"><b>Current Close Price:</b> {current_price}</span>', unsafe_allow_html=True)
|
| 594 |
+
# Show following day close price
|
| 595 |
rec_col3.write(f'<span style="font-size: large;"><b>Following Close Price:</b> {fp[pred_date]}</span>', unsafe_allow_html=True)
|
| 596 |
+
|
| 597 |
+
# Show generated recommendations
|
| 598 |
genrec_container.subheader("Generated Recommendation")
|
| 599 |
genrec_container.write(trade_recs['Recommendations'][0])
|
| 600 |
+
|
| 601 |
+
# Show Market and News Analysis w.r.t. OGDCL Close Price chart
|
| 602 |
# Create the line trace for stock prices
|
| 603 |
line_stock = go.Scatter(x=events['Date'], y=events['Price'], mode='lines', name='OGDCL Close Price',
|
| 604 |
line=dict(dash='solid', color=cs.close_line_color, width=2),
|
| 605 |
# text=events['Cleaned_Headline'],
|
| 606 |
# hovertext=events['FeatureSentiment'],
|
| 607 |
+
customdata=events['SetFeature'],
|
| 608 |
hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>',
|
| 609 |
# hoverlabel=dict(font=dict(color=events
|
| 610 |
# ['FeatureSentiment'].apply(lambda x: 'red' if x == 'Negative' else 'blue' if x == 'Neutral' else 'green'))), # Customize the line style, color, and width
|
|
|
|
| 629 |
|
| 630 |
# Add all traces to the figure
|
| 631 |
figure = go.Figure(data=[line_stock], layout=layout)
|
| 632 |
+
# Add positive impact
|
| 633 |
figure.add_scatter(x=plot_sub_pos['Date'], y=plot_sub_pos['Price'], mode='markers',
|
| 634 |
marker=dict(symbol='triangle-up', size=10, color=cs.pos_impacts_color), name='Positive Impact',
|
| 635 |
customdata=plot_sub_pos['SetFeature'], hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>')
|
| 636 |
+
# Add negative impact
|
| 637 |
figure.add_scatter(x=plot_sub_neg['Date'], y=plot_sub_neg['Price'], mode='markers',
|
| 638 |
marker=dict(symbol='triangle-down', size=10, color=cs.neg_impacts_color), name='Negative Impact',
|
| 639 |
customdata=plot_sub_neg['SetFeature'], hovertemplate='%{x}<br>Close: %{y}<br>Feature: %{customdata}<br>',)
|
| 640 |
+
|
| 641 |
+
# Update layout
|
| 642 |
figure.update_layout(
|
| 643 |
title={
|
| 644 |
'text': title,
|
|
|
|
| 651 |
hovermode='closest',
|
| 652 |
margin=dict(l=40, r=40, t=80, b=40),
|
| 653 |
modebar_add="togglespikelines",
|
|
|
|
| 654 |
)
|
| 655 |
+
# Add date range selection buttons to chart
|
| 656 |
figure.update_xaxes(
|
| 657 |
rangeslider_visible=True,
|
| 658 |
rangeselector=dict(
|