OmidSakaki commited on
Commit
769c366
·
verified ·
1 Parent(s): 1f5a715

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +392 -125
app.py CHANGED
@@ -37,7 +37,10 @@ with open('src/visualizers/__init__.py', 'w') as f:
37
  with open('src/utils/__init__.py', 'w') as f:
38
  f.write('')
39
 
40
- # Now import our modules
 
 
 
41
  from src.environments.visual_trading_env import VisualTradingEnvironment
42
  from src.agents.visual_agent import VisualTradingAgent
43
 
@@ -50,6 +53,16 @@ class ChartRenderer:
50
  """Render price chart with actions"""
51
  fig = go.Figure()
52
 
 
 
 
 
 
 
 
 
 
 
53
  # Add price line
54
  fig.add_trace(go.Scatter(
55
  x=list(range(len(prices))),
@@ -71,7 +84,7 @@ class ChartRenderer:
71
  y=[prices[i] for i in buy_indices],
72
  mode='markers',
73
  name='Buy',
74
- marker=dict(color='green', size=10, symbol='triangle-up')
75
  ))
76
 
77
  if sell_indices:
@@ -80,14 +93,24 @@ class ChartRenderer:
80
  y=[prices[i] for i in sell_indices],
81
  mode='markers',
82
  name='Sell',
83
- marker=dict(color='red', size=10, symbol='triangle-down')
 
 
 
 
 
 
 
 
 
84
  ))
85
 
86
  fig.update_layout(
87
  title=f"Price Chart (Step: {current_step})",
88
  xaxis_title="Time Step",
89
  yaxis_title="Price",
90
- height=300
 
91
  )
92
 
93
  return fig
@@ -103,9 +126,11 @@ class DataLoader:
103
 
104
  prices = [100.0]
105
  for i in range(1, num_points):
106
- # Random walk with trend
107
  change = np.random.normal(trend, volatility)
108
- price = max(0.1, prices[-1] * (1 + change))
 
 
109
  prices.append(price)
110
 
111
  return np.array(prices)
@@ -129,91 +154,131 @@ class TradingAIDemo:
129
  self.episode_history = []
130
  self.chart_renderer = ChartRenderer()
131
  self.data_loader = DataLoader()
 
132
 
133
  def initialize_environment(self, initial_balance, risk_level, asset_type):
134
  """Initialize trading environment"""
135
  try:
 
 
136
  self.env = VisualTradingEnvironment(
137
- initial_balance=initial_balance,
138
  risk_level=risk_level,
139
  asset_type=asset_type
140
  )
 
 
141
  self.agent = VisualTradingAgent(
142
- state_dim=(84, 84, 4),
143
  action_dim=4
144
  )
 
145
  self.current_state = self.env.reset()
146
  self.episode_history = []
147
- return "✅ Environment initialized successfully!"
 
 
 
148
  except Exception as e:
149
- return f"❌ Error initializing environment: {str(e)}"
 
 
150
 
151
  def run_single_step(self, action_choice):
152
  """Run a single step in the environment"""
153
- if self.env is None or self.agent is None:
154
- return None, None, "Please initialize environment first!"
155
 
156
  try:
157
  # Use selected action or let agent decide
158
  if action_choice == "AI Decision":
159
  action = self.agent.select_action(self.current_state)
 
160
  else:
161
  action_mapping = {"Hold": 0, "Buy": 1, "Sell": 2, "Close": 3}
162
  action = action_mapping[action_choice]
 
 
 
163
 
164
  # Execute action
165
  next_state, reward, done, info = self.env.step(action)
166
  self.current_state = next_state
167
 
168
  # Update history
169
- self.episode_history.append({
170
  'step': len(self.episode_history),
171
  'action': action,
172
  'reward': reward,
173
  'net_worth': info['net_worth'],
174
  'balance': info['balance'],
175
  'position': info['position_size'],
176
- 'price': info['current_price']
177
- })
 
 
178
 
179
  # Create visualizations
180
  price_chart = self.create_price_chart(info)
181
  performance_chart = self.create_performance_chart()
182
  action_chart = self.create_action_chart()
183
 
184
- status = f"Step {info['step']}: {['Hold', 'Buy', 'Sell', 'Close'][action]} | Reward: {reward:.3f} | Net Worth: ${info['net_worth']:.2f}"
 
 
 
 
 
 
 
 
 
 
 
185
  if done:
186
- status += " | Episode Completed!"
187
 
188
  return price_chart, performance_chart, action_chart, status
189
 
190
  except Exception as e:
191
- return None, None, None, f"❌ Error during step: {str(e)}"
 
 
192
 
193
- def run_episode(self, num_steps):
194
  """Run a complete episode"""
195
- if self.env is None or self.agent is None:
196
- return None, None, None, "Please initialize environment first!"
197
 
198
  try:
199
- self.env.reset()
 
200
  self.episode_history = []
201
  total_reward = 0
202
 
 
 
203
  for step in range(num_steps):
204
  action = self.agent.select_action(self.current_state)
205
  next_state, reward, done, info = self.env.step(action)
206
  self.current_state = next_state
207
  total_reward += reward
208
 
 
 
 
209
  self.episode_history.append({
210
  'step': step,
211
  'action': action,
212
  'reward': reward,
213
  'net_worth': info['net_worth'],
214
- 'price': info['current_price']
 
215
  })
216
 
 
 
 
217
  if done:
218
  break
219
 
@@ -222,30 +287,44 @@ class TradingAIDemo:
222
  performance_chart = self.create_performance_chart()
223
  action_chart = self.create_action_chart()
224
 
