File size: 4,531 Bytes
c0c59ce
 
 
85b7a89
3c4450e
958b14a
 
 
011359b
ada01c4
 
 
 
 
 
 
3c4450e
 
 
 
 
 
ada01c4
3c4450e
 
f77f56c
ada01c4
 
 
 
 
f77f56c
ada01c4
f77f56c
 
ada01c4
 
 
 
 
f77f56c
ada01c4
 
 
 
45ab29a
 
 
 
 
 
94126ed
45ab29a
0424c3b
94126ed
602a247
 
 
 
 
ada01c4
94126ed
55e99f6
ada01c4
94126ed
ada01c4
 
3c4450e
 
 
 
94126ed
ada01c4
3c4450e
 
 
94126ed
55e99f6
3c4450e
 
 
94126ed
261a5a7
ada01c4
 
3c4450e
 
 
 
 
ada01c4
 
 
3c4450e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import streamlit as st
import yfinance as yf
import pandas as pd

@st.experimental_singleton
def get_sp500_list():
    table = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
    return table[0]['Symbol'].tolist()

def load_sp500_averages(filepath):
    return pd.read_csv(filepath, header=0, names=['Ratio', 'Average']).set_index('Ratio')

def fetch_stock_data(ticker_symbol):
    ticker = yf.Ticker(ticker_symbol)
    info = ticker.info
    financials = {
        'P/E Ratio': info.get('forwardPE'),
        'P/B Ratio': info.get('priceToBook'),
        'P/S Ratio': info.get('priceToSalesTrailing12Months'),
        'Debt to Equity Ratio': info.get('debtToEquity'),
        'Return on Equity': info.get('returnOnEquity'),
        'Book-to-Market Ratio': 1 / info.get('priceToBook') if info.get('priceToBook') else None
    }
    # Debug: Print to see if financials are fetched correctly
    print(f"Financials for {ticker_symbol}: {financials}")
    return financials, info

def compare_to_index(stock_ratios, index_averages):
    comparison = {}
    score = 0
    for ratio, value in stock_ratios.items():
        if ratio in index_averages.index and pd.notna(value):
            average = index_averages.loc[ratio, 'Average']
            comparison[ratio] = 'Undervalued' if value < average else 'Overvalued'
            score += 1 if value < average else -1
    return comparison, score

def calculate_combined_scores_for_stocks(stocks, index_averages):
    scores = []
    for ticker_symbol in stocks:
        stock_data, _ = fetch_stock_data(ticker_symbol)
        comparison, score = compare_to_index(stock_data, index_averages)
        scores.append({'Stock': ticker_symbol, 'Combined Score': score})
    return pd.DataFrame(scores)

def color_combined_score(value):
    if value > 0:
        color = 'green'
    elif value < 0:
        color = 'red'
    else:
        color = 'lightgrey'
    return f'background-color: {color};'

def filter_incomplete_stocks(df, required_columns):
    # Ensure all required columns exist in the DataFrame
    for column in required_columns:
        if column not in df.columns:
            df[column] = pd.NA
    return df.dropna(subset=required_columns)

st.title('S&P 500 Stock Comparison Tool')

sp500_list = get_sp500_list()
sp500_averages = load_sp500_averages('sp500_averages.csv')

scores_df = calculate_combined_scores_for_stocks(sp500_list, sp500_averages)

# Debug: Print the DataFrame before filtering to see its content
print("Scores DataFrame before filtering:", scores_df.head())

required_columns = ['P/E Ratio', 'P/B Ratio', 'P/S Ratio', 'Debt to Equity Ratio', 'Return on Equity', 'Book-to-Market Ratio']

# Attempt a lenient filtering approach or skip filtering to debug
# scores_df_filtered = filter_incomplete_stocks(scores_df, required_columns)
scores_df_filtered = scores_df  # Temporarily bypass filtering to debug
scores_df_sorted = scores_df_filtered.sort_values(by='Combined Score', ascending=False)

# Debug: Print the DataFrame after sorting to see if it's empty
print("Scores DataFrame after sorting:", scores_df_sorted.head())

col1, col2 = st.columns([3, 5])

with col1:
    st.subheader("Stock Overview")
    if not scores_df_sorted.empty:
        styled_scores_df = scores_df_sorted.style.applymap(color_combined_score, subset=['Combined Score'])
        st.dataframe(styled_scores_df)
    else:
        st.write("No data available after filtering.")

with col2:
    st.subheader("Stock Details")
    if not scores_df_sorted.empty:
        sorted_tickers = scores_df_sorted['Stock'].tolist()
        ticker_symbol = st.selectbox('Select a stock for details', options=sorted_tickers)
        if ticker_symbol:
            with st.spinner(f'Fetching data for {ticker_symbol}...'):
                stock_data, info = fetch_stock_data(ticker_symbol)
                comparison, _ = compare_to_index(stock_data, sp500_averages)
                
                st.write(f"**{info.get('longName', 'N/A')}** ({ticker_symbol})")
                st.write(info.get('longBusinessSummary', 'N/A'))
                
                for ratio in required_columns:
                    value = stock_data.get(ratio, 'N/A')
                    average = sp500_averages.loc[ratio, 'Average'] if ratio in sp500_averages.index else 'N/A'
                    status = comparison.get(ratio, 'N/A')
                    st.write(f"{ratio}: {value} (Your Ratio) | {average} (S&P 500 Avg) - {status}")
    else:
        st.write("No stocks to display.")