jetpackjules commited on
Commit
c345102
·
1 Parent(s): 055eea7

Remove nested directory structure that was confusing Hugging Face

Browse files
hf_space/.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
hf_space/README.md DELETED
@@ -1,34 +0,0 @@
1
- ---
2
- title: Trading_Dashboard
3
- app_file: app.py
4
- sdk: gradio
5
- sdk_version: 5.35.0
6
- ---
7
- # Stock-Trader
8
- Line of best fit stock trader test
9
-
10
-
11
- ## ENV MANAGER:
12
- >To CREATE/UPDATE YAML (from PC to file) go to reg. terminal:
13
- >conda env export > env.yml
14
- >
15
- >To create env (from file to PC):
16
- >conda env create --file=env.yml
17
- >
18
- >To update ENV (FROM FILE TO PC) (run in conda terminal) (if i remove --prune it works in terminal?):
19
- >conda env update --file env.yml --prune
20
-
21
-
22
-
23
-
24
- ### THIS WORKED TO FIX QT ISSUE:
25
- from PyQt5.QtCore import QCoreApplication, Qt
26
-
27
- # Clear any cached Qt plugins
28
- QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling, True)
29
-
30
- app = QCoreApplication([])
31
-
32
-
33
-
34
- # This might not be needed since we are using conda... (TO ACTIVATE ENV: source venv/bin/activate)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
hf_space/app.py DELETED
@@ -1,598 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Premium Trading Dashboard - Full Featured
4
- Beautiful Vercel-style dashboard with VM data integration
5
- """
6
-
7
- import os
8
- import pandas as pd
9
- import gradio as gr
10
- import plotly.graph_objects as go
11
- import plotly.express as px
12
- from datetime import datetime, timedelta, timezone
13
- import logging
14
- import requests
15
- from alpaca.trading.client import TradingClient
16
- from alpaca.trading.requests import GetOrdersRequest, GetPortfolioHistoryRequest
17
- from alpaca.trading.enums import OrderStatus
18
- from alpaca.data.timeframe import TimeFrame
19
- from alpaca.data.historical import StockHistoricalDataClient
20
-
21
- # Get API keys and VM URL from environment variables
22
- API_KEY = os.getenv('ALPACA_API_KEY', 'PK2FD9B2S86LHR7ZBHG1')
23
- SECRET_KEY = os.getenv('ALPACA_SECRET_KEY', 'QPmGPDgbPArvHv6cldBXc7uWddapYcIAnBhtkuBW')
24
- VM_API_URL = os.getenv('VM_API_URL', 'http://34.56.193.18:8090') # Set this in Hugging Face
25
-
26
- # Configure logging
27
- logging.basicConfig(level=logging.INFO)
28
- logger = logging.getLogger(__name__)
29
-
30
- # Initialize Alpaca clients
31
- trading_client = TradingClient(api_key=API_KEY, secret_key=SECRET_KEY)
32
- data_client = StockHistoricalDataClient(API_KEY, SECRET_KEY)
33
-
34
- # Modern color scheme
35
- COLORS = {
36
- 'primary': '#0070f3',
37
- 'success': '#00d647',
38
- 'error': '#ff0080',
39
- 'warning': '#f5a623',
40
- 'neutral': '#8b949e',
41
- 'background': '#fafafa',
42
- 'surface': '#ffffff',
43
- 'text': '#000000',
44
- 'text_secondary': '#666666',
45
- 'border': '#eaeaea'
46
- }
47
-
48
- def fetch_from_vm(endpoint, default_value=None):
49
- """Fetch data from VM API server"""
50
- try:
51
- response = requests.get(f"{VM_API_URL}/api/{endpoint}", timeout=10)
52
- if response.status_code == 200:
53
- return response.json()
54
- else:
55
- logger.warning(f"VM API {endpoint} returned {response.status_code}")
56
- return default_value
57
- except Exception as e:
58
- logger.error(f"Error fetching from VM {endpoint}: {e}")
59
- return default_value
60
-
61
- def get_account_info():
62
- """Get current account information from Alpaca"""
63
- try:
64
- account = trading_client.get_account()
65
- return {
66
- 'portfolio_value': float(account.portfolio_value),
67
- 'buying_power': float(account.buying_power),
68
- 'cash': float(account.cash),
69
- 'equity': float(account.equity),
70
- 'day_change': float(getattr(account, 'unrealized_pl', 0)) if hasattr(account, 'unrealized_pl') else 0,
71
- 'day_change_percent': float(getattr(account, 'unrealized_plpc', 0)) * 100 if hasattr(account, 'unrealized_plpc') else 0,
72
- 'last_equity': float(account.last_equity) if account.last_equity else 0
73
- }
74
- except Exception as e:
75
- logger.error(f"Error fetching account info: {e}")
76
- return {
77
- 'portfolio_value': 0, 'buying_power': 0, 'cash': 0, 'equity': 0,
78
- 'day_change': 0, 'day_change_percent': 0, 'last_equity': 0
79
- }
80
-
81
- def get_portfolio_history():
82
- """Get portfolio value history from Alpaca"""
83
- try:
84
- portfolio_history_request = GetPortfolioHistoryRequest(
85
- period="1M",
86
- timeframe="1D",
87
- extended_hours=False
88
- )
89
-
90
- portfolio_history = trading_client.get_portfolio_history(portfolio_history_request)
91
-
92
- timestamps = [datetime.fromtimestamp(ts, tz=timezone.utc) for ts in portfolio_history.timestamp]
93
- equity_values = portfolio_history.equity
94
-
95
- df = pd.DataFrame({
96
- 'timestamp': timestamps,
97
- 'equity': equity_values
98
- })
99
-
100
- return df.dropna()
101
- except Exception as e:
102
- logger.error(f"Error fetching portfolio history: {e}")
103
- return pd.DataFrame()
104
-
105
- def get_current_positions():
106
- """Get current positions"""
107
- try:
108
- positions = trading_client.get_all_positions()
109
- position_data = []
110
-
111
- for position in positions:
112
- position_data.append({
113
- 'symbol': position.symbol,
114
- 'qty': float(position.qty),
115
- 'market_value': float(position.market_value),
116
- 'cost_basis': float(position.cost_basis),
117
- 'unrealized_pl': float(position.unrealized_pl),
118
- 'unrealized_plpc': float(position.unrealized_plpc) * 100,
119
- 'current_price': float(position.current_price) if position.current_price else 0
120
- })
121
-
122
- return position_data
123
- except Exception as e:
124
- logger.error(f"Error fetching positions: {e}")
125
- return []
126
-
127
- def create_portfolio_chart():
128
- """Create beautiful portfolio value chart"""
129
- portfolio_df = get_portfolio_history()
130
-
131
- if portfolio_df.empty:
132
- fig = go.Figure()
133
- fig.add_annotation(
134
- text="No portfolio history available",
135
- x=0.5, y=0.5,
136
- xref="paper", yref="paper",
137
- showarrow=False,
138
- font=dict(size=16, color=COLORS['text_secondary'])
139
- )
140
- else:
141
- fig = go.Figure()
142
-
143
- fig.add_trace(go.Scatter(
144
- x=portfolio_df['timestamp'],
145
- y=portfolio_df['equity'],
146
- mode='lines',
147
- name='Portfolio Value',
148
- line=dict(color=COLORS['primary'], width=3),
149
- fill='tonexty',
150
- fillcolor=f"rgba(0, 112, 243, 0.1)",
151
- hovertemplate='<b>%{y:$,.2f}</b><br>%{x}<extra></extra>'
152
- ))
153
-
154
- if len(portfolio_df) > 0:
155
- current_value = portfolio_df['equity'].iloc[-1]
156
- fig.add_annotation(
157
- x=portfolio_df['timestamp'].iloc[-1],
158
- y=current_value,
159
- text=f"${current_value:,.2f}",
160
- showarrow=True,
161
- arrowhead=2,
162
- arrowcolor=COLORS['primary'],
163
- bgcolor="white",
164
- bordercolor=COLORS['primary'],
165
- borderwidth=2,
166
- font=dict(size=12, color=COLORS['text'])
167
- )
168
-
169
- fig.update_layout(
170
- title=dict(
171
- text="Portfolio Value (Last 30 Days)",
172
- font=dict(size=24, color=COLORS['text'], family="Inter"),
173
- x=0.02
174
- ),
175
- xaxis=dict(
176
- title="Date",
177
- showgrid=True,
178
- gridcolor=COLORS['border'],
179
- color=COLORS['text_secondary']
180
- ),
181
- yaxis=dict(
182
- title="Portfolio Value ($)",
183
- showgrid=True,
184
- gridcolor=COLORS['border'],
185
- color=COLORS['text_secondary'],
186
- tickformat='$,.0f'
187
- ),
188
- plot_bgcolor='white',
189
- paper_bgcolor='white',
190
- height=400,
191
- margin=dict(l=60, r=40, t=60, b=60),
192
- hovermode='x unified',
193
- showlegend=False
194
- )
195
-
196
- return fig
197
-
198
- def create_ipo_discovery_chart():
199
- """Create IPO discovery chart with investment decisions"""
200
- ipos = fetch_from_vm('ipos?limit=30', [])
201
-
202
- if not ipos:
203
- fig = go.Figure()
204
- fig.add_annotation(
205
- text="No IPO data available from VM",
206
- x=0.5, y=0.5,
207
- xref="paper", yref="paper",
208
- showarrow=False,
209
- font=dict(size=16, color=COLORS['text_secondary'])
210
- )
211
- else:
212
- # Count by status
213
- status_counts = {}
214
- for ipo in ipos:
215
- status = ipo.get('investment_status', 'UNKNOWN')
216
- status_counts[status] = status_counts.get(status, 0) + 1
217
-
218
- # Create pie chart
219
- labels = list(status_counts.keys())
220
- values = list(status_counts.values())
221
-
222
- # Map status to colors
223
- color_map = {
224
- 'INVESTED': COLORS['success'],
225
- 'ELIGIBLE_NOT_INVESTED': COLORS['warning'],
226
- 'WRONG_TYPE': COLORS['neutral'],
227
- 'UNKNOWN': COLORS['error']
228
- }
229
- colors = [color_map.get(label, COLORS['neutral']) for label in labels]
230
-
231
- fig = go.Figure(data=[go.Pie(
232
- labels=labels,
233
- values=values,
234
- hole=0.4,
235
- marker=dict(colors=colors),
236
- textinfo='label+percent',
237
- textposition='outside'
238
- )])
239
-
240
- fig.update_layout(
241
- title=dict(
242
- text="IPO Investment Decisions",
243
- font=dict(size=24, color=COLORS['text'], family="Inter"),
244
- x=0.5
245
- ),
246
- plot_bgcolor='white',
247
- paper_bgcolor='white',
248
- height=400,
249
- margin=dict(l=60, r=60, t=60, b=60),
250
- showlegend=True
251
- )
252
-
253
- return fig
254
-
255
- def refresh_account_overview():
256
- """Refresh account overview display"""
257
- account = get_account_info()
258
-
259
- portfolio_value = f"${account['portfolio_value']:,.2f}"
260
- buying_power = f"${account['buying_power']:,.2f}"
261
- cash = f"${account['cash']:,.2f}"
262
-
263
- day_change_value = account['day_change']
264
- day_change_percent = account['day_change_percent']
265
- if day_change_value > 0:
266
- day_change = f"↗️ +${day_change_value:,.2f} (+{day_change_percent:.2f}%)"
267
- elif day_change_value < 0:
268
- day_change = f"↘️ ${day_change_value:,.2f} ({day_change_percent:.2f}%)"
269
- else:
270
- day_change = f"➡️ ${day_change_value:,.2f} ({day_change_percent:.2f}%)"
271
-
272
- equity = f"${account['equity']:,.2f}"
273
-
274
- return portfolio_value, buying_power, cash, day_change, equity
275
-
276
- def refresh_positions_table():
277
- """Refresh current positions table"""
278
- positions = get_current_positions()
279
- if not positions:
280
- return pd.DataFrame(columns=['Symbol', 'Quantity', 'Market Value', 'Unrealized P&L', 'Unrealized %'])
281
-
282
- df_data = []
283
- for pos in positions:
284
- pnl_indicator = "🟢" if pos['unrealized_pl'] > 0 else "🔴" if pos['unrealized_pl'] < 0 else "⚪"
285
- df_data.append({
286
- 'Symbol': f"{pnl_indicator} {pos['symbol']}",
287
- 'Quantity': f"{pos['qty']:.0f}",
288
- 'Market Value': f"${pos['market_value']:,.2f}",
289
- 'Unrealized P&L': f"${pos['unrealized_pl']:,.2f}",
290
- 'Unrealized %': f"{pos['unrealized_plpc']:.2f}%"
291
- })
292
-
293
- return pd.DataFrame(df_data)
294
-
295
- def refresh_ipo_discoveries_table():
296
- """Refresh IPO discoveries table with investment decisions"""
297
- ipos = fetch_from_vm('ipos?limit=100', [])
298
-
299
- if not ipos:
300
- return pd.DataFrame(columns=['Status', 'Symbol', 'Security Type', 'Price', 'Detected At'])
301
-
302
- df_data = []
303
- for ipo in ipos:
304
- status_emoji = ipo.get('status_emoji', '⚪')
305
- status = ipo.get('investment_status', 'UNKNOWN')
306
-
307
- # Clean up status for display
308
- display_status = {
309
- 'INVESTED': '🟢 INVESTED',
310
- 'ELIGIBLE_NOT_INVESTED': '🟡 ELIGIBLE',
311
- 'WRONG_TYPE': '⚪ WRONG TYPE',
312
- 'UNKNOWN': '🔴 UNKNOWN'
313
- }.get(status, '⚪ UNKNOWN')
314
-
315
- df_data.append({
316
- 'Status': display_status,
317
- 'Symbol': ipo.get('symbol', 'N/A'),
318
- 'Security Type': ipo.get('security_type', 'N/A'),
319
- 'Price': f"${ipo.get('trading_price', 0)}" if ipo.get('trading_price') != 'N/A' else 'N/A',
320
- 'Detected At': ipo.get('detected_at', 'N/A')
321
- })
322
-
323
- return pd.DataFrame(df_data)
324
-
325
- def refresh_vm_stats():
326
- """Refresh VM statistics"""
327
- stats = fetch_from_vm('stats', {})
328
-
329
- if not stats:
330
- return "0", "0", "0", "0%", "No data"
331
-
332
- return (
333
- str(stats.get('total_ipos_detected', 0)),
334
- str(stats.get('ipos_invested', 0)),
335
- str(stats.get('cs_stocks_detected', 0)),
336
- f"{stats.get('investment_rate', 0):.1f}%",
337
- stats.get('last_updated', 'N/A')
338
- )
339
-
340
- def refresh_system_logs():
341
- """Refresh system logs from VM"""
342
- logs = fetch_from_vm('logs', [])
343
-
344
- if not logs:
345
- return "No logs available from VM"
346
-
347
- # Format logs for display
348
- formatted_logs = []
349
- for log in logs:
350
- emoji = log.get('emoji', '⚪')
351
- timestamp = log.get('timestamp', 'N/A')
352
- message = log.get('message', '')
353
- formatted_logs.append(f"{emoji} {timestamp} | {message}")
354
-
355
- return '\n'.join(formatted_logs)
356
-
357
- def refresh_raw_logs():
358
- """Refresh raw logs from VM"""
359
- raw_data = fetch_from_vm('logs/raw?lines=1000', {})
360
-
361
- if not raw_data:
362
- return "No raw logs available from VM"
363
-
364
- content = raw_data.get('content', 'No content')
365
- total_lines = raw_data.get('total_lines', 0)
366
- showing_lines = raw_data.get('showing_lines', 0)
367
-
368
- header = f"=== RAW CRON LOGS ===\nShowing last {showing_lines} of {total_lines} total lines\n\n"
369
- return header + content
370
-
371
- # Custom CSS for gorgeous design
372
- custom_css = """
373
- .gradio-container {
374
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
375
- background: #fafafa !important;
376
- }
377
-
378
- .main-header {
379
- background: linear-gradient(135deg, #0070f3 0%, #0051a5 100%);
380
- color: white;
381
- padding: 2rem;
382
- border-radius: 16px;
383
- margin-bottom: 2rem;
384
- box-shadow: 0 10px 40px rgba(0, 112, 243, 0.3);
385
- }
386
-
387
- .metric-card {
388
- background: white;
389
- border: 1px solid #eaeaea;
390
- border-radius: 12px;
391
- padding: 1.5rem;
392
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
393
- transition: all 0.3s ease;
394
- }
395
-
396
- .metric-card:hover {
397
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
398
- transform: translateY(-4px);
399
- }
400
-
401
- .gr-button {
402
- background: linear-gradient(135deg, #0070f3 0%, #0051a5 100%) !important;
403
- color: white !important;
404
- border: none !important;
405
- border-radius: 12px !important;
406
- font-weight: 600 !important;
407
- padding: 1rem 2rem !important;
408
- transition: all 0.3s ease !important;
409
- box-shadow: 0 4px 16px rgba(0, 112, 243, 0.3) !important;
410
- }
411
-
412
- .gr-button:hover {
413
- transform: translateY(-2px) !important;
414
- box-shadow: 0 8px 32px rgba(0, 112, 243, 0.4) !important;
415
- }
416
-
417
- .gr-textbox, .gr-dataframe {
418
- border: 1px solid #eaeaea !important;
419
- border-radius: 12px !important;
420
- background: white !important;
421
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04) !important;
422
- }
423
-
424
- .plotly-graph-div {
425
- border-radius: 16px !important;
426
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important;
427
- background: white !important;
428
- }
429
-
430
- .status-invested { color: #00d647 !important; font-weight: 600 !important; }
431
- .status-eligible { color: #f5a623 !important; font-weight: 600 !important; }
432
- .status-wrong { color: #8b949e !important; }
433
- .status-unknown { color: #ff0080 !important; }
434
- """
435
-
436
- def create_dashboard():
437
- with gr.Blocks(
438
- title="🚀 Premium Trading Dashboard",
439
- theme=gr.themes.Soft(primary_hue="blue"),
440
- css=custom_css
441
- ) as demo:
442
-
443
- # Header
444
- gr.HTML("""
445
- <div class="main-header">
446
- <h1 style="margin: 0; font-size: 3rem; font-weight: 800; text-shadow: 0 2px 4px rgba(0,0,0,0.1);">
447
- 🚀 Premium Trading Dashboard
448
- </h1>
449
- <p style="margin: 1rem 0 0 0; font-size: 1.3rem; opacity: 0.95;">
450
- Real-time portfolio monitoring with IPO discovery analytics
451
- </p>
452
- </div>
453
- """)
454
-
455
- with gr.Tabs():
456
- # Portfolio Overview Tab
457
- with gr.Tab("📊 Portfolio Overview"):
458
- gr.Markdown("## 💼 Account Summary")
459
- with gr.Row():
460
- portfolio_value = gr.Textbox(label="💰 Portfolio Value", interactive=False, elem_classes=["metric-card"])
461
- buying_power = gr.Textbox(label="💳 Buying Power", interactive=False, elem_classes=["metric-card"])
462
- cash = gr.Textbox(label="💵 Cash", interactive=False, elem_classes=["metric-card"])
463
- day_change = gr.Textbox(label="📈 Day Change", interactive=False, elem_classes=["metric-card"])
464
- equity = gr.Textbox(label="🏦 Total Equity", interactive=False, elem_classes=["metric-card"])
465
-
466
- gr.Markdown("## 📈 Portfolio Performance")
467
- portfolio_chart = gr.Plot(label="Portfolio Value Over Time")
468
-
469
- refresh_overview_btn = gr.Button("🔄 Refresh Portfolio Data", variant="primary", size="lg")
470
-
471
- # IPO Discoveries Tab
472
- with gr.Tab("🔍 IPO Discoveries"):
473
- gr.Markdown("## 📊 IPO Discovery Analytics")
474
-
475
- with gr.Row():
476
- total_ipos = gr.Textbox(label="🎯 Total IPOs Detected", interactive=False, elem_classes=["metric-card"])
477
- ipos_invested = gr.Textbox(label="💰 IPOs Invested", interactive=False, elem_classes=["metric-card"])
478
- cs_stocks = gr.Textbox(label="📈 CS Stocks Found", interactive=False, elem_classes=["metric-card"])
479
- investment_rate = gr.Textbox(label="🎲 Investment Rate", interactive=False, elem_classes=["metric-card"])
480
- last_updated = gr.Textbox(label="🕒 Last Updated", interactive=False, elem_classes=["metric-card"])
481
-
482
- with gr.Row():
483
- with gr.Column(scale=1):
484
- ipo_chart = gr.Plot(label="Investment Decision Breakdown")
485
-
486
- with gr.Column(scale=2):
487
- gr.Markdown("## 🆕 Recent IPO Discoveries")
488
- ipo_table = gr.Dataframe(
489
- label="IPO Discoveries with Investment Decisions",
490
- elem_classes=["gr-dataframe"]
491
- )
492
-
493
- refresh_ipo_btn = gr.Button("🔄 Refresh IPO Data", variant="primary", size="lg")
494
-
495
- # Current Positions Tab
496
- with gr.Tab("🏦 Current Positions"):
497
- gr.Markdown("## 📊 Open Positions")
498
- positions_table = gr.Dataframe(label="Current Holdings", elem_classes=["gr-dataframe"])
499
- refresh_positions_btn = gr.Button("🔄 Refresh Positions", variant="primary", size="lg")
500
-
501
- # System Logs Tab
502
- with gr.Tab("📋 System Logs"):
503
- gr.Markdown("## 🖥️ Trading Bot Activity")
504
-
505
- with gr.Row():
506
- with gr.Column():
507
- gr.Markdown("### 🎯 Parsed Logs (Color Coded)")
508
- system_logs = gr.Textbox(
509
- label="Recent System Activity",
510
- lines=20,
511
- max_lines=20,
512
- interactive=False,
513
- elem_classes=["gr-textbox"]
514
- )
515
-
516
- with gr.Column():
517
- gr.Markdown("### 📄 Raw Cron Logs")
518
- raw_logs = gr.Textbox(
519
- label="Raw Log Output",
520
- lines=20,
521
- max_lines=20,
522
- interactive=False,
523
- elem_classes=["gr-textbox"]
524
- )
525
-
526
- refresh_logs_btn = gr.Button("🔄 Refresh All Logs", variant="primary", size="lg")
527
-
528
- # Footer
529
- gr.HTML("""
530
- <div style="text-align: center; padding: 2rem; color: #666; border-top: 1px solid #eaeaea; margin-top: 3rem; background: white; border-radius: 16px;">
531
- <p style="font-size: 1.1rem;"><strong>🤖 Automated Trading Dashboard</strong></p>
532
- <p style="font-size: 0.95rem;">Real-time data from Alpaca Markets + VM Analytics | Built with ❤️</p>
533
- </div>
534
- """)
535
-
536
- # Event Handlers
537
-
538
- # Portfolio tab
539
- refresh_overview_btn.click(
540
- fn=refresh_account_overview,
541
- outputs=[portfolio_value, buying_power, cash, day_change, equity]
542
- )
543
- refresh_overview_btn.click(
544
- fn=create_portfolio_chart,
545
- outputs=[portfolio_chart]
546
- )
547
-
548
- # IPO tab
549
- refresh_ipo_btn.click(
550
- fn=refresh_vm_stats,
551
- outputs=[total_ipos, ipos_invested, cs_stocks, investment_rate, last_updated]
552
- )
553
- refresh_ipo_btn.click(
554
- fn=create_ipo_discovery_chart,
555
- outputs=[ipo_chart]
556
- )
557
- refresh_ipo_btn.click(
558
- fn=refresh_ipo_discoveries_table,
559
- outputs=[ipo_table]
560
- )
561
-
562
- # Positions tab
563
- refresh_positions_btn.click(
564
- fn=refresh_positions_table,
565
- outputs=[positions_table]
566
- )
567
-
568
- # Logs tab
569
- refresh_logs_btn.click(
570
- fn=refresh_system_logs,
571
- outputs=[system_logs]
572
- )
573
- refresh_logs_btn.click(
574
- fn=refresh_raw_logs,
575
- outputs=[raw_logs]
576
- )
577
-
578
- # Initial data load
579
- demo.load(
580
- fn=refresh_account_overview,
581
- outputs=[portfolio_value, buying_power, cash, day_change, equity]
582
- )
583
- demo.load(fn=create_portfolio_chart, outputs=[portfolio_chart])
584
- demo.load(fn=refresh_positions_table, outputs=[positions_table])
585
- demo.load(
586
- fn=refresh_vm_stats,
587
- outputs=[total_ipos, ipos_invested, cs_stocks, investment_rate, last_updated]
588
- )
589
- demo.load(fn=create_ipo_discovery_chart, outputs=[ipo_chart])
590
- demo.load(fn=refresh_ipo_discoveries_table, outputs=[ipo_table])
591
-
592
- return demo
593
-
594
- # Create and launch
595
- demo = create_dashboard()
596
-
597
- if __name__ == "__main__":
598
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
hf_space/requirements.txt DELETED
@@ -1,9 +0,0 @@
1
- # Trading Dashboard Requirements - Full Featured
2
- gradio>=5.0.0
3
- plotly>=6.0.0
4
- pandas>=2.0.0
5
- numpy>=1.20.0
6
- alpaca-py>=0.8.0
7
- requests>=2.28.0
8
- flask>=2.0.0
9
- flask-cors>=4.0.0
 
 
 
 
 
 
 
 
 
 
hf_space/vm_data_server.py DELETED
@@ -1,277 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- VM Data Server
4
- Exposes local trading bot data via API for dashboard consumption
5
- Runs on the VM alongside your trading bot
6
- """
7
-
8
- import os
9
- import json
10
- import pandas as pd
11
- from datetime import datetime, timedelta
12
- from flask import Flask, jsonify, request
13
- from flask_cors import CORS
14
- import logging
15
-
16
- app = Flask(__name__)
17
- CORS(app) # Allow dashboard to connect from anywhere
18
-
19
- # Configure logging
20
- logging.basicConfig(level=logging.INFO)
21
- logger = logging.getLogger(__name__)
22
-
23
- # File paths
24
- PORTFOLIO_FILE = 'portfolio.txt'
25
- NEW_TICKERS_LOG_FILE = 'new_tickers_log.csv'
26
- SCRIPT_LOG_FILE = 'script.log'
27
- BUY_QUEUE_FILE = 'buy_queue.json'
28
- CURRENT_TICKERS_FILE = 'current_tickers.txt'
29
-
30
- def load_portfolio_data():
31
- """Load portfolio CSV data"""
32
- try:
33
- if os.path.exists(PORTFOLIO_FILE):
34
- df = pd.read_csv(PORTFOLIO_FILE)
35
- return df.to_dict('records')
36
- return []
37
- except Exception as e:
38
- logger.error(f"Error loading portfolio: {e}")
39
- return []
40
-
41
- def load_new_tickers_with_decisions():
42
- """Load IPO discoveries with investment decisions"""
43
- try:
44
- if not os.path.exists(NEW_TICKERS_LOG_FILE):
45
- return []
46
-
47
- df = pd.read_csv(NEW_TICKERS_LOG_FILE)
48
- portfolio_data = load_portfolio_data()
49
-
50
- # Get symbols we actually invested in
51
- invested_symbols = set()
52
- for trade in portfolio_data:
53
- invested_symbols.add(trade.get('symbol', ''))
54
-
55
- # Add investment decision to each IPO
56
- enriched_ipos = []
57
- for _, row in df.iterrows():
58
- symbol = row.get('Symbol', '')
59
- security_type = row.get('Security_Type', '')
60
-
61
- # Determine investment status
62
- if symbol in invested_symbols:
63
- investment_status = 'INVESTED'
64
- status_color = 'success'
65
- status_emoji = '🟢'
66
- elif security_type == 'CS':
67
- investment_status = 'ELIGIBLE_NOT_INVESTED'
68
- status_color = 'warning'
69
- status_emoji = '🟡'
70
- elif security_type in ['SP', 'WARRANT', 'UNIT']:
71
- investment_status = 'WRONG_TYPE'
72
- status_color = 'neutral'
73
- status_emoji = '⚪'
74
- else:
75
- investment_status = 'UNKNOWN'
76
- status_color = 'error'
77
- status_emoji = '🔴'
78
-
79
- enriched_ipos.append({
80
- 'symbol': symbol,
81
- 'security_type': security_type,
82
- 'trading_price': row.get('Trading_Price', 'N/A'),
83
- 'detected_at': row.get('Detected_At', 'N/A'),
84
- 'investment_status': investment_status,
85
- 'status_color': status_color,
86
- 'status_emoji': status_emoji
87
- })
88
-
89
- # Sort by detection date (newest first)
90
- enriched_ipos.sort(key=lambda x: x['detected_at'], reverse=True)
91
-
92
- return enriched_ipos
93
- except Exception as e:
94
- logger.error(f"Error loading IPO data: {e}")
95
- return []
96
-
97
- def load_script_logs(lines=100):
98
- """Load recent script logs"""
99
- try:
100
- if not os.path.exists(SCRIPT_LOG_FILE):
101
- return []
102
-
103
- with open(SCRIPT_LOG_FILE, 'r') as f:
104
- all_lines = f.readlines()
105
-
106
- # Get recent lines
107
- recent_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
108
-
109
- # Parse log lines
110
- logs = []
111
- for line in recent_lines:
112
- line = line.strip()
113
- if line:
114
- # Try to parse timestamp and level
115
- parts = line.split(' - ', 2)
116
- if len(parts) >= 3:
117
- timestamp = parts[0]
118
- level = parts[1]
119
- message = parts[2]
120
-
121
- # Determine log type for color coding
122
- if 'ERROR' in level:
123
- log_type = 'error'
124
- emoji = '🔴'
125
- elif 'WARNING' in level or 'WARN' in level:
126
- log_type = 'warning'
127
- emoji = '🟡'
128
- elif 'Buy order placed' in message or 'Sold' in message:
129
- log_type = 'trade'
130
- emoji = '💰'
131
- elif 'Found' in message and 'new ticker' in message:
132
- log_type = 'discovery'
133
- emoji = '🔍'
134
- elif 'INFO' in level:
135
- log_type = 'info'
136
- emoji = '🔵'
137
- else:
138
- log_type = 'default'
139
- emoji = '⚪'
140
-
141
- logs.append({
142
- 'timestamp': timestamp,
143
- 'level': level,
144
- 'message': message,
145
- 'log_type': log_type,
146
- 'emoji': emoji,
147
- 'full_line': line
148
- })
149
- else:
150
- # Fallback for unparseable lines
151
- logs.append({
152
- 'timestamp': 'N/A',
153
- 'level': 'RAW',
154
- 'message': line,
155
- 'log_type': 'default',
156
- 'emoji': '⚪',
157
- 'full_line': line
158
- })
159
-
160
- return logs
161
- except Exception as e:
162
- logger.error(f"Error loading logs: {e}")
163
- return []
164
-
165
- def load_buy_queue():
166
- """Load current buy queue"""
167
- try:
168
- if os.path.exists(BUY_QUEUE_FILE):
169
- with open(BUY_QUEUE_FILE, 'r') as f:
170
- return json.load(f)
171
- return []
172
- except Exception as e:
173
- logger.error(f"Error loading buy queue: {e}")
174
- return []
175
-
176
- def get_system_stats():
177
- """Get system statistics"""
178
- try:
179
- portfolio_data = load_portfolio_data()
180
- ipo_data = load_new_tickers_with_decisions()
181
-
182
- # Calculate stats
183
- total_ipos_detected = len(ipo_data)
184
- ipos_invested = len([ipo for ipo in ipo_data if ipo['investment_status'] == 'INVESTED'])
185
- current_positions = len(portfolio_data)
186
-
187
- # Get detection stats by type
188
- cs_stocks = len([ipo for ipo in ipo_data if ipo['security_type'] == 'CS'])
189
- other_types = total_ipos_detected - cs_stocks
190
-
191
- return {
192
- 'total_ipos_detected': total_ipos_detected,
193
- 'ipos_invested': ipos_invested,
194
- 'current_positions': current_positions,
195
- 'cs_stocks_detected': cs_stocks,
196
- 'other_types_detected': other_types,
197
- 'investment_rate': round((ipos_invested / cs_stocks * 100) if cs_stocks > 0 else 0, 1),
198
- 'last_updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
199
- }
200
- except Exception as e:
201
- logger.error(f"Error calculating stats: {e}")
202
- return {}
203
-
204
- # API Endpoints
205
-
206
- @app.route('/health')
207
- def health_check():
208
- """Health check endpoint"""
209
- return jsonify({'status': 'healthy', 'timestamp': datetime.now().isoformat()})
210
-
211
- @app.route('/api/portfolio')
212
- def get_portfolio():
213
- """Get portfolio data"""
214
- return jsonify(load_portfolio_data())
215
-
216
- @app.route('/api/ipos')
217
- def get_ipos():
218
- """Get IPO discoveries with investment decisions"""
219
- limit = request.args.get('limit', 50, type=int)
220
- ipos = load_new_tickers_with_decisions()
221
- return jsonify(ipos[:limit])
222
-
223
- @app.route('/api/logs')
224
- def get_logs():
225
- """Get script logs"""
226
- lines = request.args.get('lines', 100, type=int)
227
- logs = load_script_logs(lines)
228
- return jsonify(logs)
229
-
230
- @app.route('/api/buy_queue')
231
- def get_buy_queue():
232
- """Get current buy queue"""
233
- return jsonify(load_buy_queue())
234
-
235
- @app.route('/api/stats')
236
- def get_stats():
237
- """Get system statistics"""
238
- return jsonify(get_system_stats())
239
-
240
- @app.route('/api/logs/raw')
241
- def get_raw_logs():
242
- """Get raw log file content"""
243
- lines = request.args.get('lines', 200, type=int)
244
- try:
245
- if not os.path.exists(SCRIPT_LOG_FILE):
246
- return jsonify({'content': 'No log file found'})
247
-
248
- with open(SCRIPT_LOG_FILE, 'r') as f:
249
- all_lines = f.readlines()
250
-
251
- recent_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
252
- content = ''.join(recent_lines)
253
-
254
- return jsonify({
255
- 'content': content,
256
- 'total_lines': len(all_lines),
257
- 'showing_lines': len(recent_lines)
258
- })
259
- except Exception as e:
260
- return jsonify({'error': str(e), 'content': ''})
261
-
262
- if __name__ == '__main__':
263
- print("🚀 Starting VM Data Server...")
264
- print("📡 This exposes your trading bot data via API")
265
- print("🌐 Dashboard can now access:")
266
- print(" • IPO discoveries with investment decisions")
267
- print(" • Raw cron logs with color coding")
268
- print(" • Portfolio data from VM files")
269
- print(" • Buy queue and system stats")
270
- print("-" * 50)
271
-
272
- # Run on all interfaces so dashboard can connect
273
- app.run(
274
- host='0.0.0.0', # Allow external connections
275
- port=8090, # Different from dashboard port
276
- debug=False
277
- )