225
- summary = f"Episode completed! Total Reward: {total_reward:.2f} | Final Net Worth: ${info['net_worth']:.2f} | Steps: {len(self.episode_history)}"
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
  return price_chart, performance_chart, action_chart, summary
228
 
229
  except Exception as e:
230
- return None, None, None, f"❌ Error during episode: {str(e)}"
 
 
231
 
232
  def train_agent(self, num_episodes, learning_rate):
233
  """Train the AI agent"""
234
- if self.env is None:
235
- yield None, None, None, "Please initialize environment first!"
236
  return
237
 
238
  self.is_training = True
239
  training_history = []
240
 
241
  try:
242
- for episode in range(num_episodes):
243
  state = self.env.reset()
244
  episode_reward = 0
245
  done = False
246
  steps = 0
247
 
248
- while not done and steps < 200: # Limit steps per episode
249
  action = self.agent.select_action(state)
250
  next_state, reward, done, info = self.env.step(action)
251
  self.agent.store_transition(state, action, reward, next_state, done)
@@ -260,28 +339,52 @@ class TradingAIDemo:
260
  'episode': episode,
261
  'reward': episode_reward,
262
  'net_worth': info['net_worth'],
263
- 'loss': loss if loss else 0
 
264
  })
265
 
266
- # Yield progress every 10 episodes or at the end
267
- if episode % 10 == 0 or episode == num_episodes - 1:
268
  progress_chart = self.create_training_progress(training_history)
269
- yield progress_chart, f"Training... Episode {episode+1}/{num_episodes} (Reward: {episode_reward:.2f})"
 
 
 
 
 
 
 
270
 
271
  # Small delay to make training visible
272
  time.sleep(0.01)
273
 
274
  self.is_training = False
275
- yield self.create_training_progress(training_history), "✅ Training completed!"
 
 
 
 
 
 
276
 
277
  except Exception as e:
278
  self.is_training = False
279
- yield None, f"❌ Training error: {str(e)}"
 
 
280
 
281
  def create_price_chart(self, info):
282
  """Create price chart with actions"""
283
  if not self.episode_history:
284
- return go.Figure()
 
 
 
 
 
 
 
 
285
 
286
  prices = [h['price'] for h in self.episode_history]
287
  actions = [h['action'] for h in self.episode_history]
@@ -294,7 +397,7 @@ class TradingAIDemo:
294
  y=prices,
295
  mode='lines',
296
  name='Price',
297
- line=dict(color='blue', width=2)
298
  ))
299
 
300
  # Action markers
@@ -308,7 +411,8 @@ class TradingAIDemo:
308
  y=[prices[i] for i in buy_indices],
309
  mode='markers',
310
  name='Buy',
311
- marker=dict(color='green', size=12, symbol='triangle-up', line=dict(width=2, color='darkgreen'))
 
312
  ))
313
 
314
  if sell_indices:
@@ -317,7 +421,8 @@ class TradingAIDemo:
317
  y=[prices[i] for i in sell_indices],
318
  mode='markers',
319
  name='Sell',
320
- marker=dict(color='red', size=12, symbol='triangle-down', line=dict(width=2, color='darkred'))
 
321
  ))
322
 
323
  if close_indices:
@@ -326,15 +431,17 @@ class TradingAIDemo:
326
  y=[prices[i] for i in close_indices],
327
  mode='markers',
328
  name='Close',
329
- marker=dict(color='orange', size=10, symbol='x', line=dict(width=2, color='darkorange'))
 
330
  ))
331
 
332
  fig.update_layout(
333
  title="Price Chart with Trading Actions",
334
  xaxis_title="Step",
335
  yaxis_title="Price",
336
- height=300,
337
- showlegend=True
 
338
  )
339
 
340
  return fig
@@ -342,35 +449,48 @@ class TradingAIDemo:
342
  def create_performance_chart(self):
343
  """Create portfolio performance chart"""
344
  if not self.episode_history:
345
- return go.Figure()
 
 
 
 
 
346
 
347
  net_worth = [h['net_worth'] for h in self.episode_history]
348
  rewards = [h['reward'] for h in self.episode_history]
349
 
350
  fig = make_subplots(
351
  rows=2, cols=1,
352
- subplot_titles=['Portfolio Value', 'Step Rewards'],
353
- vertical_spacing=0.1
354
  )
355
 
356
  # Portfolio value
357
  fig.add_trace(go.Scatter(
358
  x=list(range(len(net_worth))),
359
  y=net_worth,
360
- mode='lines',
361
  name='Net Worth',
362
- line=dict(color='green', width=2)
 
363
  ), row=1, col=1)
364
 
365
- # Rewards
 
 
 
 
 
 
366
  fig.add_trace(go.Bar(
367
  x=list(range(len(rewards))),
368
  y=rewards,
369
  name='Reward',
370
- marker_color=['green' if r >= 0 else 'red' for r in rewards]
 
371
  ), row=2, col=1)
372
 
373
- fig.update_layout(height=400, showlegend=False)
374
  fig.update_yaxes(title_text="Value ($)", row=1, col=1)
375
  fig.update_yaxes(title_text="Reward", row=2, col=1)
376
  fig.update_xaxes(title_text="Step", row=2, col=1)
@@ -380,7 +500,12 @@ class TradingAIDemo:
380
  def create_action_chart(self):
381
  """Create action distribution chart"""
382
  if not self.episode_history:
383
- return go.Figure()
 
 
 
 
 
384
 
385
  actions = [h['action'] for h in self.episode_history]
386
  action_names = ['Hold', 'Buy', 'Sell', 'Close']
