OmidSakaki commited on
Commit
702eb67
·
verified ·
1 Parent(s): 8b48d05

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +535 -628
app.py CHANGED
@@ -1,751 +1,658 @@
1
  import gradio as gr
2
  import numpy as np
3
  import pandas as pd
4
- import matplotlib.pyplot as plt
5
  import torch
6
- import io
7
- import base64
8
- from PIL import Image
9
- import plotly.graph_objects as go
10
- from plotly.subplots import make_subplots
11
  import time
12
  import sys
13
  import os
14
  import threading
 
15
  from datetime import datetime, timedelta
 
 
 
16
 
17
- # Set matplotlib backend
18
- plt.switch_backend('Agg')
 
19
 
20
- # Create directories and init files
21
- os.makedirs('src/environments', exist_ok=True)
22
- os.makedirs('src/agents', exist_ok=True)
23
- os.makedirs('src/sentiment', exist_ok=True)
24
- os.makedirs('src/visualizers', exist_ok=True)
25
- os.makedirs('src/utils', exist_ok=True)
 
 
 
 
 
 
 
26
 
27
- for dir_path in ['src', 'src/environments', 'src/agents', 'src/sentiment', 'src/visualizers', 'src/utils']:
28
- init_file = os.path.join(dir_path, '__init__.py')
29
- with open(init_file, 'w') as f:
30
- f.write('')
31
 
32
- sys.path.append('src')
 
 
33
 
34
- # Import our custom modules
35
- from src.environments.visual_trading_env import VisualTradingEnvironment
36
- from src.agents.visual_agent import VisualTradingAgent
 
 
 
 
 
 
 
 
37
 
38
- class RealTimeTradingDemo:
 
 
39
  def __init__(self):
40
  self.env = None
41
  self.agent = None
 
 
42
  self.current_state = None
43
  self.is_training = False
44
  self.training_complete = False
45
  self.live_trading = False
46
  self.trading_thread = None
47
- self.live_data = []
48
- self.performance_data = []
49
- self.action_history = []
 
 
50
  self.initialized = False
51
  self.start_time = None
52
  self.last_update = None
53
 
