Unosoftware commited on
Commit
d740391
Β·
verified Β·
1 Parent(s): 6c2d586

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +419 -0
app.py ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import MetaTrader5 as mt5
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ from smolagents import CodeAgent, HfApiModel, tool
6
+ import json
7
+ from typing import Dict, List, Optional
8
+
9
+ # Custom MetaTrader Tools
10
+ @tool
11
+ def connect_mt5(login: int, password: str, server: str) -> str:
12
+ """
13
+ Connect to MetaTrader 5 terminal
14
+
15
+ Args:
16
+ login: MT5 account login number
17
+ password: MT5 account password
18
+ server: MT5 server name
19
+
20
+ Returns:
21
+ Connection status message
22
+ """
23
+ try:
24
+ if not mt5.initialize():
25
+ return f"Failed to initialize MT5: {mt5.last_error()}"
26
+
27
+ if not mt5.login(login, password=password, server=server):
28
+ return f"Failed to connect to account {login}: {mt5.last_error()}"
29
+
30
+ return f"Successfully connected to MT5 account {login}"
31
+ except Exception as e:
32
+ return f"Error connecting to MT5: {str(e)}"
33
+
34
+ @tool
35
+ def get_account_info() -> str:
36
+ """
37
+ Get MetaTrader 5 account information
38
+
39
+ Returns:
40
+ Account information as formatted string
41
+ """
42
+ try:
43
+ account_info = mt5.account_info()
44
+ if account_info is None:
45
+ return "Failed to get account info. Please ensure you're connected to MT5."
46
+
47
+ info_dict = account_info._asdict()
48
+ formatted_info = "=== ACCOUNT INFORMATION ===\n"
49
+ formatted_info += f"Login: {info_dict['login']}\n"
50
+ formatted_info += f"Server: {info_dict['server']}\n"
51
+ formatted_info += f"Name: {info_dict['name']}\n"
52
+ formatted_info += f"Company: {info_dict['company']}\n"
53
+ formatted_info += f"Currency: {info_dict['currency']}\n"
54
+ formatted_info += f"Balance: {info_dict['balance']:.2f}\n"
55
+ formatted_info += f"Equity: {info_dict['equity']:.2f}\n"
56
+ formatted_info += f"Margin: {info_dict['margin']:.2f}\n"
57
+ formatted_info += f"Free Margin: {info_dict['margin_free']:.2f}\n"
58
+ formatted_info += f"Margin Level: {info_dict['margin_level']:.2f}%\n"
59
+ formatted_info += f"Profit: {info_dict['profit']:.2f}\n"
60
+
61
+ return formatted_info
62
+ except Exception as e:
63
+ return f"Error getting account info: {str(e)}"
64
+
65
+ @tool
66
+ def get_closed_trades(days_back: int = 30) -> str:
67
+ """
68
+ Get closed trades from MetaTrader 5
69
+
70
+ Args:
71
+ days_back: Number of days to look back for trades (default: 30)
72
+
73
+ Returns:
74
+ Formatted string of closed trades
75
+ """
76
+ try:
77
+ from datetime import datetime, timedelta
78
+
79
+ # Calculate date range
80
+ end_date = datetime.now()
81
+ start_date = end_date - timedelta(days=days_back)
82
+
83
+ # Get deals (closed trades)
84
+ deals = mt5.history_deals_get(start_date, end_date)
85
+
86
+ if deals is None or len(deals) == 0:
87
+ return f"No closed trades found in the last {days_back} days."
88
+
89
+ # Convert to DataFrame for easier handling
90
+ df = pd.DataFrame(list(deals), columns=deals[0]._asdict().keys())
91
+
92
+ # Filter only actual trades (exclude balance operations)
93
+ trade_deals = df[df['type'].isin([0, 1])] # 0=buy, 1=sell
94
+
95
+ if len(trade_deals) == 0:
96
+ return f"No trading deals found in the last {days_back} days."
97
+
98
+ formatted_trades = f"=== CLOSED TRADES (Last {days_back} days) ===\n"
99
+ formatted_trades += f"Total deals: {len(trade_deals)}\n\n"
100
+
101
+ for _, deal in trade_deals.iterrows():
102
+ deal_type = "BUY" if deal['type'] == 0 else "SELL"
103
+ deal_time = datetime.fromtimestamp(deal['time'])
104
+
105
+ formatted_trades += f"Ticket: {deal['ticket']}\n"
106
+ formatted_trades += f"Symbol: {deal['symbol']}\n"
107
+ formatted_trades += f"Type: {deal_type}\n"
108
+ formatted_trades += f"Volume: {deal['volume']:.2f}\n"
109
+ formatted_trades += f"Price: {deal['price']:.5f}\n"
110
+ formatted_trades += f"Profit: {deal['profit']:.2f}\n"
111
+ formatted_trades += f"Commission: {deal['commission']:.2f}\n"
112
+ formatted_trades += f"Swap: {deal['swap']:.2f}\n"
113
+ formatted_trades += f"Time: {deal_time}\n"
114
+ formatted_trades += f"Comment: {deal['comment']}\n"
115
+ formatted_trades += "-" * 40 + "\n"
116
+
117
+ return formatted_trades
118
+
119
+ except Exception as e:
120
+ return f"Error getting closed trades: {str(e)}"
121
+
122
+ @tool
123
+ def get_trade_statistics(days_back: int = 30) -> str:
124
+ """
125
+ Get trading statistics and analysis
126
+
127
+ Args:
128
+ days_back: Number of days to analyze (default: 30)
129
+
130
+ Returns:
131
+ Trading statistics as formatted string
132
+ """
133
+ try:
134
+ from datetime import datetime, timedelta
135
+
136
+ # Calculate date range
137
+ end_date = datetime.now()
138
+ start_date = end_date - timedelta(days=days_back)
139
+
140
+ # Get deals
141
+ deals = mt5.history_deals_get(start_date, end_date)
142
+
143
+ if deals is None or len(deals) == 0:
144
+ return f"No trades found for statistics in the last {days_back} days."
145
+
146
+ # Convert to DataFrame
147
+ df = pd.DataFrame(list(deals), columns=deals[0]._asdict().keys())
148
+ trade_deals = df[df['type'].isin([0, 1])]
149
+
150
+ if len(trade_deals) == 0:
151
+ return f"No trading deals found for statistics."
152
+
153
+ # Calculate statistics
154
+ total_trades = len(trade_deals)
155
+ total_profit = trade_deals['profit'].sum()
156
+ total_commission = trade_deals['commission'].sum()
157
+ total_swap = trade_deals['swap'].sum()
158
+ net_profit = total_profit + total_commission + total_swap
159
+
160
+ winning_trades = trade_deals[trade_deals['profit'] > 0]
161
+ losing_trades = trade_deals[trade_deals['profit'] < 0]
162
+
163
+ win_rate = (len(winning_trades) / total_trades * 100) if total_trades > 0 else 0
164
+ avg_win = winning_trades['profit'].mean() if len(winning_trades) > 0 else 0
165
+ avg_loss = losing_trades['profit'].mean() if len(losing_trades) > 0 else 0
166
+
167
+ stats = f"=== TRADING STATISTICS (Last {days_back} days) ===\n"
168
+ stats += f"Total Trades: {total_trades}\n"
169
+ stats += f"Winning Trades: {len(winning_trades)}\n"
170
+ stats += f"Losing Trades: {len(losing_trades)}\n"
171
+ stats += f"Win Rate: {win_rate:.1f}%\n"
172
+ stats += f"Average Win: {avg_win:.2f}\n"
173
+ stats += f"Average Loss: {avg_loss:.2f}\n"
174
+ stats += f"Total Profit: {total_profit:.2f}\n"
175
+ stats += f"Total Commission: {total_commission:.2f}\n"
176
+ stats += f"Total Swap: {total_swap:.2f}\n"
177
+ stats += f"Net Profit: {net_profit:.2f}\n"
178
+
179
+ # Most traded symbols
180
+ symbol_counts = trade_deals['symbol'].value_counts()
181
+ stats += f"\nMost Traded Symbols:\n"
182
+ for symbol, count in symbol_counts.head(5).items():
183
+ stats += f" {symbol}: {count} trades\n"
184
+
185
+ return stats
186
+
187
+ except Exception as e:
188
+ return f"Error calculating statistics: {str(e)}"
189
+
190
+ @tool
191
+ def disconnect_mt5() -> str:
192
+ """
193
+ Disconnect from MetaTrader 5
194
+
195
+ Returns:
196
+ Disconnection status message
197
+ """
198
+ try:
199
+ mt5.shutdown()
200
+ return "Successfully disconnected from MT5"
201
+ except Exception as e:
202
+ return f"Error disconnecting from MT5: {str(e)}"
203
+
204
+ # Initialize the agent with Hugging Face model
205
+ def create_agent():
206
+ """Create and return the SmolagentsAI agent with MT5 tools"""
207
+ try:
208
+ # Use a free model from Hugging Face
209
+ model = HfApiModel("microsoft/DialoGPT-medium")
210
+
211
+ # Create agent with MetaTrader tools
212
+ agent = CodeAgent(
213
+ tools=[
214
+ connect_mt5,
215
+ get_account_info,
216
+ get_closed_trades,
217
+ get_trade_statistics,
218
+ disconnect_mt5
219
+ ],
220
+ model=model,
221
+ max_steps=10
222
+ )
223
+
224
+ return agent
225
+ except Exception as e:
226
+ return None, f"Error creating agent: {str(e)}"
227
+
228
+ # Global variables
229
+ agent = None
230
+ is_connected = False
231
+
232
+ def initialize_agent():
233
+ """Initialize the agent"""
234
+ global agent
235
+ agent, error = create_agent()
236
+ if agent is None:
237
+ return f"Failed to initialize agent: {error}"
238
+ return "Agent initialized successfully!"
239
+
240
+ def connect_to_mt5(login, password, server):
241
+ """Connect to MT5 with credentials"""
242
+ global agent, is_connected
243
+
244
+ if agent is None:
245
+ return "Please initialize the agent first!"
246
+
247
+ try:
248
+ login_int = int(login)
249
+ result = agent.run(f"Connect to MT5 with login {login_int}, password {password}, and server {server}")
250
+
251
+ if "Successfully connected" in result:
252
+ is_connected = True
253
+ return result
254
+ else:
255
+ is_connected = False
256
+ return result
257
+
258
+ except ValueError:
259
+ return "Login must be a valid number"
260
+ except Exception as e:
261
+ return f"Error: {str(e)}"
262
+
263
+ def chat_with_agent(message, history):
264
+ """Main chat function for the agent"""
265
+ global agent, is_connected
266
+
267
+ if agent is None:
268
+ return history + [("Please initialize the agent first!", "")]
269
+
270
+ if not is_connected:
271
+ return history + [(message, "Please connect to MT5 first using your credentials in the connection tab.")]
272
+
273
+ try:
274
+ # Run the agent with the user's message
275
+ response = agent.run(message)
276
+ history.append((message, response))
277
+ return history
278
+ except Exception as e:
279
+ error_msg = f"Error processing request: {str(e)}"
280
+ history.append((message, error_msg))
281
+ return history
282
+
283
+ # Create Gradio interface
284
+ def create_gradio_interface():
285
+ """Create the Gradio interface"""
286
+
287
+ with gr.Blocks(title="MetaTrader 5 AI Agent", theme=gr.themes.Soft()) as demo:
288
+ gr.Markdown("# πŸ€– MetaTrader 5 AI Agent")
289
+ gr.Markdown("An intelligent agent that can access your MT5 account and provide trading information.")
290
+
291
+ with gr.Tabs():
292
+ # Setup Tab
293
+ with gr.TabItem("πŸ”§ Setup"):
294
+ gr.Markdown("### Initialize Agent")
295
+ init_btn = gr.Button("Initialize Agent", variant="primary")
296
+ init_output = gr.Textbox(label="Initialization Status", interactive=False)
297
+
298
+ init_btn.click(
299
+ initialize_agent,
300
+ outputs=init_output
301
+ )
302
+
303
+ gr.Markdown("### Connect to MetaTrader 5")
304
+ with gr.Row():
305
+ login_input = gr.Textbox(label="Login", placeholder="Your MT5 login number")
306
+ password_input = gr.Textbox(label="Password", type="password", placeholder="Your MT5 password")
307
+ server_input = gr.Textbox(label="Server", placeholder="Your MT5 server name")
308
+
309
+ connect_btn = gr.Button("Connect to MT5", variant="primary")
310
+ connection_output = gr.Textbox(label="Connection Status", interactive=False)
311
+
312
+ connect_btn.click(
313
+ connect_to_mt5,
314
+ inputs=[login_input, password_input, server_input],
315
+ outputs=connection_output
316
+ )
317
+
318
+ # Chat Tab
319
+ with gr.TabItem("πŸ’¬ Chat with Agent"):
320
+ gr.Markdown("### Ask the Agent About Your Trading Account")
321
+ gr.Markdown("""
322
+ **Example prompts you can try:**
323
+ - "Show me my account information"
324
+ - "Get my closed trades from the last 30 days"
325
+ - "What are my trading statistics?"
326
+ - "Show me trades from the last 7 days"
327
+ - "Calculate my win rate and profit"
328
+ """)
329
+
330
+ chatbot = gr.Chatbot(
331
+ label="MT5 Agent Chat",
332
+ height=400,
333
+ show_copy_button=True
334
+ )
335
+
336
+ msg = gr.Textbox(
337
+ label="Your Message",
338
+ placeholder="Ask about your account, trades, or statistics...",
339
+ lines=2
340
+ )
341
+
342
+ with gr.Row():
343
+ send_btn = gr.Button("Send", variant="primary")
344
+ clear_btn = gr.Button("Clear Chat")
345
+
346
+ # Event handlers
347
+ def send_message(message, history):
348
+ return chat_with_agent(message, history), ""
349
+
350
+ def clear_chat():
351
+ return []
352
+
353
+ send_btn.click(
354
+ send_message,
355
+ inputs=[msg, chatbot],
356
+ outputs=[chatbot, msg]
357
+ )
358
+
359
+ msg.submit(
360
+ send_message,
361
+ inputs=[msg, chatbot],
362
+ outputs=[chatbot, msg]
363
+ )
364
+
365
+ clear_btn.click(
366
+ clear_chat,
367
+ outputs=chatbot
368
+ )
369
+
370
+ # Help Tab
371
+ with gr.TabItem("❓ Help"):
372
+ gr.Markdown("""
373
+ ## How to Use This Application
374
+
375
+ ### 1. Setup
376
+ - First, click "Initialize Agent" in the Setup tab
377
+ - Enter your MT5 credentials (login, password, server)
378
+ - Click "Connect to MT5"
379
+
380
+ ### 2. Chat with Agent
381
+ - Go to the "Chat with Agent" tab
382
+ - Ask questions about your trading account
383
+ - The agent can provide account info, closed trades, and statistics
384
+
385
+ ### Sample Questions:
386
+ - "What's my account balance and equity?"
387
+ - "Show me all closed trades from last week"
388
+ - "Calculate my trading performance statistics"
389
+ - "What symbols do I trade most?"
390
+ - "What's my win rate?"
391
+
392
+ ### Requirements:
393
+ - MetaTrader 5 terminal must be installed and running
394
+ - Valid MT5 account credentials
395
+ - Internet connection for the AI model
396
+
397
+ ### Troubleshooting:
398
+ - Make sure MT5 terminal is running before connecting
399
+ - Check your credentials are correct
400
+ - Ensure your MT5 account allows API access
401
+ - Try reinitializing the agent if you encounter errors
402
+ """)
403
+
404
+ # Footer
405
+ gr.Markdown("---")
406
+ gr.Markdown("*Powered by SmolagentsAI and MetaTrader 5 API*")
407
+
408
+ return demo
409
+
410
+ # Launch the application
411
+ if __name__ == "__main__":
412
+ # Create and launch the Gradio interface
413
+ demo = create_gradio_interface()
414
+ demo.launch(
415
+ server_name="0.0.0.0",
416
+ server_port=7860,
417
+ share=True, # Creates a public link
418
+ debug=True
419
+ )