Update app.py
Browse files
app.py
CHANGED
@@ -516,6 +516,20 @@ def predict_stock_prices():
|
|
516 |
else:
|
517 |
st.error("Failed to fetch stock data. Please try again.")
|
518 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
519 |
def explore_data():
|
520 |
st.header("Explore Stock Data")
|
521 |
|
@@ -531,104 +545,203 @@ def explore_data():
|
|
531 |
|
532 |
if st.button("Explore Data"):
|
533 |
with st.spinner("Fetching and analyzing data..."):
|
534 |
-
|
|
|
535 |
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
# Create tabs for different visualizations
|
540 |
-
tab1, tab2, tab3, tab4, tab5 = st.tabs(["Price History", "OHLC", "Technical Indicators", "Volume & Turnover", "Statistics"])
|
541 |
-
|
542 |
-
with tab1:
|
543 |
-
# Stock Price History
|
544 |
-
fig = go.Figure()
|
545 |
-
fig.add_trace(go.Scatter(x=data.index, y=data['Open'], mode='lines', name='Open'))
|
546 |
-
fig.add_trace(go.Scatter(x=data.index, y=data['High'], mode='lines', name='High'))
|
547 |
-
fig.add_trace(go.Scatter(x=data.index, y=data['Low'], mode='lines', name='Low'))
|
548 |
-
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
|
549 |
|
550 |
-
#
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
622 |
|
623 |
-
|
624 |
-
|
625 |
-
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
|
626 |
-
fig.update_yaxes(title_text="Volume", row=1, col=1)
|
627 |
-
fig.update_yaxes(title_text="Turnover", row=2, col=1)
|
628 |
|
629 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
630 |
|
631 |
-
with tab5:
|
632 |
# Display key statistics
|
633 |
st.subheader("Key Statistics")
|
634 |
col1, col2, col3 = st.columns(3)
|
@@ -643,20 +756,10 @@ def explore_data():
|
|
643 |
st.metric("Avg Daily Return", f"{returns.mean():.2f}%")
|
644 |
st.metric("Return Volatility", f"{returns.std():.2f}%")
|
645 |
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
st.plotly_chart(heatmap_fig, use_container_width=True)
|
651 |
-
|
652 |
-
# Display news
|
653 |
-
st.subheader("Latest News")
|
654 |
-
news = fetch_news(company_name)
|
655 |
-
for item in news:
|
656 |
-
st.markdown(f"[{item['title']}]({item['link']}) ({item['pubDate']})")
|
657 |
-
|
658 |
-
else:
|
659 |
-
st.error("Failed to fetch data. Please try again.")
|
660 |
|
661 |
if __name__ == "__main__":
|
662 |
main()
|
|
|
516 |
else:
|
517 |
st.error("Failed to fetch stock data. Please try again.")
|
518 |
|
519 |
+
def calculate_bollinger_bands(data, window=20, num_std=2):
|
520 |
+
rolling_mean = data.rolling(window=window).mean()
|
521 |
+
rolling_std = data.rolling(window=window).std()
|
522 |
+
upper_band = rolling_mean + (rolling_std * num_std)
|
523 |
+
lower_band = rolling_mean - (rolling_std * num_std)
|
524 |
+
return upper_band, lower_band
|
525 |
+
|
526 |
+
def calculate_rsi(data, window=14):
|
527 |
+
delta = data.diff()
|
528 |
+
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
|
529 |
+
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
|
530 |
+
rs = gain / loss
|
531 |
+
return 100 - (100 / (1 + rs))
|
532 |
+
|
533 |
def explore_data():
|
534 |
st.header("Explore Stock Data")
|
535 |
|
|
|
545 |
|
546 |
if st.button("Explore Data"):
|
547 |
with st.spinner("Fetching and analyzing data..."):
|
548 |
+
try:
|
549 |
+
data = yf.download(ticker, period=period)
|
550 |
|
551 |
+
if data is not None and not data.empty:
|
552 |
+
st.subheader(f"{company_name} Stock Data")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
553 |
|
554 |
+
# Create tabs for different visualizations
|
555 |
+
tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs([
|
556 |
+
"Price History", "OHLC", "Technical Indicators",
|
557 |
+
"Volume Analysis", "Returns Distribution", "Moving Averages"
|
558 |
+
])
|
559 |
|
560 |
+
with tab1:
|
561 |
+
st.markdown("""
|
562 |
+
### Price History
|
563 |
+
This chart shows the historical closing prices of the stock over time.
|
564 |
+
|
565 |
+
**How to use**:
|
566 |
+
- Use the slider at the bottom to zoom in on specific time periods.
|
567 |
+
- Hover over the line to see exact prices at different dates.
|
568 |
+
|
569 |
+
**How it helps**:
|
570 |
+
- Identify long-term trends in the stock's price.
|
571 |
+
- Spot key price levels and potential support/resistance areas.
|
572 |
+
- Understand the overall price movement and volatility of the stock.
|
573 |
+
""")
|
574 |
+
|
575 |
+
fig = go.Figure()
|
576 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
|
577 |
+
|
578 |
+
fig.update_layout(title=f"{company_name} Stock Price History",
|
579 |
+
xaxis_title="Date",
|
580 |
+
yaxis_title="Price",
|
581 |
+
hovermode="x unified",
|
582 |
+
template="plotly_dark")
|
583 |
+
st.plotly_chart(fig, use_container_width=True)
|
584 |
+
|
585 |
+
with tab2:
|
586 |
+
st.markdown("""
|
587 |
+
### OHLC (Open-High-Low-Close) Chart
|
588 |
+
This candlestick chart shows the opening, high, low, and closing prices for each trading day.
|
589 |
+
|
590 |
+
**How to use**:
|
591 |
+
- Green candles indicate days where the closing price was higher than the opening price.
|
592 |
+
- Red candles indicate days where the closing price was lower than the opening price.
|
593 |
+
- The thin lines (wicks) show the high and low prices for the day.
|
594 |
+
|
595 |
+
**How it helps**:
|
596 |
+
- Identify daily price movements and volatility.
|
597 |
+
- Spot potential reversal patterns or trends.
|
598 |
+
- Understand the intraday price action of the stock.
|
599 |
+
""")
|
600 |
+
|
601 |
+
ohlc_fig = go.Figure(data=[go.Candlestick(x=data.index,
|
602 |
+
open=data['Open'],
|
603 |
+
high=data['High'],
|
604 |
+
low=data['Low'],
|
605 |
+
close=data['Close'])])
|
606 |
+
ohlc_fig.update_layout(title=f"{company_name} OHLC Chart",
|
607 |
+
xaxis_title="Date",
|
608 |
+
yaxis_title="Price",
|
609 |
+
template="plotly_dark",
|
610 |
+
xaxis_rangeslider_visible=False)
|
611 |
+
st.plotly_chart(ohlc_fig, use_container_width=True)
|
612 |
+
|
613 |
+
with tab3:
|
614 |
+
st.markdown("""
|
615 |
+
### Technical Indicators
|
616 |
+
This chart displays various technical indicators alongside the stock price.
|
617 |
+
|
618 |
+
**How to use**:
|
619 |
+
- The top chart shows the stock price with SMA (Simple Moving Average), EMA (Exponential Moving Average), and Bollinger Bands.
|
620 |
+
- The bottom chart shows the RSI (Relative Strength Index).
|
621 |
+
|
622 |
+
**How it helps**:
|
623 |
+
- Identify potential buy/sell signals using moving average crossovers.
|
624 |
+
- Spot overbought or oversold conditions using RSI.
|
625 |
+
- Understand price volatility using Bollinger Bands.
|
626 |
+
- Combine multiple indicators for more robust trading decisions.
|
627 |
+
""")
|
628 |
+
|
629 |
+
data['SMA_20'] = data['Close'].rolling(window=20).mean()
|
630 |
+
data['EMA_20'] = data['Close'].ewm(span=20, adjust=False).mean()
|
631 |
+
data['Upper_BB'], data['Lower_BB'] = calculate_bollinger_bands(data['Close'])
|
632 |
+
data['RSI'] = calculate_rsi(data['Close'])
|
633 |
+
|
634 |
+
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
|
635 |
+
vertical_spacing=0.03,
|
636 |
+
subplot_titles=("Price and Indicators", "RSI"),
|
637 |
+
row_heights=[0.7, 0.3])
|
638 |
+
|
639 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'), row=1, col=1)
|
640 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['SMA_20'], mode='lines', name='SMA 20'), row=1, col=1)
|
641 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['EMA_20'], mode='lines', name='EMA 20'), row=1, col=1)
|
642 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Upper_BB'], mode='lines', name='Upper BB'), row=1, col=1)
|
643 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Lower_BB'], mode='lines', name='Lower BB'), row=1, col=1)
|
644 |
+
|
645 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI'), row=2, col=1)
|
646 |
+
fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
|
647 |
+
fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
|
648 |
+
|
649 |
+
fig.update_layout(height=800, title_text=f"{company_name} Technical Indicators",
|
650 |
+
hovermode="x unified", template="plotly_dark")
|
651 |
+
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
|
652 |
+
fig.update_yaxes(title_text="Price", row=1, col=1)
|
653 |
+
fig.update_yaxes(title_text="RSI", row=2, col=1)
|
654 |
+
|
655 |
+
st.plotly_chart(fig, use_container_width=True)
|
656 |
+
|
657 |
+
with tab4:
|
658 |
+
st.markdown("""
|
659 |
+
### Volume Analysis
|
660 |
+
This chart shows the trading volume alongside the stock price.
|
661 |
+
|
662 |
+
**How to use**:
|
663 |
+
- The top chart displays the daily trading volume.
|
664 |
+
- The bottom chart shows the corresponding stock price.
|
665 |
+
|
666 |
+
**How it helps**:
|
667 |
+
- Identify periods of high and low trading activity.
|
668 |
+
- Confirm price trends (higher volume often validates price movements).
|
669 |
+
- Spot potential reversals (e.g., high volume at price extremes).
|
670 |
+
- Understand the liquidity of the stock.
|
671 |
+
""")
|
672 |
+
|
673 |
+
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
|
674 |
+
vertical_spacing=0.03,
|
675 |
+
subplot_titles=("Volume", "Price"),
|
676 |
+
row_heights=[0.7, 0.3])
|
677 |
|
678 |
+
fig.add_trace(go.Bar(x=data.index, y=data['Volume'], name='Volume'), row=1, col=1)
|
679 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price'), row=2, col=1)
|
|
|
|
|
|
|
680 |
|
681 |
+
fig.update_layout(height=600, title_text=f"{company_name} Volume Analysis",
|
682 |
+
hovermode="x unified", template="plotly_dark")
|
683 |
+
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
|
684 |
+
fig.update_yaxes(title_text="Volume", row=1, col=1)
|
685 |
+
fig.update_yaxes(title_text="Price", row=2, col=1)
|
686 |
+
|
687 |
+
st.plotly_chart(fig, use_container_width=True)
|
688 |
+
|
689 |
+
with tab5:
|
690 |
+
st.markdown("""
|
691 |
+
### Returns Distribution
|
692 |
+
This histogram shows the distribution of daily returns for the stock.
|
693 |
+
|
694 |
+
**How to use**:
|
695 |
+
- The x-axis represents the daily return percentages.
|
696 |
+
- The y-axis shows the frequency of each return range.
|
697 |
+
|
698 |
+
**How it helps**:
|
699 |
+
- Understand the volatility and risk profile of the stock.
|
700 |
+
- Identify the most common daily return ranges.
|
701 |
+
- Spot any skewness or unusual patterns in returns.
|
702 |
+
- Compare the stock's return distribution to a normal distribution for risk assessment.
|
703 |
+
""")
|
704 |
+
|
705 |
+
returns = data['Close'].pct_change().dropna()
|
706 |
+
fig = go.Figure(data=[go.Histogram(x=returns, nbinsx=50)])
|
707 |
+
fig.update_layout(title=f"{company_name} Returns Distribution",
|
708 |
+
xaxis_title="Daily Returns",
|
709 |
+
yaxis_title="Frequency",
|
710 |
+
template="plotly_dark")
|
711 |
+
st.plotly_chart(fig, use_container_width=True)
|
712 |
+
|
713 |
+
with tab6:
|
714 |
+
st.markdown("""
|
715 |
+
### Moving Averages
|
716 |
+
This chart shows the stock price along with 50-day and 200-day Simple Moving Averages (SMA).
|
717 |
+
|
718 |
+
**How to use**:
|
719 |
+
- The blue line represents the stock's closing price.
|
720 |
+
- The orange line is the 50-day SMA.
|
721 |
+
- The green line is the 200-day SMA.
|
722 |
+
|
723 |
+
**How it helps**:
|
724 |
+
- Identify long-term trends in the stock price.
|
725 |
+
- Spot potential buy/sell signals when the price crosses above/below the moving averages.
|
726 |
+
- Recognize "Golden Cross" (50-day crosses above 200-day) and "Death Cross" (50-day crosses below 200-day) signals.
|
727 |
+
- Understand the overall momentum of the stock.
|
728 |
+
""")
|
729 |
+
|
730 |
+
data['SMA_50'] = data['Close'].rolling(window=50).mean()
|
731 |
+
data['SMA_200'] = data['Close'].rolling(window=200).mean()
|
732 |
+
|
733 |
+
fig = go.Figure()
|
734 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
|
735 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['SMA_50'], mode='lines', name='50-day SMA'))
|
736 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['SMA_200'], mode='lines', name='200-day SMA'))
|
737 |
+
|
738 |
+
fig.update_layout(title=f"{company_name} Moving Averages",
|
739 |
+
xaxis_title="Date",
|
740 |
+
yaxis_title="Price",
|
741 |
+
template="plotly_dark",
|
742 |
+
hovermode="x unified")
|
743 |
+
st.plotly_chart(fig, use_container_width=True)
|
744 |
|
|
|
745 |
# Display key statistics
|
746 |
st.subheader("Key Statistics")
|
747 |
col1, col2, col3 = st.columns(3)
|
|
|
756 |
st.metric("Avg Daily Return", f"{returns.mean():.2f}%")
|
757 |
st.metric("Return Volatility", f"{returns.std():.2f}%")
|
758 |
|
759 |
+
else:
|
760 |
+
st.error("Failed to fetch data. Please try again.")
|
761 |
+
except Exception as e:
|
762 |
+
st.error(f"An error occurred: {str(e)}. Please try a different time period or check your internet connection.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
763 |
|
764 |
if __name__ == "__main__":
|
765 |
main()
|