File size: 10,269 Bytes
40a48fb
ad9f8c5
 
54e930d
ad9f8c5
54e930d
4018845
20d6bb4
54e930d
2544f4c
20d6bb4
2544f4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e314039
40a48fb
54e930d
 
f8f52b4
92aeff5
 
 
 
 
 
 
8817f6b
8beaa28
 
 
 
 
 
 
 
 
 
 
8817f6b
54e930d
8817f6b
ad9f8c5
40a48fb
 
 
 
 
 
67a8285
 
 
 
 
f8f52b4
40a48fb
 
 
 
67a8285
 
 
 
 
c7fe441
52c8526
67a8285
 
 
 
 
 
b7d96b6
8817f6b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad9f8c5
d277616
b7d96b6
f8f52b4
 
 
 
b7d96b6
20d6bb4
b7d96b6
 
 
 
 
 
 
 
 
 
8eb4d8c
9a0bbc7
 
 
8beaa28
 
 
 
 
 
 
 
 
b7d96b6
20d6bb4
 
 
 
 
b7d96b6
f8f52b4
 
b7d96b6
20d6bb4
 
 
 
 
67a8285
8817f6b
 
 
 
 
 
 
 
 
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
import pandas as pd
import matplotlib.pyplot as plt
import gradio as gr
import requests
import os
import datetime
import tempfile
import numpy as np  # Added for smoothing historical prices

# Your Hugging Face API Token (set this safely)
HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")

# Mistral Inference API URL
API_URL = "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.3"

# Headers for authentication
headers = {
    "Authorization": f"Bearer {HF_TOKEN}"
}

# Function to query Mistral API
def query_mistral(question):
    payload = {
        "inputs": question,
        "parameters": {"max_length": 256}
    }
    response = requests.post(API_URL, headers=headers, json=payload)
    output = response.json()
    return output[0]["generated_text"]

# API Key
POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")

# Sector Averages
sector_averages = {
    "Technology": {"P/E Ratio": 25, "P/S Ratio": 5, "P/B Ratio": 6},
    "Healthcare": {"P/E Ratio": 20, "P/S Ratio": 4, "P/B Ratio": 3},
    "Financials": {"P/E Ratio": 15, "P/S Ratio": 2, "P/B Ratio": 1.5},
    "Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
}


# Safe Request Function
def safe_request(url):
    try:
        response = requests.get(url)
        response.raise_for_status()
        return response
    except:
        return None

# Fetch Functions
# (functions unchanged)
# ...

# Financial Calculations
# Financial Calculations
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
    pe = price / eps if eps else 0
    ps = market_cap / total_revenue if total_revenue else 0
    pb = market_cap / book_value if book_value else 0
    peg = pe / (growth * 100) if growth else 0
    div_yield = (dividend_amount / price) * 100 if price else 0
    # New Financial Health Metrics
    debt_equity = np.random.uniform(0.2, 2.0)  # Placeholder: random for now
    roe = np.random.uniform(5, 25)  # Placeholder: random for now
    free_cash_flow = np.random.uniform(50000000, 500000000)  # Placeholder: random for now
    beta = np.random.uniform(0.8, 1.5)  # Placeholder: random for now
    return {
        'P/E Ratio': pe,
        'P/S Ratio': ps,
        'P/B Ratio': pb,
        'PEG Ratio': peg,
        'Dividend Yield': div_yield,
        'Debt/Equity Ratio': debt_equity,
        'Return on Equity (%)': roe,
        'Free Cash Flow ($)': free_cash_flow,
        'Beta (Volatility)': beta
    }

# Theme Selection
selected_theme = os.getenv("APP_THEME", "light")
if selected_theme == "dark":
    theme = gr.themes.Base()
else:
    theme = gr.themes.Soft(primary_hue="blue")


# Fetch Functions
def get_company_info(symbol):
    url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={POLYGON_API_KEY}"
    response = safe_request(url)
    if response:
        data = response.json().get('results', {})
        sector = data.get('market', 'Technology')
        if sector.lower() == 'stocks':
            sector = 'Technology'
        return {
            'Name': data.get('name', 'N/A'),
            'Industry': data.get('sic_description', 'N/A'),
            'Sector': sector,
            'Market Cap': data.get('market_cap', 0),
            'Total Revenue': data.get('total_employees', 0) * 100000
        }
    return None

def get_current_price(symbol):
    url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={POLYGON_API_KEY}"
    response = safe_request(url)
    if response:
        return response.json()['results'][0]['c']
    return None

def get_dividends(symbol):
    url = f"https://api.polygon.io/v3/reference/dividends?ticker={symbol}&apiKey={POLYGON_API_KEY}"
    response = safe_request(url)
    if response:
        return response.json()['results'][0].get('cash_amount', 0)
    return 0

def get_historical_prices(symbol):
    end = datetime.date.today()
    start = end - datetime.timedelta(days=365)
    url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/{start}/{end}?adjusted=true&sort=asc&apiKey={POLYGON_API_KEY}"
    response = safe_request(url)
    if response:
        results = response.json()['results']
        dates = [datetime.datetime.fromtimestamp(r['t']/1000) for r in results]
        prices = [r['c'] for r in results]
        return dates, prices
    return [], []

# Financial Calculations
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
    pe = price / eps if eps else 0
    ps = market_cap / total_revenue if total_revenue else 0
    pb = market_cap / book_value if book_value else 0
    peg = pe / (growth * 100) if growth else 0
    div_yield = (dividend_amount / price) * 100 if price else 0
    return {
        'P/E Ratio': pe,
        'P/S Ratio': ps,
        'P/B Ratio': pb,
        'PEG Ratio': peg,
        'Dividend Yield': div_yield
    }

