mr601s commited on
Commit
8dcefb7
Β·
verified Β·
1 Parent(s): a34be3d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -7
app.py CHANGED
@@ -1,5 +1,7 @@
1
  import gradio as gr
2
  import requests
 
 
3
  import feedparser
4
  import time
5
  import random
@@ -10,7 +12,7 @@ import os
10
  POLYGON_API_KEY = os.getenv("POLYGON_API_KEY") or "fAhg47wPlf4FT6U2Hn23kQoQCQIyW0G_"
11
  FINNHUB_API_KEY = "d2urs69r01qq994h1f5gd2urs69r01qq994h1f60"
12
 
13
- # === POLYGON QUOTE ===
14
  def fetch_polygon_quote(ticker, polygon_api_key=POLYGON_API_KEY):
15
  url = f"https://api.polygon.io/v2/aggs/ticker/{ticker.upper()}/prev?adjusted=true&apiKey={polygon_api_key}"
16
  try:
@@ -38,7 +40,6 @@ def get_financial_summary_finnhub(ticker, finnhub_api_key=FINNHUB_API_KEY):
38
  if not metrics:
39
  return f"πŸ“Š **Financial Summary for {ticker.upper()}**\n\n❌ No financial data found."
40
  result = f"πŸ“Š **Financial Summary for {ticker.upper()}**\n\n"
41
- # Revenue (TTM)
42
  if metrics.get('totalRevenueTTM'):
43
  result += f"β€’ **Revenue (TTM):** ${int(metrics['totalRevenueTTM']):,}\n"
44
  if metrics.get('netIncomeTTM'):
@@ -140,7 +141,7 @@ class NewsUtils:
140
  except Exception as e:
141
  return f"πŸ“° **Latest News for {ticker}**\n\n❌ Error fetching news: {str(e)}\n\nπŸ’‘ Try these alternatives:\nβ€’ [Yahoo Finance News](https://finance.yahoo.com/quote/{ticker}/news)\nβ€’ [Google Finance](https://www.google.com/finance/quote/{ticker}:NASDAQ)\nβ€’ [MarketWatch](https://www.marketwatch.com/investing/stock/{ticker})"
142
 
143
- # === TradingView Widget Embed ===
144
  def get_tradingview_embed(ticker):
145
  ticker = ticker.strip().upper() if ticker else "AAPL"
146
  ticker = ''.join(filter(str.isalnum, ticker))
@@ -149,7 +150,91 @@ def get_tradingview_embed(ticker):
149
  width="100%" height="400" frameborder="0" allowtransparency="true" scrolling="no"></iframe>
150
  """
151
 
152
- # === Instantiate utilities ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  sec_utils = SECUtils()
154
  news_utils = NewsUtils()
155
 
@@ -184,11 +269,11 @@ css = """
184
  with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Stock Research Platform") as demo:
185
  gr.Markdown("""
186
  # πŸ“ˆ Stock Research Platform MVP
187
- **Comprehensive stock analysis with real-time data, news, SEC filings, and financial summaries.**
188
 
189
- 🎯 Enter a stock ticker symbol (like **AAPL**, **TSLA**, **MSFT**, **GOOGL**) to explore detailed information.
190
 
191
- ⚠️ **Note**: Stock quote data provided by Polygon (Previous Close for free plans). Financial summary data from Finnhub. News and SEC filings remain free. Charts now powered by TradingView.
192
  """)
193
  with gr.Row():
194
  with gr.Column(scale=3):
@@ -212,6 +297,54 @@ with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Stock Research Platform")
212
  gr.Markdown("### Interactive Price Chart")
213
  gr.Markdown("*Powered by TradingView*")
