VisualTradingAI / app.py
OmidSakaki's picture
Update app.py
db2e29b verified
raw
history blame
28.3 kB
import gradio as gr
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
import io
import base64
from PIL import Image
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import time
import sys
import os
# Set matplotlib backend to avoid display issues
plt.switch_backend('Agg')
# Create necessary directories
os.makedirs('src/environments', exist_ok=True)
os.makedirs('src/agents', exist_ok=True)
os.makedirs('src/visualizers', exist_ok=True)
os.makedirs('src/utils', exist_ok=True)
# Create __init__.py files
for dir_path in ['src', 'src/environments', 'src/agents', 'src/visualizers', 'src/utils']:
init_file = os.path.join(dir_path, '__init__.py')
with open(init_file, 'w') as f:
f.write('')
# Now import our custom modules
sys.path.append('src')
# Import our custom modules
from src.environments.visual_trading_env import VisualTradingEnvironment
from src.agents.visual_agent import VisualTradingAgent
from src.visualizers.chart_renderer import ChartRenderer
class TradingAIDemo:
def __init__(self):
self.env = None
self.agent = None
self.current_state = None
self.is_training = False
self.episode_history = []
self.chart_renderer = ChartRenderer()
self.initialized = False
def initialize_environment(self, initial_balance, risk_level, asset_type):
"""Initialize trading environment"""
try:
print(f"Initializing environment with balance: {initial_balance}, risk: {risk_level}, asset: {asset_type}")
self.env = VisualTradingEnvironment(
initial_balance=float(initial_balance),
risk_level=risk_level,
asset_type=asset_type
)
# Initialize agent with correct dimensions
self.agent = VisualTradingAgent(
state_dim=(84, 84, 4),
action_dim=4
)
self.current_state = self.env.reset()
self.episode_history = []
self.initialized = True
return "✅ Environment initialized successfully! Ready for trading."
except Exception as e:
error_msg = f"❌ Error initializing environment: {str(e)}"
print(error_msg)
return error_msg
def run_single_step(self, action_choice):
"""Run a single step in the environment"""
if not self.initialized or self.env is None or self.agent is None:
return None, None, None, "⚠️ Please initialize environment first!"
try:
# Use selected action or let agent decide
if action_choice == "AI Decision":
action = self.agent.select_action(self.current_state)
action_source = "AI"
else:
action_mapping = {"Hold": 0, "Buy": 1, "Sell": 2, "Close": 3}
action = action_mapping[action_choice]
action_source = "Manual"
print(f"Executing action: {action} ({action_source})")
# Execute action
next_state, reward, done, info = self.env.step(action)
self.current_state = next_state
# Update history
history_entry = {
'step': len(self.episode_history),
'action': action,
'reward': reward,
'net_worth': info['net_worth'],
'balance': info['balance'],
'position': info['position_size'],
'price': info['current_price'],
'action_source': action_source
}
self.episode_history.append(history_entry)
# Create visualizations
price_chart = self.create_price_chart(info)
performance_chart = self.create_performance_chart()
action_chart = self.create_action_chart()
# Create status message
action_names = ["Hold", "Buy", "Sell", "Close"]
status = (
f"✅ Step {info['step']} Completed!\n"
f"• Action: {action_names[action]} ({action_source})\n"
f"• Reward: {reward:.3f}\n"
f"• Net Worth: ${info['net_worth']:.2f}\n"
f"• Balance: ${info['balance']:.2f}\n"
f"• Position: {info['position_size']:.4f}\n"
f"• Current Price: ${info['current_price']:.2f}"
)
if done:
status += "\n🎯 Episode Completed!"
return price_chart, performance_chart, action_chart, status
except Exception as e:
error_msg = f"❌ Error during step execution: {str(e)}"
print(error_msg)
return None, None, None, error_msg
def run_episode(self, num_steps=20):
"""Run a complete episode"""
if not self.initialized or self.env is None or self.agent is None:
return None, None, None, "⚠️ Please initialize environment first!"
try:
# Reset environment for new episode
self.current_state = self.env.reset()
self.episode_history = []
total_reward = 0
print(f"Starting episode with {num_steps} steps...")
for step in range(num_steps):
action = self.agent.select_action(self.current_state)
next_state, reward, done, info = self.env.step(action)
self.current_state = next_state
total_reward += reward
# Store experience for training
self.agent.store_transition(self.current_state, action, reward, next_state, done)
self.episode_history.append({
'step': step,
'action': action,
'reward': reward,
'net_worth': info['net_worth'],
'price': info['current_price'],
'action_source': 'AI'
})
# Small delay to make execution visible
time.sleep(0.05)
if done:
break
# Create visualizations
price_chart = self.create_price_chart(info)
performance_chart = self.create_performance_chart()
action_chart = self.create_action_chart()
# Calculate performance metrics
initial_balance = self.env.initial_balance
final_net_worth = info['net_worth']
total_return = 0.0
if initial_balance > 0:
total_return = (final_net_worth - initial_balance) / initial_balance * 100
summary = (
f"🎯 Episode Completed!\n"
f"• Total Steps: {len(self.episode_history)}\n"
f"• Total Reward: {total_reward:.2f}\n"
f"• Final Net Worth: ${final_net_worth:.2f}\n"
f"• Total Return: {total_return:.2f}%\n"
f"• Total Trades: {info['total_trades']}"
)
return price_chart, performance_chart, action_chart, summary
except Exception as e:
error_msg = f"❌ Error during episode: {str(e)}"
print(error_msg)
return None, None, None, error_msg
def train_agent(self, num_episodes, learning_rate):
"""Train the AI agent"""
if not self.initialized or self.env is None:
yield None, "⚠️ Please initialize environment first!"
return
self.is_training = True
training_history = []
try:
num_episodes = int(num_episodes)
for episode in range(num_episodes):
state = self.env.reset()
episode_reward = 0.0
done = False
steps = 0
while not done and steps < 100:
action = self.agent.select_action(state)
next_state, reward, done, info = self.env.step(action)
self.agent.store_transition(state, action, reward, next_state, done)
state = next_state
episode_reward += reward
steps += 1
# Update agent
loss = self.agent.update()
training_history.append({
'episode': episode,
'reward': episode_reward,
'net_worth': info['net_worth'],
'loss': loss,
'steps': steps
})
# Yield progress every 5 episodes or at the end
if episode % 5 == 0 or episode == num_episodes - 1:
progress_chart = self.create_training_progress(training_history)
status = (
f"🔄 Training Progress: {episode+1}/{num_episodes}\n"
f"• Episode Reward: {episode_reward:.2f}\n"
f"• Final Net Worth: ${info['net_worth']:.2f}\n"
f"• Loss: {loss:.4f}\n"
f"• Epsilon: {self.agent.epsilon:.3f}"
)
yield progress_chart, status
time.sleep(0.01)
self.is_training = False
# Calculate average reward
rewards = [h['reward'] for h in training_history]
avg_reward = np.mean(rewards) if rewards else 0.0
final_status = (
f"✅ Training Completed!\n"
f"• Total Episodes: {num_episodes}\n"
f"• Final Epsilon: {self.agent.epsilon:.3f}\n"
f"• Average Reward: {avg_reward:.2f}"
)
yield self.create_training_progress(training_history), final_status
except Exception as e:
self.is_training = False
error_msg = f"❌ Training error: {str(e)}"
print(f"Training error details: {e}")
yield None, error_msg
def create_price_chart(self, info):
"""Create price chart with actions"""
if not self.episode_history:
# Return empty chart with message
fig = go.Figure()
fig.update_layout(
title="Price Chart - No Data Available",
xaxis_title="Time Step",
yaxis_title="Price",
height=300,
template="plotly_white"
)
return fig
prices = [h['price'] for h in self.episode_history]
actions = [h['action'] for h in self.episode_history]
fig = go.Figure()
# Price line
fig.add_trace(go.Scatter(
x=list(range(len(prices))),
y=prices,
mode='lines',
name='Price',
line=dict(color='blue', width=3)
))
# Action markers
buy_indices = [i for i, action in enumerate(actions) if action == 1]
sell_indices = [i for i, action in enumerate(actions) if action == 2]
close_indices = [i for i, action in enumerate(actions) if action == 3]
if buy_indices:
fig.add_trace(go.Scatter(
x=buy_indices,
y=[prices[i] for i in buy_indices],
mode='markers',
name='Buy',
marker=dict(color='green', size=12, symbol='triangle-up',
line=dict(width=2, color='darkgreen'))
))
if sell_indices:
fig.add_trace(go.Scatter(
x=sell_indices,
y=[prices[i] for i in sell_indices],
mode='markers',
name='Sell',
marker=dict(color='red', size=12, symbol='triangle-down',
line=dict(width=2, color='darkred'))
))
if close_indices:
fig.add_trace(go.Scatter(
x=close_indices,
y=[prices[i] for i in close_indices],
mode='markers',
name='Close',
marker=dict(color='orange', size=10, symbol='x',
line=dict(width=2, color='darkorange'))
))
fig.update_layout(
title="Price Chart with Trading Actions",
xaxis_title="Step",
yaxis_title="Price",
height=350,
showlegend=True,
template="plotly_white"
)
return fig
def create_performance_chart(self):
"""Create portfolio performance chart"""
if not self.episode_history:
fig = go.Figure()
fig.update_layout(
title="Portfolio Performance - No Data Available",
height=400
)
return fig
net_worth = [h['net_worth'] for h in self.episode_history]
rewards = [h['reward'] for h in self.episode_history]
fig = make_subplots(
rows=2, cols=1,
subplot_titles=['Portfolio Value Over Time', 'Step Rewards'],
vertical_spacing=0.15
)
# Portfolio value
fig.add_trace(go.Scatter(
x=list(range(len(net_worth))),
y=net_worth,
mode='lines+markers',
name='Net Worth',
line=dict(color='green', width=3),
marker=dict(size=4)
), row=1, col=1)
# Add initial balance reference line
if self.env:
fig.add_hline(y=self.env.initial_balance, line_dash="dash",
line_color="red", annotation_text="Initial Balance",
row=1, col=1)
# Rewards as bar chart
if rewards:
fig.add_trace(go.Bar(
x=list(range(len(rewards))),
y=rewards,
name='Reward',
marker_color=['green' if r >= 0 else 'red' for r in rewards],
opacity=0.7
), row=2, col=1)
fig.update_layout(height=500, showlegend=False, template="plotly_white")
fig.update_yaxes(title_text="Value ($)", row=1, col=1)
fig.update_yaxes(title_text="Reward", row=2, col=1)
fig.update_xaxes(title_text="Step", row=2, col=1)
return fig
def create_action_chart(self):
"""Create action distribution chart"""
if not self.episode_history:
fig = go.Figure()
fig.update_layout(
title="Action Distribution - No Data Available",
height=300
)
return fig
actions = [h['action'] for h in self.episode_history]
action_names = ['Hold', 'Buy', 'Sell', 'Close']
action_counts = [actions.count(i) for i in range(4)]
colors = ['blue', 'green', 'red', 'orange']
fig = go.Figure(data=[go.Pie(
labels=action_names,
values=action_counts,
hole=.4,
marker_colors=colors,
textinfo='label+percent+value',
hoverinfo='label+percent+value'
)])
fig.update_layout(
title="Action Distribution",
height=350,
annotations=[dict(text='Actions', x=0.5, y=0.5, font_size=16, showarrow=False)],
template="plotly_white"
)
return fig
def create_training_progress(self, training_history):
"""Create training progress visualization"""
if not training_history:
fig = go.Figure()
fig.update_layout(
title="Training Progress - No Data Available",
height=500
)
return fig
episodes = [h['episode'] for h in training_history]
rewards = [h['reward'] for h in training_history]
net_worths = [h['net_worth'] for h in training_history]
losses = [h.get('loss', 0) for h in training_history]
fig = make_subplots(
rows=2, cols=2,
subplot_titles=['Episode Rewards', 'Portfolio Value',
'Training Loss', 'Moving Average Reward (5)'],
specs=[[{}, {}], [{}, {}]]
)
# Rewards
fig.add_trace(go.Scatter(
x=episodes, y=rewards, mode='lines+markers',
name='Reward', line=dict(color='blue', width=2),
marker=dict(size=4)
), row=1, col=1)
# Portfolio value
fig.add_trace(go.Scatter(
x=episodes, y=net_worths, mode='lines+markers',
name='Net Worth', line=dict(color='green', width=2),
marker=dict(size=4)
), row=1, col=2)
# Loss
if any(loss > 0 for loss in losses):
fig.add_trace(go.Scatter(
x=episodes, y=losses, mode='lines+markers',
name='Loss', line=dict(color='red', width=2),
marker=dict(size=4)
), row=2, col=1)
# Moving average reward
if len(rewards) > 5:
ma_rewards = []
for i in range(len(rewards)):
start_idx = max(0, i - 4)
ma = np.mean(rewards[start_idx:i+1])
ma_rewards.append(ma)
fig.add_trace(go.Scatter(
x=episodes, y=ma_rewards, mode='lines',
name='MA Reward (5)', line=dict(color='orange', width=3, dash='dash')
), row=2, col=2)
fig.update_layout(
height=600,
showlegend=True,
title_text="Training Progress Over Episodes",
template="plotly_white"
)
return fig
# Initialize the demo
demo = TradingAIDemo()
# Create Gradio interface
def create_interface():
with gr.Blocks(theme=gr.themes.Soft(), title="Visual Trading AI") as interface:
gr.Markdown("""
# 🚀 Visual Trading AI
**هوش مصنوعی معامله‌گر بصری - تحلیل چارت‌های قیمت با یادگیری تقویتی عمیق**
*این پروژه از شبکه‌های عصبی کانولوشن برای تحلیل بصری نمودارهای قیمت و یادگیری تقویتی برای تصمیم‌گیری معاملاتی استفاده می‌کند.*
""")
with gr.Row():
with gr.Column(scale=1):
# Configuration section
gr.Markdown("## ⚙️ پیکربندی محیط")
with gr.Row():
initial_balance = gr.Slider(
minimum=1000, maximum=50000, value=10000, step=1000,
label="موجودی اولیه ($)", info="میزان سرمایه اولیه برای معامله"
)
with gr.Row():
risk_level = gr.Radio(
["Low", "Medium", "High"],
value="Medium",
label="سطح ریسک",
info="سطح ریسک پذیری در معاملات"
)
with gr.Row():
asset_type = gr.Radio(
["Stock", "Crypto", "Forex"],
value="Stock",
label="نوع دارایی",
info="نوع بازار مالی برای شبیه‌سازی"
)
with gr.Row():
init_btn = gr.Button(
"🚀 راه‌اندازی محیط معاملاتی",
variant="primary",
size="lg"
)
with gr.Row():
init_status = gr.Textbox(
label="وضعیت راه‌اندازی",
interactive=False,
placeholder="برای شروع، محیط را راه‌اندازی کنید...",
lines=2
)
with gr.Column(scale=2):
# Status output
gr.Markdown("## 📊 وضعیت معاملات")
status_output = gr.Textbox(
label="وضعیت اجرا",
interactive=False,
placeholder="وضعیت معاملات اینجا نمایش داده می‌شود...",
lines=4
)
with gr.Row():
gr.Markdown("## 🎮 کنترل معاملات")
with gr.Row():
# Action controls
action_choice = gr.Radio(
["AI Decision", "Buy", "Sell", "Hold", "Close"],
value="AI Decision",
label="انتخاب اقدام",
info="AI Decision: تصمیم خودکار هوش مصنوعی"
)
with gr.Row():
with gr.Column(scale=1):
step_btn = gr.Button(
"▶️ اجرای یک قدم",
variant="secondary",
size="lg"
)
with gr.Column(scale=1):
episode_btn = gr.Button(
"🎯 اجرای یک اپیزود (20 قدم)",
variant="secondary",
size="lg"
)
with gr.Row():
# Visualization outputs
with gr.Column(scale=1):
price_chart = gr.Plot(
label="📈 نمودار قیمت و اقدامات"
)
with gr.Column(scale=1):
performance_chart = gr.Plot(
label="💰 عملکرد پرتفولیو"
)
with gr.Row():
with gr.Column(scale=1):
action_chart = gr.Plot(
label="🎯 توزیع اقدامات"
)
with gr.Row():
gr.Markdown("## 🎓 آموزش هوش مصنوعی")
with gr.Row():
with gr.Column(scale=1):
num_episodes = gr.Slider(
minimum=10, maximum=200, value=50, step=10,
label="تعداد اپیزودهای آموزش",
info="تعداد دوره‌های آموزشی"
)
learning_rate = gr.Slider(
minimum=0.0001, maximum=0.01, value=0.001, step=0.0001,
label="نرخ یادگیری",
info="سرعت یادگیری الگوریتم"
)
train_btn = gr.Button(
"🤖 شروع آموزش",
variant="primary",
size="lg"
)
with gr.Column(scale=2):
training_plot = gr.Plot(
label="📊 پیشرفت آموزش"
)
training_status = gr.Textbox(
label="وضعیت آموزش",
interactive=False,
placeholder="وضعیت آموزش اینجا نمایش داده می‌شود...",
lines=3
)
with gr.Row():
gr.Markdown("## ℹ️ راهنمای استفاده")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("""
**🎯 اقدامات ممکن:**
- **Hold (0)**: حفظ وضعیت فعلی
- **Buy (1)**: باز کردن پوزیشن خرید
- **Sell (2)**: افزایش سایز پوزیشن
- **Close (3)**: بستن پوزیشن فعلی
**📈 معیارهای عملکرد:**
- **Reward**: امتیاز دریافتی از محیط
- **Net Worth**: ارزش کل پرتفولیو
- **Balance**: موجودی نقدی
- **Position**: سایز پوزیشن فعلی
""")
with gr.Column(scale=1):
gr.Markdown("""
**🔧 نحوه استفاده:**
1. محیط را راه‌اندازی کنید
2. اقدامات تکی یا اپیزودها را اجرا کنید
3. عملکرد را در نمودارها مشاهده کنید
4. هوش مصنوعی را آموزش دهید
5. نتایج را تحلیل کنید
**⚠️ توجه:**
این یک شبیه‌ساز آموزشی است و برای معاملات واقعی طراحی نشده است.
""")
# Event handlers
init_btn.click(
demo.initialize_environment,
inputs=[initial_balance, risk_level, asset_type],
outputs=[init_status]
)
step_btn.click(
demo.run_single_step,
inputs=[action_choice],
outputs=[price_chart, performance_chart, action_chart, status_output]
)
episode_btn.click(
demo.run_episode,
inputs=[],
outputs=[price_chart, performance_chart, action_chart, status_output]
)
train_btn.click(
demo.train_agent,
inputs=[num_episodes, learning_rate],
outputs=[training_plot, training_status]
)
gr.Markdown("""
## 🏗 معماری فنی
**🎯 هسته هوش مصنوعی:**
- **پردازش بصری**: شبکه عصبی کانولوشن (CNN) برای تحلیل نمودارهای قیمت
- **یادگیری تقویتی**: الگوریتم Deep Q-Network (DQN) برای تصمیم‌گیری
- **تجربه replay**: ذخیره و بازیابی تجربیات برای یادگیری پایدار
**🛠 فناوری‌ها:**
- **یادگیری عمیق**: PyTorch
- **محیط شبیه‌سازی**: محیط اختصاصی معاملاتی
- **رابط کاربری**: Gradio
- **ویژوالیزیشن**: Plotly, Matplotlib
- **پردازش داده**: NumPy, Pandas
**📊 ویژگی‌های کلیدی:**
- تحلیل بصری نمودارهای قیمت
- یادگیری خودکار استراتژی‌های معاملاتی
- نمایش زنده عملکرد و تصمیم‌ها
- کنترل دستی و خودکار
- آنالیز جامع عملکرد
*توسعه داده شده توسط Omid Sakaki - 2024*
""")
return interface
# Create and launch interface
if __name__ == "__main__":
print("🚀 Starting Visual Trading AI Application...")
print("📊 Initializing components...")
interface = create_interface()
print("✅ Application initialized successfully!")
print("🌐 Starting server on http://0.0.0.0:7860")
print("📱 You can now access the application in your browser")
# Launch with better configuration
interface.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True,
debug=True
)