def compare_to_sector(sector, ratios):
    if sector.lower() == 'stocks':
        sector = 'Technology'
    averages = sector_averages.get(sector, {})
    if not averages:
        return pd.DataFrame({"Metric": ["Sector data not available"], "Value": ["N/A"]})

    data = {
        "Ratio": [],
        "Stock Value": [],
        "Sector Average": [],
        "Difference": []
    }
    for key in averages:
        stock_value = ratios.get(key, 0)
        sector_value = averages.get(key, 0)
        diff = stock_value - sector_value

        # Add emoji based on difference
        if diff < 0:
            diff_display = f"{diff:.2f} 🟢"
        elif diff > 0:
            diff_display = f"{diff:.2f} 🔴"
        else:
            diff_display = f"{diff:.2f} ⚪"

        data["Ratio"].append(key)
        data["Stock Value"].append(round(stock_value, 2))
        data["Sector Average"].append(round(sector_value, 2))
        data["Difference"].append(diff_display)

    return pd.DataFrame(data)

def generate_summary(info, ratios):
    recommendation = "Hold"
    if ratios['P/E Ratio'] < 15 and ratios['P/B Ratio'] < 2 and ratios['PEG Ratio'] < 1.0 and ratios['Dividend Yield'] > 2:
        recommendation = "Buy"
    elif ratios['P/E Ratio'] > 30 and ratios['P/B Ratio'] > 5 and ratios['PEG Ratio'] > 2.0:
        recommendation = "Sell"
    
    report = (
        f"Company Overview:\n"
        f"Name: {info['Name']}\n"
        f"Industry: {info['Industry']}\n"
        f"Sector: {info['Sector']}\n"
        f"Market Cap: ${info['Market Cap']:,.2f}\n\n"
        f"Financial Metrics:\n"
        f"P/E Ratio: {ratios['P/E Ratio']:.2f}\n"
        f"P/S Ratio: {ratios['P/S Ratio']:.2f}\n"
        f"P/B Ratio: {ratios['P/B Ratio']:.2f}\n"
        f"PEG Ratio: {ratios['PEG Ratio']:.2f}\n"
        f"Dividend Yield: {ratios['Dividend Yield']:.2f}%\n\n"
        f"Recommended Investment Action: {recommendation}.\n"
    )

    # Use Mistral to generate the summary
    summary_prompt = f"Summarize the following financial report clearly and briefly:\n\n{report}"
    return query_mistral(summary_prompt)

def stock_research(symbol, eps=5.0, growth=0.1, book=500000000):
    info = get_company_info(symbol)
    price = get_current_price(symbol)
    dividends = get_dividends(symbol)
    dates, prices = get_historical_prices(symbol)

    if not info or not price:
        return "⚠️ Error fetching stock info", None, None, None, None

    ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends, eps, growth, book)
    summary = generate_summary(info, ratios)
    sector_comp = compare_to_sector(info['Sector'], ratios)

    fig, ax = plt.subplots()
    ax.plot(dates, prices)
    ax.set_title(f"{symbol} Historical Price (1Y)")
    ax.set_xlabel("Date")
    ax.set_ylabel("Price ($)")
    ax.grid(True)

    info_table = pd.DataFrame(info.items(), columns=["Metric", "Value"])
    ratios_table = pd.DataFrame(ratios.items(), columns=["Ratio", "Value"])

    return summary, info_table, ratios_table, sector_comp, fig



# Gradio UI
with gr.Blocks(theme=theme) as iface:
    with gr.Row():
        symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)")
        eps = gr.Number(label="Assumed EPS", value=5.0)
        growth = gr.Number(label="Assumed Growth Rate", value=0.1)
        book = gr.Number(label="Assumed Book Value", value=500000000)

    with gr.Tabs() as tabs:
        with gr.Tab("AI Research Summary"):
            output_summary = gr.Textbox()
        with gr.Tab("Company Snapshot"):
            output_info = gr.Dataframe()
        with gr.Tab("Valuation Ratios"):
            output_ratios = gr.Dataframe()
        with gr.Tab("Sector Comparison"):
            output_sector = gr.Dataframe()
        with gr.Tab("Historical Price Chart"):
            output_chart = gr.Plot()
        with gr.Tab("Ask About Investing"):
            user_question = gr.Textbox(label="Ask about investing...")
            answer_box = gr.Textbox(label="Answer")
            ask_button = gr.Button("Get Answer")
            with gr.Row():
                ask_button.click(fn=lambda q: query_mistral(q),
                                 inputs=[user_question],
                                 outputs=[answer_box],
                                 api_name="query_mistral").then(
                    lambda: "",
                    inputs=[],
                    outputs=[user_question]
                )

    with gr.Row():
        submit_btn = gr.Button("Run Analysis")
        reset_btn = gr.Button("Reset All Fields")
        download_btn = gr.Button("Download Report")
        file_output = gr.File()

    submit_btn.click(fn=stock_research, inputs=[symbol, eps, growth, book],
                     outputs=[output_summary, output_info, output_ratios, output_sector, output_chart])

    def reset_fields():
        return "", 5.0, 0.1, 500000000, "", "", "", "", None

    reset_btn.click(fn=reset_fields, inputs=[], outputs=[symbol, eps, growth, book, output_summary, output_info, output_ratios, output_sector, output_chart])


    def reset_fields():
        return "", 5.0, 0.1, 500000000, "", "", "", "", None

    reset_btn.click(fn=reset_fields, inputs=[], outputs=[symbol, eps, growth, book, output_summary, output_info, output_ratios, output_sector, output_chart])



if __name__ == "__main__":
    iface.launch()