54
- def initialize_environment(self, initial_balance, risk_level, asset_type):
55
- """Initialize trading environment"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  try:
57
- print(f"🚀 Initializing Real-Time Trading Environment...")
58
-
59
- self.env = VisualTradingEnvironment(
60
- initial_balance=float(initial_balance),
61
- risk_level=risk_level,
62
- asset_type=asset_type
63
- )
64
-
65
- self.agent = VisualTradingAgent(
66
- state_dim=(84, 84, 4),
67
- action_dim=4
68
- )
69
-
70
- self.current_state = self.env.reset()
71
- self.live_data = []
72
- self.performance_data = []
73
- self.action_history = []
74
- self.training_complete = False
75
- self.live_trading = False
76
- self.initialized = True
77
- self.start_time = datetime.now()
78
- self.last_update = datetime.now()
79
-
80
- # Initialize live data with more realistic pattern
81
- self._initialize_live_data()
82
-
83
- return "✅ محیط معاملاتی Real-Time راه‌اندازی شد!\n\n🎯 آماده برای شروع آموزش هوش مصنوعی..."
84
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  except Exception as e:
86
- error_msg = f" خطا در راه‌اندازی محیط: {str(e)}"
87
- print(error_msg)
88
- return error_msg
89
 
90
- def _initialize_live_data(self):
91
- """Initialize live trading data with realistic patterns"""
92
- base_price = 100
93
- # Create realistic price pattern with some volatility
94
- for i in range(100):
95
- # Simulate realistic market movements
96
- trend = np.sin(i * 0.1) * 5 # Long-term trend
97
- noise = np.random.normal(0, 1.5) # Market noise
98
- price = base_price + trend + noise
99
-
100
- self.live_data.append({
101
- 'timestamp': datetime.now() - timedelta(seconds=100-i),
102
- 'price': max(50, price), # Prevent negative prices
103
- 'action': 0,
104
- 'net_worth': self.env.initial_balance if self.env else 10000,
105
- 'volume': np.random.randint(1000, 10000)
106
- })
107
 
108
- def train_agent(self, num_episodes):
109
- """Train the AI agent and show real-time progress"""
110
- if not self.initialized or self.env is None:
111
- yield "❌ لطفا اول محیط را راه‌اندازی کنید!", None
 
 
 
 
112
  return
113
-
114
- self.is_training = True
115
- self.training_complete = False
116
- training_history = []
117
 
118
  try:
119
- num_episodes = int(num_episodes)
 
120
 
121
  for episode in range(num_episodes):
 
 
 
 
122
  state = self.env.reset()
123
  episode_reward = 0.0
124
  done = False
125
- steps = 0
 
126
 
127
- while not done and steps < 100:
128
  action = self.agent.select_action(state)
129
  next_state, reward, done, info = self.env.step(action)
130
- self.agent.store_transition(state, action, reward, next_state, done)
 
 
 
 
 
131
  state = next_state
132
  episode_reward += reward
133
- steps += 1
134
 
135
  # Update agent
136
- loss = self.agent.update()
 
 
 
137
 
138
- training_history.append({
 
139
  'episode': episode,
140
  'reward': episode_reward,
141
- 'net_worth': info['net_worth'],
142
  'loss': loss,
143
- 'steps': steps
 
144
  })
145
 
146
- # Create real-time training progress
147
- progress_chart = self._create_training_progress(training_history)
 
 
 
148
 
149
- # Update status message
150
- progress_percent = (episode + 1) / num_episodes * 100
151
- status = (
152
- f"🔄 در حال آموزش هوش مصنوعی...\n"
153
- f"📊 پیشرفت: {episode+1}/{num_episodes} ({progress_percent:.1f}%)\n"
154
- f"🎯 Reward این اپیزود: {episode_reward:.3f}\n"
155
- f"💰 ارزش پرتفولیو: ${info['net_worth']:.2f}\n"
156
- f"📉 Loss: {loss:.4f}\n"
157
- f"🎲 Epsilon: {self.agent.epsilon:.3f}"
158
- )
159
 
160
- yield status, progress_chart
161
- time.sleep(0.1)
162
 
163
- self.is_training = False
164
  self.training_complete = True
165
-
166
- # Calculate final metrics
167
- final_reward = np.mean([h['reward'] for h in training_history])
168
- final_net_worth = training_history[-1]['net_worth']
169
-
170
- completion_status = (
171
- f"✅ آموزش هوش مصنوعی با موفقیت تکمیل شد!\n\n"
172
- f"🎯 نتایج نهایی:\n"
173
- f"• تعداد اپیزودها: {num_episodes}\n"
174
- f"• میانگین Reward: {final_reward:.3f}\n"
175
- f"• ارزش نهایی پرتفولیو: ${final_net_worth:.2f}\n"
176
- f"• Epsilon نهایی: {self.agent.epsilon:.3f}\n\n"
177
- f"🚀 آماده برای معامله Real-Time!"
178
- )
179
-
180
- yield completion_status, self._create_training_progress(training_history)
181
 
182
  except Exception as e:
 
 
 
 
183
  self.is_training = False
184
- error_msg = f"❌ خطا در آموزش: {str(e)}"
185
- print(f"Training error: {e}")
186
- yield error_msg, None
187
 
188
- def start_live_trading(self):
189
- """Start real-time live trading demo"""
190
- if not self.training_complete:
191
- return " لطفا اول آموزش را کامل کنید!", None, None, None
192
-
193
- if self.live_trading:
194
- return "⚠️ معامله Real-Time در حال اجراست!", None, None, None
195
-
196
- self.live_trading = True
197
- self.live_data = []
198
- self.performance_data = []
199
- self.action_history = []
200
- self._initialize_live_data()
201
-
202
- # Start live trading in a separate thread
203
- self.trading_thread = threading.Thread(target=self._live_trading_loop)
204
- self.trading_thread.daemon = True
205
- self.trading_thread.start()
206
-
207
- # Get initial status and charts
208
- status = "🎯 معامله Real-Time شروع شد!\n\n📈 نمودارها بصورت زنده آپدیت می‌شوند..."
209
- live_chart = self._create_live_chart()
210
- performance_chart = self._create_performance_chart()
211
- stats_table = self._create_stats_table()
212
-
213
- return status, live_chart, performance_chart, stats_table
214
 
215
- def _live_trading_loop(self):
216
- """Main live trading loop"""
217
- step_count = 0
218
- max_steps = 300 # Run for demo
219
-
220
- while self.live_trading and step_count < max_steps:
221
- try:
222
- # Get AI decision
223
- action = self.agent.select_action(self.current_state)
224
-
225
- # Execute action
226
- next_state, reward, done, info = self.env.step(action)
227
- self.current_state = next_state
228
-
229
- # Update live data with realistic price movement
230
- current_time = datetime.now()
231
- last_price = self.live_data[-1]['price'] if self.live_data else 100
232
-
233
- # Simulate realistic price movement
234
- price_change = np.random.normal(0, 0.8) # Random walk
235
- if action == 1: # Buy - slight upward pressure
236
- price_change += 0.3
237
- elif action == 2: # Sell - slight downward pressure
238
- price_change -= 0.3
 
 
 
 
 
 
 
 
 
 
239
 
240
- new_price = max(50, last_price + price_change)
 
 
241
 
242
- self.live_data.append({
243
- 'timestamp': current_time,
244
- 'price': new_price,
245
- 'action': action,
246
- 'net_worth': info['net_worth'],
247
- 'volume': np.random.randint(1000, 15000)
248
- })
249
 
250
- # Keep only last 100 data points for performance
251
- if len(self.live_data) > 100:
252
- self.live_data.pop(0)
253
 
254
- self.action_history.append({
255
- 'step': step_count,
256
- 'action': action,
257
- 'reward': reward,
258
- 'timestamp': current_time,
259
- 'price': new_price
260
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- self.last_update = current_time
263
- step_count += 1
264
- time.sleep(1) # 1 second between steps
265
 
266
  except Exception as e:
267
- print(f"Error in live trading: {e}")
268
- break
 
269
 
270
  self.live_trading = False
271
 
272
- def get_live_update(self):
273
- """Get real-time update for auto-refresh"""
274
- if not self.live_trading:
275
- return {
276
- "status": "🛑 معامله Real-Time متوقف شده",
277
- "live_chart": self._create_live_chart(),
278
- "performance_chart": self._create_performance_chart(),
279
- "stats_table": self._create_stats_table()
280
- }
281
-
282
- current_data = self.live_data[-1] if self.live_data else None
283
- if not current_data:
284
- return {
285
- "status": "📊 در حال آماده‌سازی داده...",
286
- "live_chart": self._create_live_chart(),
287
- "performance_chart": self._create_performance_chart(),
288
- "stats_table": self._create_stats_table()
289
- }
290
-
291
- action_names = ["نگهداری", "خرید", "فروش", "بستن"]
292
- action = current_data['action']
293
- action_text = action_names[action]
294
-
295
- # Calculate performance metrics
296
- initial_balance = self.env.initial_balance
297
- current_net_worth = current_data['net_worth']
298
- profit_loss = current_net_worth - initial_balance
299
- profit_loss_pct = (profit_loss / initial_balance) * 100
300
-
301
- status = (
302
- f"🎯 معامله Real-Time در حال اجرا...\n"
303
- f"💰 قیمت فعلی: ${current_data['price']:.2f}\n"
304
- f"🎪 اقدام اخیر: {action_text}\n"
305
- f"💼 ارزش پرتفولیو: ${current_net_worth:.2f}\n"
306
- f"📈 سود/زیان: ${profit_loss:.2f} ({profit_loss_pct:+.2f}%)\n"
307
- f"⏰ زمان اجرا: {len(self.action_history)} ثانیه"
308
- )
309
-
310
- return {
311
- "status": status,
312
- "live_chart": self._create_live_chart(),
313
- "performance_chart": self._create_performance_chart(),
314
- "stats_table": self._create_stats_table()
315
- }
316
 
317
- def stop_live_trading(self):
318
- """Stop the live trading demo"""
319
- self.live_trading = False
320
- if self.trading_thread and self.trading_thread.is_alive():
321
- self.trading_thread.join(timeout=1.0)
322
-
323
- final_net_worth = self.live_data[-1]['net_worth'] if self.live_data else self.env.initial_balance
324
- initial_balance = self.env.initial_balance
325
- profit_loss = final_net_worth - initial_balance
326
- profit_loss_pct = (profit_loss / initial_balance) * 100
327
-
328
- # Calculate action statistics
329
- actions = [h['action'] for h in self.action_history]
330
- action_counts = {
331
- "نگهداری": actions.count(0),
332
- "خرید": actions.count(1),
333
- "فروش": actions.count(2),
334
- "بستن": actions.count(3)
335
- }
336
-
337
- performance = (
338
- f"🛑 معامله Real-Time متوقف شد\n\n"
339
- f"📈 عملکرد نهایی:\n"
340
- f"• سرمایه اولیه: ${initial_balance:.2f}\n"
341
- f"• سرمایه نهایی: ${final_net_worth:.2f}\n"
342
- f" سود/زیان: ${profit_loss:.2f} ({profit_loss_pct:+.2f}%)\n"
343
- f" تعداد اقدامات: {len(self.action_history)}\n"
344
- f" خریدها: {action_counts['خرید']} | فروش‌ها: {action_counts['فروش']}"
345
- )
346
-
347
- return performance, self._create_live_chart(), self._create_performance_chart(), self._create_stats_table()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  def _create_live_chart(self):
350
- """Create real-time trading chart with advanced features"""
351
- if not self.live_data:
352
- fig = go.Figure()
353
- fig.update_layout(
354
- title="📊 نمودار Real-Time - در حال آماده‌سازی...",
355
- height=400,
356
- template="plotly_dark"
357
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  return fig
359
-
360
- times = [d['timestamp'] for d in self.live_data]
361
- prices = [d['price'] for d in self.live_data]
362
- actions = [d['action'] for d in self.live_data]
363
- volumes = [d['volume'] for d in self.live_data]
364
-
365
- fig = make_subplots(
366
- rows=2, cols=1,
367
- subplot_titles=['🎯 نمودار قیمت لحظه‌ای', '📊 حجم معاملات'],
368
- vertical_spacing=0.1,
369
- row_heights=[0.7, 0.3]
370
- )
371
-
372
- # Price line
373
- fig.add_trace(go.Scatter(
374
- x=times,
375
- y=prices,
376
- mode='lines',
377
- name='قیمت',
378
- line=dict(color='#00FF00', width=3),
379
- hovertemplate='<b>قیمت: $%{y:.2f}</b><br>زمان: %{x}<extra></extra>'
380
- ), row=1, col=1)
381
-
382
- # Action markers
383
- buy_times = [times[i] for i, action in enumerate(actions) if action == 1]
384
- buy_prices = [prices[i] for i, action in enumerate(actions) if action == 1]
385
-
386
- sell_times = [times[i] for i, action in enumerate(actions) if action == 2]
387
- sell_prices = [prices[i] for i, action in enumerate(actions) if action == 2]
388
-
389
- if buy_times:
390
- fig.add_trace(go.Scatter(
391
- x=buy_times,
392
- y=buy_prices,
393
- mode='markers',
394
- name='خرید',
395
- marker=dict(color='green', size=10, symbol='triangle-up', line=dict(width=2, color='darkgreen')),
396
- hovertemplate='<b>🚀 خرید در $%{y:.2f}</b><br>زمان: %{x}<extra></extra>'
397
- ), row=1, col=1)
398
-
399
- if sell_times:
400
- fig.add_trace(go.Scatter(
401
- x=sell_times,
402
- y=sell_prices,
403
- mode='markers',
404
- name='فروش',
405
- marker=dict(color='red', size=10, symbol='triangle-down', line=dict(width=2, color='darkred')),
406
- hovertemplate='<b>📉 فروش در $%{y:.2f}</b><br>زمان: %{x}<extra></extra>'
407
- ), row=1, col=1)
408
-
409
- # Volume bars
410
- fig.add_trace(go.Bar(
411
- x=times,
412
- y=volumes,
413
- name='حجم',
414
- marker_color='rgba(100, 100, 200, 0.6)',
415
- hovertemplate='<b>حجم: %{y:,}</b><br>زمان: %{x}<extra></extra>'
416
- ), row=2, col=1)
417
-
418
- fig.update_layout(
419
- title="🎯 نمودار معاملات Real-Time - آپدیت لحظه‌ای",
420
- height=500,
421
- showlegend=True,
422
- template="plotly_dark",
423
- hovermode='x unified'
424
- )
425
-
426
- fig.update_xaxes(title_text="زمان", row=2, col=1)
427
- fig.update_yaxes(title_text="قیمت ($)", row=1, col=1)
428
- fig.update_yaxes(title_text="حجم", row=2, col=1)
429
-
430
- return fig
431
 
432
  def _create_performance_chart(self):
433
- """Create animated performance chart"""
434
- if not self.live_data:
 
 
 
 
 
 
 
 
 
 
435
  fig = go.Figure()
436
- fig.update_layout(
437
- title="📈 عملکرد پرتفولیو - در حال آماده‌سازی...",
438
- height=350,
439
- template="plotly_dark"
440
- )
 
 
 
441
  return fig
442
-
443
- times = [d['timestamp'] for d in self.live_data]
444
- net_worths = [d['net_worth'] for d in self.live_data]
445
-
446
- fig = go.Figure()
447
-
448
- # Net worth line with gradient
449
- fig.add_trace(go.Scatter(
450
- x=times,
451
- y=net_worths,
452
- mode='lines',
453
- name='ارزش پرتفولیو',
454
- line=dict(color='#00FF00', width=4),
455
- hovertemplate='<b>پرتفولیو: $%{y:.2f}</b><br>زمان: %{x}<extra></extra>'
456
- ))
457
-
458
- # Add initial balance line
459
- if self.env:
460
- fig.add_hline(y=self.env.initial_balance, line_dash="dash",
461
- line_color="red", annotation_text="سرمایه اولیه")
462
-
463
- fig.update_layout(
464
- title="💼 عملکرد Real-Time پرتفولیو",
465
- height=350,
466
- template="plotly_dark",
467
- showlegend=True,
468
- hovermode='x unified'
469
- )
470
-
471
- fig.update_yaxes(title_text="ارزش ($)")
472
- fig.update_xaxes(title_text="زمان")
473
-
474
- return fig
475
 
476
- def _create_stats_table(self):
477
- """Create real-time statistics table"""
478
- if not self.live_data:
479
- return pd.DataFrame({
480
- 'متریک': ['در حال بارگذاری...'],
481
- 'مقدار': ['-']
482
- })
483
-
484
- current_data = self.live_data[-1]
485
- initial_balance = self.env.initial_balance
486
- current_net_worth = current_data['net_worth']
487
-
488
- # Calculate statistics
489
- profit_loss = current_net_worth - initial_balance
490
- profit_loss_pct = (profit_loss / initial_balance) * 100
491
-
492
- # Price statistics
493
- prices = [d['price'] for d in self.live_data]
494
- current_price = prices[-1]
495
- price_change = current_price - prices[0] if len(prices) > 1 else 0
496
- price_change_pct = (price_change / prices[0]) * 100 if len(prices) > 1 else 0
497
-
498
- # Action statistics
499
- recent_actions = [d['action'] for d in self.live_data[-20:]] # Last 20 actions
500
- action_counts = {
501
- "خرید": recent_actions.count(1),
502
- "فروش": recent_actions.count(2),
503
- "بستن": recent_actions.count(3)
504
- }
505
-
506
- stats_data = {
507
- 'متریک': [
508
- '💰 قیمت فعلی',
509
- '📈 تغییر قیمت',
510
- '💼 ارزش پرتفولیو',
511
- '🎯 سود/زیان',
512
- '🔄 اقدامات اخیر',
513
- '⏰ مدت اجرا'
514
- ],
515
- 'مقدار': [
516
- f'${current_price:.2f}',
517
- f'{price_change_pct:+.2f}%',
518
- f'${current_net_worth:.2f}',
519
- f'${profit_loss:+.2f} ({profit_loss_pct:+.2f}%)',
520
- f'خرید: {action_counts["خرید"]} | فروش: {action_counts["فروش"]}',
521
- f'{len(self.action_history)} ثانیه'
522
- ]
523
- }
524
-
525
- return pd.DataFrame(stats_data)
526
 
527
- def _create_training_progress(self, training_history):
528
- """Create training progress visualization"""
529
- if not training_history:
530
- fig = go.Figure()
531
- fig.update_layout(
532
- title="📊 پیشرفت آموزش - در حال آماده‌سازی...",
533
- height=400
534
- )
535
- return fig
536
-
537
- episodes = [h['episode'] for h in training_history]
538
- rewards = [h['reward'] for h in training_history]
539
- net_worths = [h['net_worth'] for h in training_history]
540
-
541
- fig = make_subplots(
542
- rows=2, cols=1,
543
- subplot_titles=['📈 Reward اپیزودها', '💰 ارزش پرتفولیو'],
544
- vertical_spacing=0.15
545
- )
546
-
547
- # Rewards
548
- fig.add_trace(go.Scatter(
549
- x=episodes, y=rewards, mode='lines+markers',
550
- name='Reward', line=dict(color='blue', width=2),
551
- marker=dict(size=4)
552
- ), row=1, col=1)
553
-
554
- # Portfolio value
555
- fig.add_trace(go.Scatter(
556
- x=episodes, y=net_worths, mode='lines+markers',
557
- name='Net Worth', line=dict(color='green', width=2),
558
- marker=dict(size=4)
559
- ), row=2, col=1)
560
-
561
- fig.update_layout(
562
- height=400,
563
- showlegend=True,
564
- title_text="🎯 پیشرفت آموزش هوش مصنوعی",
565
- template="plotly_white"
566
- )
567
-
568
- return fig
569
-
570
- # Initialize the demo
571
- demo = RealTimeTradingDemo()
572
 
573
- # Create Gradio interface
574
  def create_interface():
575
- with gr.Blocks(theme=gr.themes.Soft(), title="Real-Time Trading AI") as interface:
576
- gr.Markdown("""
577
- # 🚀 هوش مصنوعی معامله‌گر Real-Time
578
- **آموزش و اجرای بلادرنگ روی نمو��ارهای زنده**
579
-
580
- *برای آپدیت لحظه‌ای، دکمه "بروزرسانی لحظه‌ای" را فشار دهید*
581
- """)
582
 
583
  with gr.Row():
584
  with gr.Column(scale=1):
585
- # Configuration section
586
- gr.Markdown("## ⚙️ پیکربندی سیستم")
587
-
588
- with gr.Row():
589
- initial_balance = gr.Slider(
590
- minimum=1000, maximum=50000, value=10000, step=1000,
591
- label="سرمایه اولیه ($)"
592
- )
593
-
594
- with gr.Row():
595
- risk_level = gr.Radio(
596
- ["Low", "Medium", "High"],
597
- value="Medium",
598
- label="سطح ریسک"
599
- )
600
-
601
- with gr.Row():
602
- asset_type = gr.Radio(
603
- ["Stock", "Crypto", "Forex"],
604
- value="Stock",
605
- label="نوع دارایی"
606
- )
607
-
608
- with gr.Row():
609
- init_btn = gr.Button(
610
- "🚀 راه‌اندازی محیط",
611
- variant="primary"
612
- )
613
-
614
- with gr.Row():
615
- init_status = gr.Textbox(
616
- label="وضعیت سیستم",
617
- interactive=False,
618
- lines=3
619
- )
620
 
621
  with gr.Column(scale=2):
622
- # Status output
623
- gr.Markdown("## 📊 وضعیت جاری")
624
- status_output = gr.Textbox(
625
- label="وضعیت عملیات",
626
- interactive=False,
627
- lines=5
628
- )
629
 
630
- with gr.Row():
631
- gr.Markdown("## 🎓 فاز ۱: آموزش هوش مصنوعی")
632
-
633
  with gr.Row():
634
  with gr.Column(scale=1):
635
- num_episodes = gr.Slider(
636
- minimum=10, maximum=100, value=30, step=5,
637
- label="تعداد اپیزودهای آموزش"
638
- )
639
-
640
- train_btn = gr.Button(
641
- "🤖 شروع آموزش",
642
- variant="primary",
643
- size="lg"
644
- )
645
 
646
  with gr.Column(scale=2):
647
- training_plot = gr.Plot(
648
- label="📈 پیشرفت آموزش"
649
- )
650
 
651
- with gr.Row():
652
- gr.Markdown("## 🎯 فاز ۲: معامله Real-Time")
653
-
654
  with gr.Row():
655
  with gr.Column(scale=1):
656
- start_btn = gr.Button(
657
- "▶️ شروع معامله Real-Time",
658
- variant="secondary",
659
- size="lg"
660
- )
661
-
662
- update_btn = gr.Button(
663
- "🔄 بروزرسانی لحظه‌ای",
664
- variant="secondary",
665
- size="lg"
666
- )
667
-
668
- stop_btn = gr.Button(
669
- "⏹️ توقف معامله",
670
- variant="stop",
671
- size="lg"
672
- )
673
-
674
- with gr.Row():
675
- with gr.Column(scale=2):
676
- live_chart = gr.Plot(
677
- label="📊 نمودار معاملات Real-Time"
678
- )
679
 
680
- with gr.Column(scale=1):
681
- performance_chart = gr.Plot(
682
- label="💼 عملکرد پرتفولیو"
683
- )
684
 
685
  with gr.Row():
686
- gr.Markdown("## 📈 آمار لحظه‌ای")
687
-
688
- with gr.Row():
689
- stats_table = gr.Dataframe(
690
- label="📊 متریک‌های Real-Time",
691
- headers=['متریک', 'مقدار'],
692
- datatype=['str', 'str'],
693
- row_count=6,
694
- col_count=2
695
- )
696
 
697
  # Event handlers
698
  init_btn.click(
699
  demo.initialize_environment,
700
- inputs=[initial_balance, risk_level, asset_type],
701
  outputs=[init_status]
702
  )
703
 
704
  train_btn.click(
705
  demo.train_agent,
706
- inputs=[num_episodes],
707
- outputs=[status_output, training_plot]
708
  )
709
 
710
  start_btn.click(
711
  demo.start_live_trading,
712
- inputs=[],
713
- outputs=[status_output, live_chart, performance_chart, stats_table]
714
  )
715
 
716
  update_btn.click(
717
- lambda: demo.get_live_update(),
718
- inputs=[],
719
- outputs=[status_output, live_chart, performance_chart, stats_table]
720
  )
721
 
722
  stop_btn.click(
723
  demo.stop_live_trading,
724
- inputs=[],
725
- outputs=[status_output, live_chart, performance_chart, stats_table]
726
  )
727
-
728
- gr.Markdown("""
729
- ## 🧠 نحوه کار سیستم Real-Time:
730
-
731
- 1. **آموزش هوش مصنوعی** (فاز ۱)
732
- 2. **شروع معامله Real-Time**
733
- 3. **فشار دادن دکمه "بروزرسانی لحظه‌ای"** برای آپدیت نمودارها
734
- 4. **مشاهده عملکرد زنده** روی نمودارهای متحرک
735
-
736
- *برای ضبط ریلز: بعد از شروع معامله، دکمه بروزرسانی را فشار دهید تا نمودارها آپدیت شوند*
737
-
738
- *توسعه داده شده توسط Omid Sakaki - 2024*
739
- """)
740
 
741
- return interface
742
 
743
- # Create and launch interface
744
  if __name__ == "__main__":
745
- print("🚀 Starting Real-Time Trading AI Demo...")
746
- interface = create_interface()
747
- interface.launch(
748
- server_name="0.0.0.0",
749
- server_port=7860,
750
- share=False
751
- )
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import numpy as np
3
  import pandas as pd
 
4
  import torch
 
 
 
 
 
5
  import time
6
  import sys
7
  import os
8
  import threading
9
+ import logging
10
  from datetime import datetime, timedelta
11
+ from typing import Dict, Any, Optional, Tuple
12
+ import warnings
13
+ warnings.filterwarnings('ignore')
14
 
15
+ # Configure logging
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger(__name__)
18
 
19
+ # Create directories safely
20
+ def setup_directories():
21
+ """Setup project directories with error handling"""
22
+ directories = ['src', 'src/environments', 'src/agents', 'src/sentiment', 'src/visualizers', 'src/utils']
23
+ for dir_path in directories:
24
+ try:
25
+ os.makedirs(dir_path, exist_ok=True)
26
+ init_file = os.path.join(dir_path, '__init__.py')
27
+ if not os.path.exists(init_file):
28
+ with open(init_file, 'w') as f:
29
+ f.write('# Auto-generated init file\n')
30
+ except Exception as e:
31
+ logger.warning(f"Could not create directory {dir_path}: {e}")
32
 
33
+ setup_directories()
 
 
 
34
 
35
+ # Add src to path safely
36
+ if 'src' not in sys.path:
37
+ sys.path.insert(0, 'src')
38
 
39
+ # Safe imports with fallbacks
40
+ try:
41
+ from src.environments.advanced_trading_env import AdvancedTradingEnvironment
42
+ from src.agents.advanced_agent import AdvancedTradingAgent
43
+ from src.utils.config import TradingConfig
44
+ from src.visualizers.chart_renderer import ChartRenderer
45
+ CUSTOM_MODULES_AVAILABLE = True
46
+ except ImportError as e:
47
+ logger.warning(f"Custom modules not available: {e}. Using fallback mode.")
48
+ CUSTOM_MODULES_AVAILABLE = False
49
+ # Fallback imports will be defined below
50
 
51
+ class SafeTradingDemo:
52
+ """Safe trading demo with comprehensive error handling"""
53
+
54
  def __init__(self):
55
  self.env = None
56
  self.agent = None
57
+ self.config = TradingConfig() if CUSTOM_MODULES_AVAILABLE else None
58
+ self.renderer = ChartRenderer() if CUSTOM_MODULES_AVAILABLE else None
59
  self.current_state = None
60
  self.is_training = False
61
  self.training_complete = False
62
  self.live_trading = False
63
  self.trading_thread = None
64
+ self.lock = threading.Lock()
65
+ self.live_data: list = []
66
+ self.performance_data: list = []
67
+ self.action_history: list = []
68
+ self.training_history: list = []
69
  self.initialized = False
70
  self.start_time = None
71
  self.last_update = None
72
 
73
+ # Fallback environment and agent if custom modules unavailable
74
+ if not CUSTOM_MODULES_AVAILABLE:
75
+ self._setup_fallback_components()
76
+
77
+ def _setup_fallback_components(self):
78
+ """Setup basic fallback components"""
79
+ class FallbackEnvironment:
80
+ def __init__(self, initial_balance, risk_level, asset_type):
81
+ self.initial_balance = initial_balance
82
+ self.current_balance = initial_balance
83
+ self.position = 0
84
+ self.current_price = 100.0
85
+
86
+ def reset(self):
87
+ self.current_balance = self.initial_balance
88
+ self.position = 0
89
+ self.current_price = 100.0 + np.random.normal(0, 5)
90
+ return np.random.rand(84, 84, 4).astype(np.float32)
91
+
92
+ def step(self, action):
93
+ self.current_price += np.random.normal(0, 1)
94
+ reward = np.random.normal(0, 10)
95
+ self.current_balance += reward * 0.1
96
+ done = False
97
+ info = {'net_worth': self.current_balance}
98
+ next_state = np.random.rand(84, 84, 4).astype(np.float32)
99
+ return next_state, reward, done, info
100
+
101
+ class FallbackAgent:
102
+ def __init__(self, state_dim, action_dim):
103
+ self.epsilon = 1.0
104
+ self.action_dim = action_dim
105
+
106
+ def select_action(self, state):
107
+ if np.random.random() < self.epsilon:
108
+ return np.random.randint(0, self.action_dim)
109
+ return 0
110
+
111
+ def store_transition(self, *args):
112
+ pass
113
+
114
+ def update(self):
115
+ self.epsilon = max(0.01, self.epsilon * 0.999)
116
+ return np.random.random()
117
+
118
+ self.FallbackEnvironment = FallbackEnvironment
119
+ self.FallbackAgent = FallbackAgent
120
+
121
+ def initialize_environment(self, initial_balance: float, risk_level: str,
122
+ asset_type: str) -> str:
123
+ """Initialize trading environment with comprehensive validation"""
124
  try:
125
+ with self.lock:
126
+ if self.live_trading:
127
+ return "⚠️ لطفاً ابتدا معاملات را متوقف کنید"
128
+
129
+ # Validate inputs
130
+ if initial_balance < 1000:
131
+ return "❌ سرمایه اولیه باید حداقل 1000 دلار باشد"
132
+ if risk_level not in ["Low", "Medium", "High"]:
133
+ return "❌ سطح ریسک نامعتبر"
134
+ if asset_type not in ["Crypto", "Stock", "Forex"]:
135
+ return "❌ نوع دارایی نامعتبر"
136
+
137
+ logger.info(f"Initializing environment: balance={initial_balance}, "
138
+ f"risk={risk_level}, asset={asset_type}")
139
+
140
+ if CUSTOM_MODULES_AVAILABLE:
141
+ self.env = AdvancedTradingEnvironment(
142
+ initial_balance=float(initial_balance),
143
+ risk_level=risk_level,
144
+ asset_type=asset_type,
145
+ use_sentiment=False # Disable for demo stability
146
+ )
147
+ self.agent = AdvancedTradingAgent(
148
+ state_dim=(84, 84, 4),
149
+ action_dim=4,
150
+ learning_rate=self.config.learning_rate
151
+ )
152
+ else:
153
+ self.env = self.FallbackEnvironment(initial_balance, risk_level, asset_type)
154
+ self.agent = self.FallbackAgent((84, 84, 4), 4)
155
+
156
+ self.current_state = self.env.reset()
157
+ self._reset_data()
158
+ self.initialized = True
159
+ self.start_time = datetime.now()
160
+
161
+ return (f"✅ محیط معاملاتی با موفقیت راه‌اندازی شد!\n\n"
162
+ f"💰 سرمایه: ${initial_balance:,.2f}\n"
163
+ f"🎯 نوع دارایی: {asset_type}\n"
164
+ f"⚡ سطح ریسک: {risk_level}\n\n"
165
+ f"🚀 آماده برای آموزش...")
166
+
167
  except Exception as e:
168
+ logger.error(f"Environment initialization error: {e}", exc_info=True)
169
+ return f"❌ خطا در راه‌اندازی: {str(e)}"
 
170
 
171
+ def _reset_data(self):
172
+ """Reset all data structures"""
173
+ self.live_data.clear()
174
+ self.performance_data.clear()
175
+ self.action_history.clear()
176
+ self.training_history.clear()
177
+ self.training_complete = False
178
+ self.live_trading = False
 
 
 
 
 
 
 
 
 
179
 
180
+ def train_agent(self, num_episodes: int):
181
+ """Train agent with progress updates and safety checks"""
182
+ if not self.initialized:
183
+ yield "❌ ابتدا محیط را راه‌اندازی کنید", None
184
+ return
185
+
186
+ if self.live_trading:
187
+ yield "⚠️ ابتدا معاملات را متوقف کنید", None
188
  return
 
 
 
 
189
 
190
  try:
191
+ num_episodes = max(1, min(100, int(num_episodes))) # Limit episodes
192
+ self.is_training = True
193
 
194
  for episode in range(num_episodes):
195
+ if not self.is_training:
196
+ break
197
+
198
+ episode_start = time.time()
199
  state = self.env.reset()
200
  episode_reward = 0.0
201
  done = False
202
+ step_count = 0
203
+ max_steps = 200 # Safety limit
204
 
205
+ while not done and step_count < max_steps:
206
  action = self.agent.select_action(state)
207
  next_state, reward, done, info = self.env.step(action)
208
+
209
+ try:
210
+ self.agent.store_transition(state, action, reward, next_state, done)
211
+ except:
212
+ pass # Ignore storage errors in demo
213
+
214
  state = next_state
215
  episode_reward += reward
216
+ step_count += 1
217
 
218
  # Update agent
219
+ try:
220
+ loss = self.agent.update()
221
+ except:
222
+ loss = 0.0
223
 
224
+ # Store episode data
225
+ self.training_history.append({
226
  'episode': episode,
227
  'reward': episode_reward,
228
+ 'net_worth': info.get('net_worth', 10000),
229
  'loss': loss,
230
+ 'steps': step_count,
231
+ 'duration': time.time() - episode_start
232
  })
233
 
234
+ # Create progress visualization
235
+ try:
236
+ progress_fig = self._create_training_chart()
237
+ except:
238
+ progress_fig = None
239
 
240
+ # Progress status
241
+ progress = (episode + 1) / num_episodes * 100
242
+ status = (f"🔄 آموزش در حال انجام...\n"
243
+ f"📊 اپیزود {episode+1}/{num_episodes} ({progress:.1f}%)\n"
244
+ f"🎯 پاداش: {episode_reward:.2f}\n"
245
+ f"💰 پرتفولیو: ${info.get('net_worth', 0):.2f}\n"
246
+ f"📉 Loss: {loss:.4f}")
 
 
 
247
 
248
+ yield status, progress_fig
249
+ time.sleep(0.05) # Brief pause for UI responsiveness
250
 
 
251
  self.training_complete = True
252
+ final_stats = self._calculate_training_stats()
253
+ yield final_stats, self._create_training_chart()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  except Exception as e:
256
+ logger.error(f"Training error: {e}", exc_info=True)
257
+ self.is_training = False
258
+ yield f"❌ خطا در آموزش: {str(e)}", None
259
+ finally:
260
  self.is_training = False
 
 
 
261
 
262
+ def _calculate_training_stats(self) -> str:
263
+ """Calculate and format training statistics"""
264
+ if not self.training_history:
265
+ return "آمار آموزش در دسترس نیست"
266
+
267
+ rewards = [h['reward'] for h in self.training_history]
268
+ net_worths = [h['net_worth'] for h in self.training_history]
269
+
270
+ return (f"✅ آموزش تکمیل شد!\n\n"
271
+ f"📊 آمار نهایی:\n"
272
+ f"• اپیزودها: {len(rewards)}\n"
273
+ f"• میانگین پاداش: {np.mean(rewards):.2f}\n"
274
+ f"• پاداش نهایی: {rewards[-1]:.2f}\n"
275
+ f"• ارزش نهایی: ${net_worths[-1]:.2f}\n"
276
+ f"🚀 آماده معامله Real-Time!")
 
 
 
 
 
 
 
 
 
 
 
277
 
278
+ def _create_training_chart(self):
279
+ """Create training progress chart"""
280
+ try:
281
+ if not self.training_history:
282
+ return None
283
+
284
+ import plotly.graph_objects as go
285
+ from plotly.subplots import make_subplots
286
+
287
+ episodes = [h['episode'] for h in self.training_history]
288
+ rewards = [h['reward'] for h in self.training_history]
289
+ net_worths = [h['net_worth'] for h in self.training_history]
290
+
291
+ fig = make_subplots(rows=2, cols=1, subplot_titles=['پاداش اپیزود', 'ا��زش پرتفولیو'])
292
+
293
+ fig.add_trace(go.Scatter(x=episodes, y=rewards, mode='lines+markers',
294
+ name='پاداش', line=dict(color='blue')), row=1, col=1)
295
+ fig.add_trace(go.Scatter(x=episodes, y=net_worths, mode='lines+markers',
296
+ name='پرتفولیو', line=dict(color='green')), row=2, col=1)
297
+
298
+ fig.update_layout(height=400, title="📈 پیشرفت آموزش", template="plotly_white")
299
+ return fig
300
+
301
+ except:
302
+ return None
303
+
304
+ def start_live_trading(self) -> Tuple[str, Any, Any, Any]:
305
+ """Start live trading with safety checks"""
306
+ try:
307
+ with self.lock:
308
+ if not self.training_complete and CUSTOM_MODULES_AVAILABLE:
309
+ return "⚠️ لطفاً ابتدا آموزش را کامل کنید", None, None, None
310
+ if self.live_trading:
311
+ return "⚠️ معاملات در حال اجراست", None, None, None
312
 
313
+ self.live_trading = True
314
+ self._reset_data()
315
+ self._initialize_demo_data()
316
 
317
+ # Start trading thread
318
+ self.trading_thread = threading.Thread(target=self._trading_loop, daemon=True)
319
+ self.trading_thread.start()
 
 
 
 
320
 
321
+ time.sleep(0.5) # Allow thread to initialize
322
+ return self._get_live_status()
 
323
 
324
+ except Exception as e:
325
+ logger.error(f"Live trading start error: {e}")
326
+ return f"❌ خطا در شروع معاملات: {str(e)}", None, None, None
327
+
328
+ def _trading_loop(self):
329
+ """Safe trading loop with error handling"""
330
+ max_steps = 500
331
+ step = 0
332
+
333
+ while self.live_trading and step < max_steps:
334
+ try:
335
+ with self.lock:
336
+ if not self.initialized or self.env is None:
337
+ break
338
+
339
+ # Get action
340
+ action = self.agent.select_action(self.current_state)
341
+
342
+ # Execute step
343
+ next_state, reward, done, info = self.env.step(action)
344
+ self.current_state = next_state
345
+
346
+ # Generate demo data
347
+ self._generate_demo_step(action, reward, info)
348
 
349
+ step += 1
350
+ time.sleep(1) # 1 second intervals
 
351
 
352
  except Exception as e:
353
+ logger.error(f"Trading loop error: {e}")
354
+ time.sleep(2)
355
+ continue
356
 
357
  self.live_trading = False
358
 
359
+ def _generate_demo_step(self, action: int, reward: float, info: Dict):
360
+ """Generate realistic demo data"""
361
+ current_time = datetime.now()
362
+ last_price = self.live_data[-1]['price'] if self.live_data else 100.0
363
+
364
+ # Simulate price movement
365
+ base_change = np.random.normal(0, 0.5)
366
+ action_bias = {0: 0, 1: 0.3, 2: -0.3, 3: 0}[action]
367
+ new_price = max(50, last_price + base_change + action_bias)
368
+
369
+ # Update net worth
370
+ net_worth = info.get('net_worth', self.env.initial_balance + reward * 10)
371
+
372
+ self.live_data.append({
373
+ 'timestamp': current_time,
374
+ 'price': new_price,
375
+ 'action': action,
376
+ 'net_worth': net_worth,
377
+ 'reward': reward,
378
+ 'volume': np.random.randint(1000, 10000)
379
+ })
380
+
381
+ # Keep recent data only
382
+ if len(self.live_data) > 100:
383
+ self.live_data.pop(0)
384
+
385
+ self.action_history.append({
386
+ 'step': len(self.action_history),
387
+ 'action': action,
388
+ 'reward': reward,
389
+ 'price': new_price,
390
+ 'timestamp': current_time
391
+ })
 
 
 
 
 
 
 
 
 
 
 
392
 
393
+ def _initialize_demo_data(self):
394
+ """Initialize demo data"""
395
+ base_price = 100.0
396
+ for i in range(10):
397
+ self.live_data.append({
398
+ 'timestamp': datetime.now() - timedelta(seconds=10-i),
399
+ 'price': base_price + np.random.normal(0, 2),
400
+ 'action': 0,
401
+ 'net_worth': self.env.initial_balance if self.env else 10000,
402
+ 'reward': 0,
403
+ 'volume': np.random.randint(1000, 5000)
404
+ })
405
+
406
+ def _get_live_status(self) -> Tuple[str, Any, Any, pd.DataFrame]:
407
+ """Get current live trading status"""
408
+ try:
409
+ if not self.live_data:
410
+ return "📊 در حال آماده‌سازی...", None, None, self._create_empty_stats()
411
+
412
+ current = self.live_data[-1]
413
+ initial = self.env.initial_balance if self.env else 10000
414
+
415
+ profit = current['net_worth'] - initial
416
+ profit_pct = (profit / initial) * 100
417
+
418
+ action_names = ["نگهداری", "خرید", "فروش", "بستن"]
419
+ status = (f"🎯 معاملات Real-Time فعال\n"
420
+ f"💰 قیمت: ${current['price']:.2f}\n"
421
+ f"🎪 اقدام: {action_names[current['action']]}\n"
422
+ f"💼 پرتفولیو: ${current['net_worth']:.2f}\n"
423
+ f"📈 P&L: ${profit:+.2f} ({profit_pct:+.2f}%)")
424
+
425
+ live_fig = self._create_live_chart()
426
+ perf_fig = self._create_performance_chart()
427
+ stats_df = self._create_stats_table()
428
+
429
+ return status, live_fig, perf_fig, stats_df
430
+
431
+ except Exception as e:
432
+ logger.error(f"Status update error: {e}")
433
+ return "❌ خطا در به‌روزرسانی", None, None, self._create_empty_stats()
434
+
435
+ def get_live_update(self) -> Tuple[str, Any, Any, pd.DataFrame]:
436
+ """Manual live update trigger"""
437
+ return self._get_live_status()
438
+
439
+ def stop_live_trading(self) -> Tuple[str, Any, Any, pd.DataFrame]:
440
+ """Stop live trading safely"""
441
+ try:
442
+ with self.lock:
443
+ self.live_trading = False
444
+ if self.trading_thread and self.trading_thread.is_alive():
445
+ self.trading_thread.join(timeout=2.0)
446
+
447
+ if self.live_data:
448
+ final = self.live_data[-1]
449
+ initial = self.env.initial_balance if self.env else 10000
450
+ profit = final['net_worth'] - initial
451
+ profit_pct = (profit / initial) * 100
452
+
453
+ actions = [h['action'] for h in self.action_history]
454
+ action_counts = {i: actions.count(i) for i in range(4)}
455
+
456
+ status = (f"🛑 معاملات متوقف شد\n\n"
457
+ f"📊 نتایج نهایی:\n"
458
+ f"• سرمایه نهایی: ${final['net_worth']:.2f}\n"
459
+ f"• سود/زیان: ${profit:+.2f} ({profit_pct:+.2f}%)\n"
460
+ f"• کل اقدامات: {len(actions)}\n"
461
+ f"• خرید: {action_counts[1]} | فروش: {action_counts[2]}")
462
+ else:
463
+ status = "معاملات متوقف شد - داده‌ای ثبت نشده"
464
+
465
+ return status, self._create_live_chart(), self._create_performance_chart(), self._create_stats_table()
466
+
467
+ except Exception as e:
468
+ logger.error(f"Stop trading error: {e}")
469
+ return f"❌ خطا در توقف: {str(e)}", None, None, self._create_empty_stats()
470
 
471
  def _create_live_chart(self):
472
+ """Create live price chart"""
473
+ try:
474
+ if not self.live_data:
475
+ import plotly.graph_objects as go
476
+ fig = go.Figure()
477
+ fig.update_layout(title="در حال آماده‌سازی...", height=400)
478
+ return fig
479
+
480
+ import plotly.graph_objects as go
481
+ from plotly.subplots import make_subplots
482
+
483
+ data = self.live_data[-50:] # Last 50 points
484
+ times = [d['timestamp'] for d in data]
485
+ prices = [d['price'] for d in data]
486
+ volumes = [d['volume'] for d in data]
487
+
488
+ fig = make_subplots(rows=2, cols=1, row_heights=[0.7, 0.3],
489
+ subplot_titles=['قیمت', 'حجم'])
490
+
491
+ fig.add_trace(go.Scatter(x=times, y=prices, mode='lines', name='قیمت',
492
+ line=dict(color='cyan', width=2)), row=1, col=1)
493
+
494
+ # Action markers
495
+ for action, color, name in [(1, 'green', 'خرید'), (2, 'red', 'فروش')]:
496
+ action_times = [d['timestamp'] for d in data if d['action'] == action]
497
+ action_prices = [d['price'] for d in data if d['action'] == action]
498
+ if action_times:
499
+ fig.add_trace(go.Scatter(x=action_times, y=action_prices, mode='markers',
500
+ marker=dict(color=color, size=10),
501
+ name=name), row=1, col=1)
502
+
503
+ fig.add_trace(go.Bar(x=times, y=volumes, name='حجم', marker_color='blue',
504
+ opacity=0.6), row=2, col=1)
505
+
506
+ fig.update_layout(height=450, template="plotly_dark", showlegend=True)
507
  return fig
508
+
509
+ except:
510
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
 
512
  def _create_performance_chart(self):
513
+ """Create performance chart"""
514
+ try:
515
+ if not self.live_data:
516
+ import plotly.graph_objects as go
517
+ fig = go.Figure()
518
+ fig.update_layout(title="در حال آماده‌سازی...", height=300)
519
+ return fig
520
+
521
+ import plotly.graph_objects as go
522
+ times = [d['timestamp'] for d in self.live_data]
523
+ net_worths = [d['net_worth'] for d in self.live_data]
524
+
525
  fig = go.Figure()
526
+ fig.add_trace(go.Scatter(x=times, y=net_worths, mode='lines', name='پرتفولیو',
527
+ line=dict(color='green', width=3)))
528
+
529
+ initial = self.env.initial_balance if self.env else 10000
530
+ fig.add_hline(y=initial, line_dash="dash", line_color="red",
531
+ annotation_text=f"سرمایه اولیه: ${initial:.2f}")
532
+
533
+ fig.update_layout(height=350, title="عملکرد پرتفولیو", template="plotly_dark")
534
  return fig
535
+
536
+ except:
537
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
+ def _create_stats_table(self) -> pd.DataFrame:
540
+ """Create statistics table"""
541
+ try:
542
+ if not self.live_data:
543
+ return self._create_empty_stats()
544
+
545
+ current = self.live_data[-1]
546
+ initial = self.env.initial_balance if self.env else 10000
547
+ profit = current['net_worth'] - initial
548
+ profit_pct = (profit / initial) * 100
549
+
550
+ stats = {
551
+ 'متریک': ['💰 قیمت فعلی', '💼 پرتفولیو', '📈 P&L', '🎯 اقدام اخیر', '⏰ گام‌ها'],
552
+ 'مقدار': [
553
+ f"${current['price']:.2f}",
554
+ f"${current['net_worth']:.2f}",
555
+ f"${profit:+.2f} ({profit_pct:+.2f}%)",
556
+ {0: 'نگهداری', 1: 'خرید', 2: 'فروش', 3: 'بستن'}[current['action']],
557
+ str(len(self.action_history))
558
+ ]
559
+ }
560
+ return pd.DataFrame(stats)
561
+
562
+ except:
563
+ return self._create_empty_stats()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
 
565
+ def _create_empty_stats(self) -> pd.DataFrame:
566
+ """Create empty stats table"""
567
+ return pd.DataFrame({
568
+ 'متریک': ['وضعیت'],
569
+ 'مقدار': ['در حال آماده‌سازی...']
570
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
 
 
572
  def create_interface():
573
+ """Create Gradio interface with proper error handling"""
574
+ demo = SafeTradingDemo()
575
+
576
+ with gr.Blocks(theme=gr.themes.Soft(), title="🤖 AI Trading Demo") as interface:
577
+ gr.Markdown("# 🚀 هوش مصنوعی معامله‌گر هوشمند\n**آموزش و معاملات Real-Time**")
 
 
578
 
579
  with gr.Row():
580
  with gr.Column(scale=1):
581
+ gr.Markdown("## ⚙️ تنظیمات")
582
+ balance = gr.Slider(1000, 50000, value=10000, step=1000, label="سرمایه اولیه ($)")
583
+ risk = gr.Radio(["Low", "Medium", "High"], value="Medium", label="سطح ریسک")
584
+ asset = gr.Radio(["Crypto", "Stock", "Forex"], value="Crypto", label="نوع دارایی")
585
+ init_btn = gr.Button("🚀 راه‌اندازی", variant="primary")
586
+ init_status = gr.Textbox(label="وضعیت", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
 
588
  with gr.Column(scale=2):
589
+ status = gr.Textbox(label="وضعیت کلی", interactive=False, lines=4)
 
 
 
 
 
 
590
 
 
 
 
591
  with gr.Row():
592
  with gr.Column(scale=1):
593
+ gr.Markdown("## 🎓 آموزش")
594
+ episodes = gr.Slider(10, 100, value=20, step=5, label="اپیزودها")
595
+ train_btn = gr.Button("🤖 شروع آموزش", variant="primary")
 
 
 
 
 
 
 
596
 
597
  with gr.Column(scale=2):
598
+ train_plot = gr.Plot(label="پیشرفت آموزش")
 
 
599
 
 
 
 
600
  with gr.Row():
601
  with gr.Column(scale=1):
602
+ gr.Markdown("## 🎯 معاملات زنده")
603
+ start_btn = gr.Button("▶️ شروع معاملات", variant="secondary")
604
+ update_btn = gr.Button("🔄 به‌روزرسانی", variant="secondary")
605
+ stop_btn = gr.Button("⏹️ توقف", variant="stop")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
606
 
607
+ with gr.Column(scale=3):
608
+ live_chart = gr.Plot(label="نمودار زنده")
 
 
609
 
610
  with gr.Row():
611
+ perf_chart = gr.Plot(label="عملکرد")
612
+ stats_table = gr.DataFrame(label="آمار", headers=["متریک", "مقدار"])
 
 
 
 
 
 
 
 
613
 
614
  # Event handlers
615
  init_btn.click(
616
  demo.initialize_environment,
617
+ inputs=[balance, risk, asset],
618
  outputs=[init_status]
619
  )
620
 
621
  train_btn.click(
622
  demo.train_agent,
623
+ inputs=[episodes],
624
+ outputs=[status, train_plot]
625
  )
626
 
627
  start_btn.click(
628
  demo.start_live_trading,
629
+ outputs=[status, live_chart, perf_chart, stats_table]
 
630
  )
631
 
632
  update_btn.click(
633
+ demo.get_live_update,
634
+ outputs=[status, live_chart, perf_chart, stats_table]
 
635
  )
636
 
637
  stop_btn.click(
638
  demo.stop_live_trading,
639
+ outputs=[status, live_chart, perf_chart, stats_table]
 
640
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
641
 
642
+ return interface, demo
643
 
 
644
  if __name__ == "__main__":
645
+ logger.info("Starting AI Trading Demo...")
646
+ interface, demo = create_interface()
647
+
648
+ try:
649
+ interface.launch(
650
+ server_name="0.0.0.0",
651
+ server_port=7860,
652
+ share=False,
653
+ show_error=True,
654
+ quiet=False
655
+ )
656
+ except Exception as e:
657
+ logger.error(f"Failed to launch interface: {e}")
658
+ print(f"خطا در راه‌اندازی: {e}")