@@ -391,13 +516,16 @@ class TradingAIDemo:
391
  fig = go.Figure(data=[go.Pie(
392
  labels=action_names,
393
  values=action_counts,
394
- hole=.3,
395
- marker_colors=colors
 
 
396
  )])
397
 
398
  fig.update_layout(
399
  title="Action Distribution",
400
- height=300
 
401
  )
402
 
403
  return fig
@@ -405,45 +533,65 @@ class TradingAIDemo:
405
  def create_training_progress(self, training_history):
406
  """Create training progress visualization"""
407
  if not training_history:
408
- return go.Figure()
 
 
 
 
 
409
 
410
  df = pd.DataFrame(training_history)
411
 
412
  fig = make_subplots(
413
  rows=2, cols=2,
414
  subplot_titles=['Episode Rewards', 'Portfolio Value',
415
- 'Training Loss', 'Moving Average (10)'],
416
  specs=[[{}, {}], [{}, {}]]
417
  )
418
 
419
  # Rewards
420
  fig.add_trace(go.Scatter(
421
  x=df['episode'], y=df['reward'], mode='lines+markers',
422
- name='Reward', line=dict(color='blue')
 
423
  ), row=1, col=1)
424
 
425
  # Portfolio value
426
  fig.add_trace(go.Scatter(
427
  x=df['episode'], y=df['net_worth'], mode='lines+markers',
428
- name='Net Worth', line=dict(color='green')
 
429
  ), row=1, col=2)
430
 
 
 
 
 
 
 
431
  # Loss
432
- if 'loss' in df.columns and df['loss'].notna().any():
433
  fig.add_trace(go.Scatter(
434
  x=df['episode'], y=df['loss'], mode='lines+markers',
435
- name='Loss', line=dict(color='red')
 
436
  ), row=2, col=1)
437
 
438
  # Moving average reward
439
- if len(df) > 10:
440
- df['ma_reward'] = df['reward'].rolling(window=10).mean()
441
  fig.add_trace(go.Scatter(
442
  x=df['episode'], y=df['ma_reward'], mode='lines',
443
- name='MA Reward (10)', line=dict(color='orange', dash='dash')
444
  ), row=2, col=2)
445
 
446
- fig.update_layout(height=500, showlegend=True, title_text="Training Progress")
 
 
 
 
 
 
447
  return fig
448
 
449
  # Initialize the demo
@@ -454,79 +602,174 @@ def create_interface():
454
  with gr.Blocks(theme=gr.themes.Soft(), title="Visual Trading AI") as interface:
455
  gr.Markdown("""
456
  # 🚀 Visual Trading AI
457
- *Intelligent Trading Agent with Visual Market Analysis*
458
 
459
- This AI agent learns to trade by analyzing price charts visually using Deep Reinforcement Learning.
460
  """)
461
 
462
  with gr.Row():
463
  with gr.Column(scale=1):
464
  # Configuration section
465
- gr.Markdown("## ⚙️ Configuration")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
 
467
  with gr.Row():
468
- initial_balance = gr.Slider(1000, 50000, value=10000, step=1000,
469
- label="Initial Balance ($)")
 
 
 
 
470
 
471
  with gr.Row():
472
- risk_level = gr.Radio(["Low", "Medium", "High"], value="Medium",
473
- label="Risk Level")
474
- asset_type = gr.Radio(["Stock", "Crypto", "Forex"], value="Stock",
475
- label="Asset Type")
 
476
 
477
- init_btn = gr.Button("🚀 Initialize Environment", variant="primary", scale=1)
478
- init_status = gr.Textbox(label="Status", interactive=False, scale=1)
 
 
 
 
 
479
 
480
  with gr.Column(scale=2):
481
  # Status output
482
- status_output = gr.Textbox(label="Trading Status", interactive=False)
 
 
 
 
 
 
483
 
 
 
 
484
  with gr.Row():
485
  # Action controls
486
- action_choice = gr.Radio(["AI Decision", "Buy", "Sell", "Hold", "Close"],
487
- value="AI Decision", label="Action Selection")
 
 
 
 
488
 
 
489
  with gr.Column(scale=1):
490
- step_btn = gr.Button("▶️ Execute Single Step", variant="secondary")
491
- episode_btn = gr.Button("🎯 Run Episode (20 steps)", variant="secondary")
 
 
 
 
 
 
 
 
 
 
492
 
493
  with gr.Row():
494
  # Visualization outputs
495
- price_chart = gr.Plot(label="Price & Actions")
496
- performance_chart = gr.Plot(label="Portfolio Performance")
497
- action_chart = gr.Plot(label="Action Distribution")
 
 
 
 
 
 
498
 
499
  with gr.Row():
500
- # Training section
501
- gr.Markdown("## 🎓 AI Training")
 
 
 
 
 
502
 
