import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
import time
class SimpleTradingBot:
def __init__(self, symbol, timeframe, volume = 0.1):
self.symbol = symbol
self.timeframe = timeframe
self.volume = volume
self.magic = 234000
if not mt5.initialize():
raise Exception("MT5 initialization failed")
def get_data(self, bars = 100):
"""Get historical data"""
rates = mt5.copy_rates_from_pos(self.symbol, self.timeframe, 0, bars)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit = 's')
return df
def calculate_signals(self, df):
"""Calculate trading signals"""
# Simple SMA crossover
df['sma_fast'] = df['close'].rolling(window = 20).mean()
df['sma_slow'] = df['close'].rolling(window = 50).mean()
# Generate signal
if df['sma_fast'].iloc[-1] > df['sma_slow'].iloc[-1]:
return 'BUY'
elif df['sma_fast'].iloc[-1] < df['sma_slow'].iloc[-1]:
return 'SELL'
return 'NEUTRAL'
def get_open_position(self):
"""Check if we have an open position"""
positions = mt5.positions_get(symbol = self.symbol, magic = self.magic)
if positions and len(positions) > 0:
return positions[0]
return None
def open_position(self, order_type):
"""Open a new position"""
point = mt5.symbol_info(self.symbol).point
if order_type == 'BUY':
price = mt5.symbol_info_tick(self.symbol).ask
sl = price - 50 * point * 10
tp = price + 100 * point * 10
trade_type = mt5.ORDER_TYPE_BUY
else: # SELL
price = mt5.symbol_info_tick(self.symbol).bid
sl = price + 50 * point * 10
tp = price - 100 * point * 10
trade_type = mt5.ORDER_TYPE_SELL
request = {
"action": mt5.TRADE_ACTION_DEAL,
"symbol": self.symbol,
"volume": self.volume,
"type": trade_type,
"price": price,
"sl": sl,
"tp": tp,
"deviation": 10,
"magic": self.magic,
"comment": "Bot trade",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
if result.retcode == mt5.TRADE_RETCODE_DONE:
print(f"{order_type} order opened at {price:.5f}")
return True
else:
print(f"Order failed: {result.comment}")
return False
def close_position(self, position):
"""Close existing position"""
if position.type == mt5.ORDER_TYPE_BUY:
order_type = mt5.ORDER_TYPE_SELL
price = mt5.symbol_info_tick(self.symbol).bid
else:
order_type = mt5.ORDER_TYPE_BUY
price = mt5.symbol_info_tick(self.symbol).ask
request = {
"action": mt5.TRADE_ACTION_DEAL,
"position": position.ticket,
"symbol": self.symbol,
"volume": position.volume,
"type": order_type,
"price": price,
"deviation": 10,
"magic": self.magic,
"comment": "Bot close",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
if result.retcode == mt5.TRADE_RETCODE_DONE:
print(f"Position closed. Profit: ${position.profit:.2f}")
return True
return False
def run(self, check_interval = 60):
"""Main bot loop"""
print(f"Bot started for {self.symbol}")
while True:
try:
# Get data and calculate signals
df = self.get_data()
signal = self.calculate_signals(df)
# Check current position
position = self.get_open_position()
print(f"\n{datetime.now()} - Signal: {signal}")
if position:
print(f"Current position: {position.type}, Profit: ${position.profit:.2f}")
# Close if signal changed
if (position.type == mt5.ORDER_TYPE_BUY and signal == 'SELL') or \
(position.type == mt5.ORDER_TYPE_SELL and signal == 'BUY'):
self.close_position(position)
else:
# Open new position if signal present
if signal in ['BUY', 'SELL']:
self.open_position(signal)
# Wait before next check
time.sleep(check_interval)
except KeyboardInterrupt:
print("\nBot stopped by user")
break
except Exception as e:
print(f"Error: {e}")
time.sleep(check_interval)
mt5.shutdown()
# Run the bot
bot = SimpleTradingBot("EURUSD", mt5.TIMEFRAME_M15, volume = 0.1)
bot.run(check_interval = 60) # Check every 60 seconds