File size: 10,178 Bytes
8f8ed2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60a045a
8f8ed2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
import yfinance as yf
import streamlit as st
import pandas as pd

class CalculateMetric:
    def __init__(self, symbol: str):
        self.ticker = yf.Ticker(symbol)

        # Get financial statements and info
        balance_sheet = self.ticker.balance_sheet
        income_statement = self.ticker.financials
        cash_flow = self.ticker.cashflow

        # Transpose the DataFrames to have dates as rows
        balance_sheet = balance_sheet.T
        income_statement = income_statement.T
        cash_flow = cash_flow.T

        # Sort the DataFrames by date in descending order
        self.balance_sheet = balance_sheet.sort_index(ascending=False)
        self.income_statement = income_statement.sort_index(ascending=False)
        self.cash_flow = cash_flow.sort_index(ascending=False)

        self.z_weightage = 0.6
        self.f_weightage = 0.4

    def calculate_F_Score(self) -> int:
        latest = 0
        previous = 1

        # Criterion 1: Positive Net Income
        net_income_latest = self.income_statement["Net Income"].iloc[latest]
        net_income_prev = self.income_statement["Net Income"].iloc[previous]
        c1 = 1 if net_income_latest > 0 and net_income_latest > net_income_prev else 0

        # Criterion 2: Positive Operating Cash Flow
        op_cash_flow_latest = self.cash_flow["Operating Cash Flow"].iloc[latest]
        c2 = 1 if op_cash_flow_latest > 0 else 0

        # Criterion 3: Return on Assets improving
        total_assets_latest = self.balance_sheet["Total Assets"].iloc[latest]
        total_assets_prev = self.balance_sheet["Total Assets"].iloc[previous]
        roa_latest = (
            net_income_latest / total_assets_latest if total_assets_latest != 0 else 0
        )
        roa_prev = net_income_prev / total_assets_prev if total_assets_prev != 0 else 0
        c3 = 1 if roa_latest > roa_prev else 0

        # Criterion 4: Quality of Earnings
        c4 = 1 if op_cash_flow_latest > net_income_latest else 0

        # Criterion 5: No New Debt or Debt Reduction
        long_term_debt_latest = self.balance_sheet["Long Term Debt"].iloc[latest]
        long_term_debt_prev = self.balance_sheet["Long Term Debt"].iloc[previous]
        c5 = 1 if long_term_debt_latest <= long_term_debt_prev else 0

        # Criterion 6: Improvement in Current Ratio
        current_assets_latest = self.balance_sheet["Current Assets"].iloc[latest]
        current_liabilities_latest = self.balance_sheet["Current Liabilities"].iloc[
            latest
        ]
        current_ratio_latest = (
            current_assets_latest / current_liabilities_latest
            if current_liabilities_latest != 0
            else 0
        )
        current_assets_prev = self.balance_sheet["Current Assets"].iloc[previous]
        current_liabilities_prev = self.balance_sheet["Current Liabilities"].iloc[
            previous
        ]
        current_ratio_prev = (
            current_assets_prev / current_liabilities_prev
            if current_liabilities_prev != 0
            else 0
        )
        c6 = 1 if current_ratio_latest > current_ratio_prev else 0

        # Criterion 7: No New Shares Issued
        shares_outstanding_latest = self.balance_sheet["Common Stock"].iloc[latest]
        shares_outstanding_prev = self.balance_sheet["Common Stock"].iloc[previous]
        c7 = 1 if shares_outstanding_latest <= shares_outstanding_prev else 0

        # Criterion 8: Improvement in Gross Margin
        gross_profit_latest = self.income_statement["Gross Profit"].iloc[latest]
        total_revenue_latest = self.income_statement["Total Revenue"].iloc[latest]
        gross_margin_latest = (
            gross_profit_latest / total_revenue_latest
            if total_revenue_latest != 0
            else 0
        )
        gross_profit_prev = self.income_statement["Gross Profit"].iloc[previous]
        total_revenue_prev = self.income_statement["Total Revenue"].iloc[previous]
        gross_margin_prev = (
            gross_profit_prev / total_revenue_prev if total_revenue_prev != 0 else 0
        )
        c8 = 1 if gross_margin_latest > gross_margin_prev else 0

        # Criterion 9: Improvement in Asset Turnover
        total_revenue_prev = self.income_statement["Total Revenue"].iloc[previous]
        total_assets_prev = self.balance_sheet["Total Assets"].iloc[previous]
        asset_turnover_latest = (
            total_revenue_latest / total_assets_latest
            if total_assets_latest != 0
            else 0
        )
        asset_turnover_prev = (
            total_revenue_prev / total_assets_prev if total_assets_prev != 0 else 0
        )
        c9 = 1 if asset_turnover_latest > asset_turnover_prev else 0

        # Calculate Piotroski F-Score
        f_score = c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9

        return f_score

    def calculate_altman_z_score(self) -> float:
        info = self.ticker.info

        current_assets = self.balance_sheet["Current Assets"].iloc[0] / 1000000
        current_liabilities = (
            self.balance_sheet["Current Liabilities"].iloc[0] / 1000000
        )
        total_assets = self.balance_sheet["Total Assets"].iloc[0] / 1000000
        retained_earnings = self.balance_sheet["Retained Earnings"].iloc[0] / 1000000
        ebit = self.income_statement["EBIT"].iloc[0] / 1000000
        sales = self.income_statement["Total Revenue"].iloc[0] / 1000000
        market_cap = info["marketCap"] / 1000000
        total_liabilities = (
            self.balance_sheet["Total Liabilities Net Minority Interest"].iloc[0]
            / 1000000
        )

        X1 = (current_assets - current_liabilities) / total_assets
        X2 = retained_earnings / total_assets
        X3 = ebit / total_assets
        X4 = market_cap / total_liabilities
        X5 = sales / total_assets

        # Calculate Altman Z-Score for non-manufacturing firms
        Z = 1.2 * X1 + 1.4 * X2 + 3.3 * X3 + 0.6 * X4 + 1.0 * X5

        return Z

    def health(self):
        try:
            combined_metric = (
                (self.f_weightage * self.calculate_F_Score())
                + (self.z_weightage * self.calculate_altman_z_score())
            )
        except:
            return "Error: Unable to calculate metrics", 0, False
        is_investable = False

        if combined_metric >= 7:
            is_investable = True
            message = "The company's fundamentals are Extremely Strong"
            return message, combined_metric, is_investable
        elif combined_metric >=4:
            is_investable = True
            message = "The company's fundamentals are Strong"
            return message, combined_metric, is_investable
        else:
            message = "The company's fundamentals are Weak"
            return message, combined_metric, is_investable