503
- with gr.Column():
504
- num_episodes = gr.Slider(10, 500, value=50, step=10,
505
- label="Training Episodes")
506
- learning_rate = gr.Slider(0.0001, 0.01, value=0.001, step=0.0001,
507
- label="Learning Rate")
508
- train_btn = gr.Button("🤖 Start Training", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
509
 
510
- with gr.Column():
511
- training_plot = gr.Plot(label="Training Progress")
512
- training_status = gr.Textbox(label="Training Status")
 
 
 
 
 
 
 
 
513
 
514
  with gr.Row():
515
- # Information section
516
- gr.Markdown("## 📊 System Information")
517
- gr.Markdown("""
518
- **How it works:**
519
- - The AI analyzes price charts visually using a CNN
520
- - Reinforcement learning optimizes trading decisions
521
- - Real-time visualization shows agent behavior
522
- - Training improves performance over time
523
-
524
- **Action Types:**
525
- - 🟦 Hold: Maintain current position
526
- - 🟩 Buy: Open long position
527
- - 🟥 Sell: Increase position size
528
- - 🟧 Close: Close current position
529
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
530
 
531
  # Event handlers
532
  init_btn.click(
@@ -542,7 +785,8 @@ def create_interface():
542
  )
543
 
544
  episode_btn.click(
545
- lambda: demo.run_episode(20),
 
546
  outputs=[price_chart, performance_chart, action_chart, status_output]
547
  )
548
 
@@ -553,25 +797,48 @@ def create_interface():
553
  )
554
 
555
  gr.Markdown("""
556
- ## 🔧 Technical Details
557
-
558
- **Architecture:**
559
- - **Visual Processing**: CNN analyzes price charts as images
560
- - **Reinforcement Learning**: Deep Q-Network for decision making
561
- - **Real-time Visualization**: Plotly for interactive charts
562
-
563
- **Technology Stack:**
564
- - PyTorch for deep learning
565
- - Gymnasium for environment
566
- - Gradio for web interface
567
- - Plotly for visualization
568
-
569
- *Note: This is a demonstration with synthetic data. Not for real trading.*
 
 
 
 
 
 
 
 
570
  """)
571
 
572
  return interface
573
 
574
  # Create and launch interface
575
  if __name__ == "__main__":
 
 
 
576
  interface = create_interface()
577
- interface.launch(share=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  with open('src/utils/__init__.py', 'w') as f:
38
  f.write('')
39
 
40
+ # Now import our custom modules
41
+ sys.path.append('src')
42
+
43
+ # Import our custom modules
44
  from src.environments.visual_trading_env import VisualTradingEnvironment
45
  from src.agents.visual_agent import VisualTradingAgent
46
 
 
53
  """Render price chart with actions"""
54
  fig = go.Figure()
55
 
56
+ if not prices:
57
+ # Return empty figure if no data
58
+ fig.update_layout(
59
+ title="Price Chart - No Data",
60
+ xaxis_title="Time Step",
61
+ yaxis_title="Price",
62
+ height=300
63
+ )
64
+ return fig
65
+
66
  # Add price line
67
  fig.add_trace(go.Scatter(
68
  x=list(range(len(prices))),
 
84
  y=[prices[i] for i in buy_indices],
85
  mode='markers',
86
  name='Buy',
87
+ marker=dict(color='green', size=10, symbol='triangle-up', line=dict(width=2, color='darkgreen'))
88
  ))
89
 
90
  if sell_indices:
 
93
  y=[prices[i] for i in sell_indices],
94
  mode='markers',
95
  name='Sell',
96
+ marker=dict(color='red', size=10, symbol='triangle-down', line=dict(width=2, color='darkred'))
97
+ ))
98
+
99
+ if close_indices:
100
+ fig.add_trace(go.Scatter(
101
+ x=close_indices,
102
+ y=[prices[i] for i in close_indices],
103
+ mode='markers',
104
+ name='Close',
105
+ marker=dict(color='orange', size=8, symbol='x', line=dict(width=2, color='darkorange'))
106
  ))
107
 
108
  fig.update_layout(
109
  title=f"Price Chart (Step: {current_step})",
110
  xaxis_title="Time Step",
111
  yaxis_title="Price",
112
+ height=300,
113
+ showlegend=True
114
  )
115
 
116
  return fig
 
126
 
127
  prices = [100.0]
128
  for i in range(1, num_points):
129
+ # Random walk with trend and some mean reversion
130
  change = np.random.normal(trend, volatility)
131
+ # Add some mean reversion
132
+ mean_reversion = (100 - prices[-1]) * 0.001
133
+ price = max(1.0, prices[-1] * (1 + change) + mean_reversion)
134
  prices.append(price)
135
 
136
  return np.array(prices)
 
154
  self.episode_history = []
155
  self.chart_renderer = ChartRenderer()
156
  self.data_loader = DataLoader()
157
+ self.initialized = False
158
 
159
  def initialize_environment(self, initial_balance, risk_level, asset_type):
160
  """Initialize trading environment"""
161
  try:
162
+ print(f"Initializing environment with balance: {initial_balance}, risk: {risk_level}, asset: {asset_type}")
163
+
164
  self.env = VisualTradingEnvironment(
165
+ initial_balance=float(initial_balance),
166
  risk_level=risk_level,
167
  asset_type=asset_type
168
  )
169
+
170
+ # Initialize agent with correct dimensions
171
  self.agent = VisualTradingAgent(
172
+ state_dim=(84, 84, 4), # Fixed dimensions
173
  action_dim=4
174
  )
175
+
176
  self.current_state = self.env.reset()
177
  self.episode_history = []
178
+ self.initialized = True
179
+
180
+ return "✅ Environment initialized successfully! Ready for trading."
181
+
182
  except Exception as e:
183
+ error_msg = f"❌ Error initializing environment: {str(e)}"
184
+ print(error_msg)
185
+ return error_msg
186
 
187
  def run_single_step(self, action_choice):
188
  """Run a single step in the environment"""
189
+ if not self.initialized or self.env is None or self.agent is None:
190
+ return None, None, None, "⚠️ Please initialize environment first!"
191
 
192
  try:
193
  # Use selected action or let agent decide
194
  if action_choice == "AI Decision":
195
  action = self.agent.select_action(self.current_state)
196
+ action_source = "AI"
197
  else:
198
  action_mapping = {"Hold": 0, "Buy": 1, "Sell": 2, "Close": 3}
199
  action = action_mapping[action_choice]
200
+ action_source = "Manual"
201
+
202
+ print(f"Executing action: {action} ({action_source})")
203
 
204
  # Execute action
205
  next_state, reward, done, info = self.env.step(action)
206
  self.current_state = next_state
207
 
208
  # Update history
209
+ history_entry = {
210
  'step': len(self.episode_history),
211
  'action': action,
212
  'reward': reward,
213
  'net_worth': info['net_worth'],
214
  'balance': info['balance'],
215
  'position': info['position_size'],
216
+ 'price': info['current_price'],
217
+ 'action_source': action_source
218
+ }
219
+ self.episode_history.append(history_entry)
220
 
221
  # Create visualizations
222
  price_chart = self.create_price_chart(info)
223
  performance_chart = self.create_performance_chart()
224
  action_chart = self.create_action_chart()
225
 
226
+ # Create status message
227
+ action_names = ["Hold", "Buy", "Sell", "Close"]
228
+ status = (
229
+ f"✅ Step {info['step']} Completed!\n"
230
+ f"• Action: {action_names[action]} ({action_source})\n"
231
+ f"• Reward: {reward:.3f}\n"
232
+ f"• Net Worth: ${info['net_worth']:.2f}\n"
233
+ f"• Balance: ${info['balance']:.2f}\n"
234
+ f"• Position: {info['position_size']:.4f}\n"
235
+ f"• Current Price: ${info['current_price']:.2f}"
236
+ )
237
+
238
  if done:
239
+ status += "\n🎯 Episode Completed!"
240
 
241
  return price_chart, performance_chart, action_chart, status
242
 
243
  except Exception as e:
244
+ error_msg = f"❌ Error during step execution: {str(e)}"
245
+ print(error_msg)
246
+ return None, None, None, error_msg
247
 
248
+ def run_episode(self, num_steps=20):
249
  """Run a complete episode"""
250
+ if not self.initialized or self.env is None or self.agent is None:
251
+ return None, None, None, "⚠️ Please initialize environment first!"
252
 
253
  try:
254
+ # Reset environment for new episode
255
+ self.current_state = self.env.reset()
256
  self.episode_history = []
257
  total_reward = 0
258
 
259
+ print(f"Starting episode with {num_steps} steps...")
260
+
261
  for step in range(num_steps):
262
  action = self.agent.select_action(self.current_state)
263
  next_state, reward, done, info = self.env.step(action)
264
  self.current_state = next_state
265
  total_reward += reward
266
 
267
+ # Store experience for training
268
+ self.agent.store_transition(self.current_state, action, reward, next_state, done)
269
+
270
  self.episode_history.append({
271
  'step': step,
272
  'action': action,
273
  'reward': reward,
274
  'net_worth': info['net_worth'],
275
+ 'price': info['current_price'],
276
+ 'action_source': 'AI'
277
  })
278
 
279
+ # Small delay to make execution visible
280
+ time.sleep(0.05)
281
+
282
  if done:
283
  break
284
 
 
287
  performance_chart = self.create_performance_chart()
288
  action_chart = self.create_action_chart()
289
 
290
+ # Calculate performance metrics
291
+ initial_balance = self.env.initial_balance
292
+ final_net_worth = info['net_worth']
293
+ total_return = (final_net_worth - initial_balance) / initial_balance * 100
294
+
295
+ summary = (
296
+ f"🎯 Episode Completed!\n"
297
+ f"• Total Steps: {len(self.episode_history)}\n"
298
+ f"• Total Reward: {total_reward:.2f}\n"
299
+ f"• Final Net Worth: ${final_net_worth:.2f}\n"
300
+ f"• Total Return: {total_return:.2f}%\n"
301
+ f"• Total Trades: {info['total_trades']}"
302
+ )
303
 
304
  return price_chart, performance_chart, action_chart, summary
305
 
306
  except Exception as e:
307
+ error_msg = f"❌ Error during episode: {str(e)}"
308
+ print(error_msg)
309
+ return None, None, None, error_msg
310
 
311
  def train_agent(self, num_episodes, learning_rate):
312
  """Train the AI agent"""
313
+ if not self.initialized or self.env is None:
314
+ yield None, "⚠️ Please initialize environment first!"
315
  return
316
 
317
  self.is_training = True
318
  training_history = []
319
 
320
  try:
321
+ for episode in range(int(num_episodes)):
322
  state = self.env.reset()
323
  episode_reward = 0
324
  done = False
325
  steps = 0
326
 
327
+ while not done and steps < 100: # Limit steps per episode
328
  action = self.agent.select_action(state)
329
  next_state, reward, done, info = self.env.step(action)
330
  self.agent.store_transition(state, action, reward, next_state, done)
 
339
  'episode': episode,
340
  'reward': episode_reward,
341
  'net_worth': info['net_worth'],
342
+ 'loss': loss if loss else 0,
343
+ 'steps': steps
344
  })
345
 
346
+ # Yield progress every 5 episodes or at the end
347
+ if episode % 5 == 0 or episode == num_episodes - 1:
348
  progress_chart = self.create_training_progress(training_history)
349
+ status = (
350
+ f"🔄 Training Progress: {episode+1}/{num_episodes}\n"
351
+ f"• Episode Reward: {episode_reward:.2f}\n"
352
+ f"• Final Net Worth: ${info['net_worth']:.2f}\n"
353
+ f"• Loss: {loss:.4f if loss else 0:.4f}\n"
354
+ f"• Epsilon: {self.agent.epsilon:.3f}"
355
+ )
356
+ yield progress_chart, status
357
 
358
  # Small delay to make training visible
359
  time.sleep(0.01)
360
 
361
  self.is_training = False
362
+ final_status = (
363
+ f"✅ Training Completed!\n"
364
+ f"• Total Episodes: {num_episodes}\n"
365
+ f"• Final Epsilon: {self.agent.epsilon:.3f}\n"
366
+ f"• Average Reward: {np.mean([h['reward'] for h in training_history]):.2f}"
367
+ )
368
+ yield self.create_training_progress(training_history), final_status
369
 
370
  except Exception as e:
371
  self.is_training = False
372
+ error_msg = f"❌ Training error: {str(e)}"
373
+ print(error_msg)
374
+ yield None, error_msg
375
 
376
  def create_price_chart(self, info):
377
  """Create price chart with actions"""
378
  if not self.episode_history:
379
+ # Return empty chart with message
380
+ fig = go.Figure()
381
+ fig.update_layout(
382
+ title="Price Chart - No Data Available",
383
+ xaxis_title="Time Step",
384
+ yaxis_title="Price",
385
+ height=300
386
+ )
387
+ return fig
388
 
389
  prices = [h['price'] for h in self.episode_history]
390
  actions = [h['action'] for h in self.episode_history]
 
397
  y=prices,
398
  mode='lines',
399
  name='Price',
400
+ line=dict(color='blue', width=3)
401
  ))
402
 
403
  # Action markers
 
411
  y=[prices[i] for i in buy_indices],
412
  mode='markers',
413
  name='Buy',
414
+ marker=dict(color='green', size=12, symbol='triangle-up',
415
+ line=dict(width=2, color='darkgreen'))
416
  ))
417
 
418
  if sell_indices:
 
421
  y=[prices[i] for i in sell_indices],
422
  mode='markers',
423
  name='Sell',
424
+ marker=dict(color='red', size=12, symbol='triangle-down',
425
+ line=dict(width=2, color='darkred'))
426
  ))
427
 
428
  if close_indices:
 
431
  y=[prices[i] for i in close_indices],
432
  mode='markers',
433
  name='Close',
434
+ marker=dict(color='orange', size=10, symbol='x',
435
+ line=dict(width=2, color='darkorange'))
436
  ))
437
 
438
  fig.update_layout(
439
  title="Price Chart with Trading Actions",
440
  xaxis_title="Step",
441
  yaxis_title="Price",
442
+ height=350,
443
+ showlegend=True,
444
+ template="plotly_white"
445
  )
446
 
447
  return fig
 
449
  def create_performance_chart(self):
450
  """Create portfolio performance chart"""
451
  if not self.episode_history:
452
+ fig = go.Figure()
453
+ fig.update_layout(
454
+ title="Portfolio Performance - No Data Available",
455
+ height=400
456
+ )
457
+ return fig
458
 
459
  net_worth = [h['net_worth'] for h in self.episode_history]
460
  rewards = [h['reward'] for h in self.episode_history]
461
 
462
  fig = make_subplots(
463
  rows=2, cols=1,
464
+ subplot_titles=['Portfolio Value Over Time', 'Step Rewards'],
465
+ vertical_spacing=0.15
466
  )
467
 
468
  # Portfolio value
469
  fig.add_trace(go.Scatter(
470
  x=list(range(len(net_worth))),
471
  y=net_worth,
472
+ mode='lines+markers',
473
  name='Net Worth',
474
+ line=dict(color='green', width=3),
475
+ marker=dict(size=4)
476
  ), row=1, col=1)
477
 
478
+ # Add initial balance reference line
479
+ if self.env:
480
+ fig.add_hline(y=self.env.initial_balance, line_dash="dash",
481
+ line_color="red", annotation_text="Initial Balance",
482
+ row=1, col=1)
483
+
484
+ # Rewards as bar chart
485
  fig.add_trace(go.Bar(
486
  x=list(range(len(rewards))),
487
  y=rewards,
488
  name='Reward',
489
+ marker_color=['green' if r >= 0 else 'red' for r in rewards],
490
+ opacity=0.7
491
  ), row=2, col=1)
492
 
493
+ fig.update_layout(height=500, showlegend=False, template="plotly_white")
494
  fig.update_yaxes(title_text="Value ($)", row=1, col=1)
495
  fig.update_yaxes(title_text="Reward", row=2, col=1)
496
  fig.update_xaxes(title_text="Step", row=2, col=1)
 
500
  def create_action_chart(self):
501
  """Create action distribution chart"""
502
  if not self.episode_history:
503
+ fig = go.Figure()
504
+ fig.update_layout(
505
+ title="Action Distribution - No Data Available",
506
+ height=300
507
+ )
508
+ return fig
509
 
510
  actions = [h['action'] for h in self.episode_history]
511
  action_names = ['Hold', 'Buy', 'Sell', 'Close']
 
516
  fig = go.Figure(data=[go.Pie(
517
  labels=action_names,
518
  values=action_counts,
519
+ hole=.4,
520
+ marker_colors=colors,
521
+ textinfo='label+percent+value',
522
+ hoverinfo='label+percent+value'
523
  )])
524
 
525
  fig.update_layout(
526
  title="Action Distribution",
527
+ height=350,
528
+ annotations=[dict(text='Actions', x=0.5, y=0.5, font_size=16, showarrow=False)]
529
  )
530
 
531
  return fig
 
533
  def create_training_progress(self, training_history):
534
  """Create training progress visualization"""
535
  if not training_history:
536
+ fig = go.Figure()
537
+ fig.update_layout(
538
+ title="Training Progress - No Data Available",
539
+ height=500
540
+ )
541
+ return fig
542
 
543
  df = pd.DataFrame(training_history)
544
 
545
  fig = make_subplots(
546
  rows=2, cols=2,
547
  subplot_titles=['Episode Rewards', 'Portfolio Value',
548
+ 'Training Loss', 'Moving Average Reward (5)'],
549
  specs=[[{}, {}], [{}, {}]]
550
  )
551
 
552
  # Rewards
553
  fig.add_trace(go.Scatter(
554
  x=df['episode'], y=df['reward'], mode='lines+markers',
555
+ name='Reward', line=dict(color='blue', width=2),
556
+ marker=dict(size=4)
557
  ), row=1, col=1)
558
 
559
  # Portfolio value
560
  fig.add_trace(go.Scatter(
561
  x=df['episode'], y=df['net_worth'], mode='lines+markers',
562
+ name='Net Worth', line=dict(color='green', width=2),
563
+ marker=dict(size=4)
564
  ), row=1, col=2)
565
 
566
+ # Add initial balance reference
567
+ if self.env:
568
+ fig.add_hline(y=self.env.initial_balance, line_dash="dash",
569
+ line_color="red", annotation_text="Initial Balance",
570
+ row=1, col=2)
571
+
572
  # Loss
573
+ if 'loss' in df.columns and df['loss'].notna().any() and df['loss'].sum() > 0:
574
  fig.add_trace(go.Scatter(
575
  x=df['episode'], y=df['loss'], mode='lines+markers',
576
+ name='Loss', line=dict(color='red', width=2),
577
+ marker=dict(size=4)
578
  ), row=2, col=1)
579
 
580
  # Moving average reward
581
+ if len(df) > 5:
582
+ df['ma_reward'] = df['reward'].rolling(window=5).mean()
583
  fig.add_trace(go.Scatter(
584
  x=df['episode'], y=df['ma_reward'], mode='lines',
585
+ name='MA Reward (5)', line=dict(color='orange', width=3, dash='dash')
586
  ), row=2, col=2)
587
 
588
+ fig.update_layout(
589
+ height=600,
590
+ showlegend=True,
591
+ title_text="Training Progress Over Episodes",
592
+ template="plotly_white"
593
+ )
594
+
595
  return fig
596
 
597
  # Initialize the demo
 
602
  with gr.Blocks(theme=gr.themes.Soft(), title="Visual Trading AI") as interface:
603
  gr.Markdown("""
604
  # 🚀 Visual Trading AI
605
+ **هوش مصنوعی معامله‌گر بصری - تحلیل چارت‌های قیمت با یادگیری تقویتی عمیق**
606
 
607
+ *این پروژه از شبکه‌های عصبی کانولوشن برای تحلیل بصری نمودارهای قیمت و یادگیری تقویتی برای تصمیم‌گیری معاملاتی استفاده می‌کند.*
608
  """)
609
 
610
  with gr.Row():
611
  with gr.Column(scale=1):
612
  # Configuration section
613
+ gr.Markdown("## ⚙️ پیکربندی محیط")
614
+
615
+ with gr.Row():
616
+ initial_balance = gr.Slider(
617
+ minimum=1000, maximum=50000, value=10000, step=1000,
618
+ label="موجودی اولیه ($)", info="میزان سرمایه اولیه برای معامله"
619
+ )
620
+
621
+ with gr.Row():
622
+ risk_level = gr.Radio(
623
+ ["Low", "Medium", "High"],
624
+ value="Medium",
625
+ label="سطح ریسک",
626
+ info="سطح ریسک پذیری در معاملات"
627
+ )
628
 
629
  with gr.Row():
630
+ asset_type = gr.Radio(
631
+ ["Stock", "Crypto", "Forex"],
632
+ value="Stock",
633
+ label="نوع دارایی",
634
+ info="نوع بازار مالی برای شبیه‌سازی"
635
+ )
636
 
637
  with gr.Row():
638
+ init_btn = gr.Button(
639
+ "🚀 راه‌اندازی محیط معاملاتی",
640
+ variant="primary",
641
+ size="lg"
642
+ )
643
 
644
+ with gr.Row():
645
+ init_status = gr.Textbox(
646
+ label="وضعیت راه‌اندازی",
647
+ interactive=False,
648
+ placeholder="برای شروع، محیط را راه‌اندازی کنید...",
649
+ lines=2
650
+ )
651
 
652
  with gr.Column(scale=2):
653
  # Status output
654
+ gr.Markdown("## 📊 وضعیت معاملات")
655
+ status_output = gr.Textbox(
656
+ label="وضعیت اجرا",
657
+ interactive=False,
658
+ placeholder="وضعیت معاملات اینجا نمایش داده می‌شود...",
659
+ lines=4
660
+ )
661
 
662
+ with gr.Row():
663
+ gr.Markdown("## 🎮 کنترل معاملات")
664
+
665
  with gr.Row():
666
  # Action controls
667
+ action_choice = gr.Radio(
668
+ ["AI Decision", "Buy", "Sell", "Hold", "Close"],
669
+ value="AI Decision",
670
+ label="انتخاب اقدام",
671
+ info="AI Decision: تصمیم خودکار هوش مصنوعی"
672
+ )
673
 
674
+ with gr.Row():
675
  with gr.Column(scale=1):
676
+ step_btn = gr.Button(
677
+ "▶️ اجرای یک قدم",
678
+ variant="secondary",
679
+ size="lg"
680
+ )
681
+
682
+ with gr.Column(scale=1):
683
+ episode_btn = gr.Button(
684
+ "🎯 اجرای یک اپیزود (20 قدم)",
685
+ variant="secondary",
686
+ size="lg"
687
+ )
688
 
689
  with gr.Row():
690
  # Visualization outputs
691
+ with gr.Column(scale=1):
692
+ price_chart = gr.Plot(
693
+ label="📈 نمودار قیمت و اقدامات"
694
+ )
695
+
696
+ with gr.Column(scale=1):
697
+ performance_chart = gr.Plot(
698
+ label="💰 عملکرد پرتفولیو"
699
+ )
700
 
701
  with gr.Row():
702
+ with gr.Column(scale=1):
703
+ action_chart = gr.Plot(
704
+ label="🎯 توزیع اقدامات"
705
+ )
706
+
707
+ with gr.Row():
708
+ gr.Markdown("## 🎓 آموزش هوش مصنوعی")
709
 
710
+ with gr.Row():
711
+ with gr.Column(scale=1):
712
+ num_episodes = gr.Slider(
713
+ minimum=10, maximum=200, value=50, step=10,
714
+ label="تعداد اپیزودهای آموزش",
715
+ info="تعداد دوره‌های آموزشی"
716
+ )
717
+
718
+ learning_rate = gr.Slider(
719
+ minimum=0.0001, maximum=0.01, value=0.001, step=0.0001,
720
+ label="نرخ یادگیری",
721
+ info="سرعت یادگیری الگوریتم"
722
+ )
723
+
724
+ train_btn = gr.Button(
725
+ "🤖 شروع آموزش",
726
+ variant="primary",
727
+ size="lg"
728
+ )
729
 
730
+ with gr.Column(scale=2):
731
+ training_plot = gr.Plot(
732
+ label="📊 پیشرفت آموزش"
733
+ )
734
+
735
+ training_status = gr.Textbox(
736
+ label="وضعیت آموزش",
737
+ interactive=False,
738
+ placeholder="وضعیت آموزش اینجا نمایش داده می‌شود...",
739
+ lines=3
740
+ )
741
 
742
  with gr.Row():
743
+ gr.Markdown("## ℹ️ راهنمای استفاده")
744
+
745
+ with gr.Row():
746
+ with gr.Column(scale=1):
747
+ gr.Markdown("""
748
+ **🎯 اقدامات ممکن:**
749
+ - **Hold (0)**: حفظ وضعیت فعلی
750
+ - **Buy (1)**: باز کردن پوزیشن خرید
751
+ - **Sell (2)**: افزایش سایز پوزیشن
752
+ - **Close (3)**: بستن پوزیشن فعلی
753
+
754
+ **📈 معیارهای عملکرد:**
755
+ - **Reward**: امتیاز دریافتی از محیط
756
+ - **Net Worth**: ارزش کل پرتفولیو
757
+ - **Balance**: موجودی نقدی
758
+ - **Position**: سایز پوزیشن فعلی
759
+ """)
760
+
761
+ with gr.Column(scale=1):
762
+ gr.Markdown("""
763
+ **🔧 نحوه استفاده:**
764
+ 1. محیط را راه‌اندازی کنید
765
+ 2. اقدامات تکی یا اپیزودها را اجرا کنید
766
+ 3. عملکرد را در نمودارها مشاهده کنید
767
+ 4. هوش مصنوعی را آموزش دهید
768
+ 5. نتایج را تحلیل کنید
769
+
770
+ **⚠️ توجه:**
771
+ این یک شبیه‌ساز آموزشی است و برای معاملات واقعی طراحی نشده است.
772
+ """)
773
 
774
  # Event handlers
775
  init_btn.click(
 
785
  )
786
 
787
  episode_btn.click(
788
+ demo.run_episode,
789
+ inputs=[],
790
  outputs=[price_chart, performance_chart, action_chart, status_output]
791
  )
792
 
 
797
  )
798
 
799
  gr.Markdown("""
800
+ ## 🏗 معماری فنی
801
+
802
+ **🎯 هسته هوش مصنوعی:**
803
+ - **پردازش بصری**: شبکه عصبی کانولوشن (CNN) برای تحلیل نمودارهای قیمت
804
+ - **یادگیری تقویتی**: الگوریتم Deep Q-Network (DQN) برای تصمیم‌گیری
805
+ - **تجربه replay**: ذخیره و بازیابی تجربیات برای یادگیری پایدار
806
+
807
+ **🛠 فناوری‌ها:**
808
+ - **یادگیری عمیق**: PyTorch
809
+ - **محیط شبیه‌سازی**: محیط اختصاصی معاملاتی
810
+ - **رابط کاربری**: Gradio
811
+ - **ویژوالیزیشن**: Plotly, Matplotlib
812
+ - **پردازش داده**: NumPy, Pandas
813
+
814
+ **📊 ویژگی‌های کلیدی:**
815
+ - تحلیل بصری نمودارهای قیمت
816
+ - یادگیری خودکار استراتژی‌های معاملاتی
817
+ - نمایش زنده عملکرد و تصمیم‌ها
818
+ - کنترل دستی و خودکار
819
+ - آنالیز جامع عملکرد
820
+
821
+ *توسعه داده شده توسط Omid Sakaki - 2024*
822
  """)
823
 
824
  return interface
825
 
826
  # Create and launch interface
827
  if __name__ == "__main__":
828
+ print("🚀 Starting Visual Trading AI Application...")
829
+ print("📊 Initializing components...")
830
+
831
  interface = create_interface()
832
+
833
+ print("✅ Application initialized successfully!")
834
+ print("🌐 Starting server on http://0.0.0.0:7860")
835
+ print("📱 You can now access the application in your browser")
836
+
837
+ # Launch with better configuration
838
+ interface.launch(
839
+ server_name="0.0.0.0",
840
+ server_port=7860,
841
+ share=False,
842
+ show_error=True,
843
+ debug=True
844
+ )