214
  chart_output = gr.HTML(get_tradingview_embed("AAPL"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  gr.Markdown("""
216
  ---
217
  **Data Sources:** Polygon.io for quotes, Finnhub for financials, Yahoo RSS for news, SEC EDGAR for filings.
 
1
  import gradio as gr
2
  import requests
3
+ import numpy as np
4
+ import pandas as pd
5
  import feedparser
6
  import time
7
  import random
 
12
  POLYGON_API_KEY = os.getenv("POLYGON_API_KEY") or "fAhg47wPlf4FT6U2Hn23kQoQCQIyW0G_"
13
  FINNHUB_API_KEY = "d2urs69r01qq994h1f5gd2urs69r01qq994h1f60"
14
 
15
+ # === QUOTE SECTION ===
16
  def fetch_polygon_quote(ticker, polygon_api_key=POLYGON_API_KEY):
17
  url = f"https://api.polygon.io/v2/aggs/ticker/{ticker.upper()}/prev?adjusted=true&apiKey={polygon_api_key}"
18
  try:
 
40
  if not metrics:
41
  return f"πŸ“Š **Financial Summary for {ticker.upper()}**\n\n❌ No financial data found."
42
  result = f"πŸ“Š **Financial Summary for {ticker.upper()}**\n\n"
 
43
  if metrics.get('totalRevenueTTM'):
44
  result += f"β€’ **Revenue (TTM):** ${int(metrics['totalRevenueTTM']):,}\n"
45
  if metrics.get('netIncomeTTM'):
 
141
  except Exception as e:
142
  return f"πŸ“° **Latest News for {ticker}**\n\n❌ Error fetching news: {str(e)}\n\nπŸ’‘ Try these alternatives:\nβ€’ [Yahoo Finance News](https://finance.yahoo.com/quote/{ticker}/news)\nβ€’ [Google Finance](https://www.google.com/finance/quote/{ticker}:NASDAQ)\nβ€’ [MarketWatch](https://www.marketwatch.com/investing/stock/{ticker})"
143
 
144
+ # === TradingView Widget Chart Embed ===
145
  def get_tradingview_embed(ticker):
146
  ticker = ticker.strip().upper() if ticker else "AAPL"
147
  ticker = ''.join(filter(str.isalnum, ticker))
 
150
  width="100%" height="400" frameborder="0" allowtransparency="true" scrolling="no"></iframe>
151
  """
152
 
153
+ # === LESSON MODULES ===
154
+
155
+ # 1. Order Book Simulator
156
+ def simulate_order_book(side, order_type, price, size, seed=123):
157
+ np.random.seed(seed)
158
+ base_price = 100.00
159
+ levels = np.arange(base_price - 2, base_price + 2.5, 0.5)
160
+ buy_sizes = np.random.randint(1, 40, len(levels))
161
+ sell_sizes = np.random.randint(1, 40, len(levels))
162
+ buy_mask = levels < base_price
163
+ sell_mask = levels > base_price
164
+ buys = np.where(buy_mask, buy_sizes, 0)
165
+ sells = np.where(sell_mask, sell_sizes, 0)
166
+ df = pd.DataFrame({
167
+ 'Price': levels,
168
+ 'Buy Size': buys,
169
+ 'Sell Size': sells
170
+ }).sort_values(by='Price', ascending=False).reset_index(drop=True)
171
+
172
+ fill_msg = ""
173
+ if order_type == "Market":
174
+ if side == "Buy":
175
+ best_ask = df.loc[df['Sell Size'] > 0, 'Price'].min()
176
+ filled = size
177
+ fill_msg = f"Filled {filled} @ {best_ask:.2f} (Market Buy)"
178
+ else:
179
+ best_bid = df.loc[df['Buy Size'] > 0, 'Price'].max()
180
+ filled = size
181
+ fill_msg = f"Filled {filled} @ {best_bid:.2f} (Market Sell)"
182
+ else:
183
+ if side == "Buy":
184
+ if price >= df['Price'].min():
185
+ sells_at_or_below = df[(df['Price'] <= price) & (df['Sell Size'] > 0)]
186
+ if sells_at_or_below.shape[0]:
187
+ fill_price = sells_at_or_below.iloc[0]['Price']
188
+ fill_msg = f"Filled {size} @ {fill_price:.2f} (Aggressive Limit Buy)"
189
+ else:
190
+ queue_spot = 1 + np.random.randint(0, 3)
191
+ fill_msg = f"Limit buy posted at {price:.2f}. Not immediately filled. Position in queue: #{queue_spot}"
192
+ else:
193
+ fill_msg = f"Limit buy posted below book: {price:.2f}. Not filled."
194
+ else:
195
+ if price <= df['Price'].max():
196
+ buys_at_or_above = df[(df['Price'] >= price) & (df['Buy Size'] > 0)]
197
+ if buys_at_or_above.shape[0]:
198
+ fill_price = buys_at_or_above.iloc[0]['Price']
199
+ fill_msg = f"Filled {size} @ {fill_price:.2f} (Aggressive Limit Sell)"
200
+ else:
201
+ queue_spot = 1 + np.random.randint(0, 3)
202
+ fill_msg = f"Limit sell posted at {price:.2f}. Not immediately filled. Position in queue: #{queue_spot}"
203
+ else:
204
+ fill_msg = f"Limit sell posted above book: {price:.2f}. Not filled."
205
+ return df, fill_msg
206
+
207
+ # 2. Slippage Estimator
208
+ def slippage_estimator(side, order_size, seed=123):
209
+ np.random.seed(seed)
210
+ base_price = 100
211
+ levels = np.arange(base_price-2, base_price+2.5, 0.5)
212
+ if side == "Buy":
213
+ sizes = np.random.randint(10, 70, len(levels))
214
+ prices = levels[levels > base_price]
215
+ sizes = sizes[levels > base_price]
216
+ else:
217
+ sizes = np.random.randint(10, 70, len(levels))
218
+ prices = levels[levels < base_price]
219
+ sizes = sizes[levels < base_price]
220
+ remaining = order_size
221
+ fills = []
222
+ for p, s in zip(prices, sizes):
223
+ take = min(s, remaining)
224
+ fills.append((p, take))
225
+ remaining -= take
226
+ if remaining <= 0:
227
+ break
228
+ if remaining > 0:
229
+ return "Not enough liquidity to fill order!", None
230
+ df = pd.DataFrame(fills, columns=["Price", "Shares"])
231
+ avg_fill = (df["Price"] * df["Shares"]).sum() / order_size
232
+ slip = avg_fill - base_price if side == "Buy" else base_price - avg_fill
233
+ slip_pct = (slip / base_price) * 100
234
+ summary = f"Est. avg fill @ {avg_fill:.2f}; Slippage: {slip:.2f} ({slip_pct:.2f}%) from ideal {base_price}"
235
+ return summary, df
236
+
237
+ # === Instantiate Utilities ===
238
  sec_utils = SECUtils()
239
  news_utils = NewsUtils()
240
 
 
269
  with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Stock Research Platform") as demo:
270
  gr.Markdown("""
271
  # πŸ“ˆ Stock Research Platform MVP
272
+ **Comprehensive stock analysis, real-time data, and interactive education modules.**
273
 
274
+ 🎯 Enter a stock ticker symbol (**AAPL**, **TSLA**, **MSFT**, **GOOGL**) for market data, or check out the Lessons tab for learning modules!
275
 
276
+ ⚠️ **Note**: Stock quote data from Polygon (Previous Close for free plans). Financial summary from Finnhub. Charts powered by TradingView.
277
  """)
278
  with gr.Row():
279
  with gr.Column(scale=3):
 
297
  gr.Markdown("### Interactive Price Chart")
298
  gr.Markdown("*Powered by TradingView*")
299
  chart_output = gr.HTML(get_tradingview_embed("AAPL"))
300
+ with gr.TabItem("πŸŽ“ Lessons"):
301
+ with gr.Tabs():
302
+ with gr.TabItem("Lesson 1: Exchanges & Order Book"):
303
+ gr.Markdown("""
304
+ ## Lesson 1: Exchanges, dark pools, auction vs. dealer markets
305
+
306
+ - *[Paste your main lesson text here, or sync from Google Doc]*
307
+
308
+ ---
309
+
310
+ **Explore:** Try the tools below to visualize real order book mechanics and slippage.
311
+ """)
312
+ with gr.Tabs():
313
+ with gr.TabItem("Order Book Simulator"):
314
+ lesson1_order = gr.Interface(
315
+ fn=simulate_order_book,
316
+ inputs=[
317
+ gr.Dropdown(["Buy", "Sell"], label="Order Side"),
318
+ gr.Dropdown(["Market", "Limit"], label="Order Type"),
319
+ gr.Number(value=100.00, label="Order Price (for limit)"),
320
+ gr.Slider(1, 100, value=10, step=1, label="Order Size"),
321
+ gr.Number(value=123, label="Seed (optional, for replay)"),
322
+ ],
323
+ outputs=[
324
+ gr.Dataframe(label="Order Book (randomized)"),
325
+ gr.Textbox(label="Result / Fill Message"),
326
+ ],
327
+ live=False,
328
+ allow_flagging="never"
329
+ )
330
+ with gr.TabItem("Slippage Estimator"):
331
+ lesson1_slippage = gr.Interface(
332
+ fn=slippage_estimator,
333
+ inputs=[
334
+ gr.Dropdown(["Buy", "Sell"], label="Order Side"),
335
+ gr.Slider(1, 300, value=50, step=1, label="Order Size"),
336
+ gr.Number(value=123, label="Seed (for repeatability)"),
337
+ ],
338
+ outputs=[
339
+ gr.Textbox(label="Estimate"),
340
+ gr.Dataframe(label="Fill breakdown"),
341
+ ],
342
+ live=False,
343
+ allow_flagging="never"
344
+ )
345
+
346
+ # Add more lessons as new gr.TabItem("Lesson X: ...") blocks here
347
+
348
  gr.Markdown("""
349
  ---
350
  **Data Sources:** Polygon.io for quotes, Finnhub for financials, Yahoo RSS for news, SEC EDGAR for filings.