st.set_page_config(page_title='Fundler', page_icon='💰')

st.title('Gemstone Score Calculator💰')
st.write('Enter a Yahoo Finance compatible ticker symbol to get investment recommendations based on fundamental analysis.')

ticker_symbol = st.text_input('Enter Ticker Symbol', help='e.g., AAPL for Apple Inc.', value='MSFT')

if st.button('Submit'):
    try:
        calculator = CalculateMetric(ticker_symbol)
        message, score, invest = calculator.health()
        # Display the results
        st.subheader('Analysis Results:')
        st.write(f'**Message:** {message}')
        st.write(f'**Score:** {score:.2f}')
        if invest:
            st.write('**Investment Decision:** Yes, consider investing in this stock.')
        else:
            st.write('**Investment Decision:** No, do not invest in this stock.')
    except Exception as e:
        st.error(f'An error occurred: {e}')

st.write("---")

st.markdown("Made By Adeeb [GitHub](https://github.com/Itachi-Uchiha581)")

st.subheader('Ticker Symbol Naming Conventions for Different Exchanges')


data = {
    "Exchange Name": [
        "Bombay Stock Exchange (BSE)",
        "National Stock Exchange (NSE)",
        "New York Stock Exchange (NYSE)",
        "NASDAQ",
        "London Stock Exchange (LSE)",
        "Tokyo Stock Exchange (TSE)",
        "Hong Kong Stock Exchange (HKEX)",
        "Shanghai Stock Exchange (SSE)",
        "Shenzhen Stock Exchange (SZSE)",
        "Euronext Amsterdam",
        "Euronext Paris",
        "Toronto Stock Exchange (TSX)",
        "Australian Securities Exchange (ASX)",
        "Deutsche Börse Xetra (Frankfurt)",
        "Swiss Exchange (SIX)",
        "Milan Stock Exchange (Borsa Italiana)",
        "Vienna Stock Exchange (WBAG)",
        "Madrid Stock Exchange (BME)",
        "Stockholm Stock Exchange (OMX)",
        "Johannesburg Stock Exchange (JSE)",
        "São Paulo Stock Exchange (B3)",
        "Moscow Exchange (MOEX)",
        "Taiwan Stock Exchange (TWSE)",
        "Korean Stock Exchange (KRX)",
        "OTC Markets (Over-the-Counter, US)",
        "Currency Exchange (Forex)",
        "Cryptocurrencies",
    ],
    "Suffix": [
        ".BO", ".NS", "No Suffix Required", "No Suffix Required", ".L", ".T", ".HK", ".SS", ".SZ", ".AS", ".PA", ".TO",
        ".AX", ".DE", ".SW", ".MI", ".VI", ".MC", ".ST", ".JO", ".SA", ".ME", ".TW",
        ".KS", ".OTC", ".X", ".CRYPTO"
    ],
    "Example Ticker Symbol": [
        "RELIANCE.BO, TCS.BO",
        "RELIANCE.NS, TCS.NS",
        "AAPL, MSFT",
        "GOOGL, TSLA",
        "HSBA.L, RIO.L",
        "7203.T (Toyota), 6758.T (Sony)",
        "0005.HK (HSBC), 0700.HK (Tencent)",
        "600519.SS (Kweichow Moutai)",
        "000001.SZ (Ping An Bank)",
        "ADYEN.AS, PHIA.AS",
        "BNP.PA, AIR.PA",
        "RY.TO, TD.TO",
        "BHP.AX, CBA.AX",
        "DBK.DE (Deutsche Bank), SAP.DE",
        "NESN.SW, UBSG.SW",
        "ENEL.MI, ISP.MI",
        "EBS.VI, ANDR.VI",
        "SAN.MC, IBE.MC",
        "ERIC.ST, VOLV.ST",
        "NPN.JO, AGL.JO",
        "PETR4.SA, VALE3.SA",
        "GAZP.ME, SBER.ME",
        "2330.TW (TSMC), 2303.TW",
        "005930.KS (Samsung), 000660.KS",
        "TCEHY.OTC, BABA.OTC",
        "USDINR=X, EURUSD=X",
        "BTC-USD, ETH-USD"
    ],
}


exchange_df = pd.DataFrame(data)

# Display the table
st.table(exchange_df)