├── README.md ├── ftmo5setup (1).exe └── pyTrader.py /README.md: -------------------------------------------------------------------------------- 1 | # Trading Strategy: RSI and SMA Combined Strategy 2 | 3 | ## Description 4 | 5 | This repository contains a trading strategy implementation that combines the Relative Strength Index (RSI) and the Simple Moving Average (SMA) indicators. The strategy generates buy and sell signals based on the RSI and SMA values to determine potential entry and exit points in a financial market. 6 | 7 | The code is designed to work with MetaTrader 5 (MT5) data and trading platform. It includes functions to calculate RSI, SMA, and a main function to check for trading signals based on the combined RSI and SMA strategy. 8 | 9 | ## Features 10 | 11 | - Calculates RSI and SMA indicators for a given symbol and timeframe. 12 | - Generates buy and sell signals based on the RSI and SMA conditions. 13 | - Provides flexibility to adjust RSI and SMA parameters to fit your trading strategy. 14 | 15 | 16 | ![76aab6c3e6fb92b6a7754fac5f8dc5fd](https://github.com/ic3IT/Python-Trading-Bot-MT5/assets/138330122/a9be95b4-80bf-4ef2-b986-9166d4a6e93f) 17 | -------------------------------------------------------------------------------- /ftmo5setup (1).exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ic88t/Python-Trading-Bot-MT5/54a3c9a42947ef9142f710d60b2f982f02b1e99b/ftmo5setup (1).exe -------------------------------------------------------------------------------- /pyTrader.py: -------------------------------------------------------------------------------- 1 | import MetaTrader5 as mt5 2 | import pandas as pd 3 | from datetime import datetime 4 | import time 5 | 6 | class GoldTrader: 7 | def __init__(self): 8 | mt5.initialize() 9 | self.SYMBOL = "XAUUSD" 10 | self.TIMEFRAME = mt5.TIMEFRAME_M5 11 | self.EMA_PERIOD = 12 12 | self.TP_PERCENT = 0.0045 # 0.45% 13 | self.SL_PERCENT = 0.002 # 0.2% 14 | self.MAGIC = 100 15 | self.Comment = 'GoldEMA5M' 16 | self.initial_balance = 2000 17 | self.risk_percentage = 0.01 # 1% risk per trade 18 | self.min_account_size = 100000 # $100,000 base for minimum lot size 19 | 20 | def calculate_position_size(self, entry_price, stop_loss_price): 21 | account_info = mt5.account_info() 22 | if account_info is None: 23 | print("Failed to get account info") 24 | return 0.01 25 | 26 | equity = account_info.equity 27 | risk_amount = equity * self.risk_percentage 28 | 29 | symbol_info = mt5.symbol_info(self.SYMBOL) 30 | contract_size = symbol_info.trade_contract_size 31 | pip_value = contract_size * 0.01 # 1 pip is 0.01 for XAUUSD 32 | 33 | pips_risked = abs(entry_price - stop_loss_price) / symbol_info.point 34 | 35 | position_size = risk_amount / (pips_risked * pip_value) 36 | 37 | # Calculate minimum lot size based on 1% of $100,000 38 | min_lot_size = (self.min_account_size * self.risk_percentage) / (pips_risked * pip_value) 39 | 40 | # Use the larger of the calculated position size and the minimum lot size 41 | position_size = max(position_size, min_lot_size) 42 | 43 | position_size = round(position_size, 2) 44 | 45 | min_volume = symbol_info.volume_min 46 | max_volume = symbol_info.volume_max 47 | position_size = max(min(position_size, max_volume), min_volume) 48 | 49 | return position_size 50 | 51 | def get_ema(self): 52 | rates = mt5.copy_rates_from_pos(self.SYMBOL, self.TIMEFRAME, 0, self.EMA_PERIOD + 1) 53 | df = pd.DataFrame(rates) 54 | df['ema'] = df['close'].ewm(span=self.EMA_PERIOD, adjust=False).mean() 55 | return df['ema'].iloc[-1], df['close'].iloc[-1] 56 | 57 | def check_signal(self): 58 | ema, current_close = self.get_ema() 59 | 60 | if current_close > ema: 61 | print("Bullish") 62 | return 1 # Buy signal 63 | elif current_close < ema: 64 | print("Bearish") 65 | return -1 # Sell signal 66 | else: 67 | return 0 # No signal 68 | 69 | def open_position(self, signal): 70 | price = mt5.symbol_info_tick(self.SYMBOL).ask if signal == 1 else mt5.symbol_info_tick(self.SYMBOL).bid 71 | 72 | sl = price * (1 - self.SL_PERCENT) if signal == 1 else price * (1 + self.SL_PERCENT) 73 | tp = price * (1 + self.TP_PERCENT) if signal == 1 else price * (1 - self.TP_PERCENT) 74 | 75 | volume = self.calculate_position_size(price, sl) 76 | 77 | request = { 78 | "action": mt5.TRADE_ACTION_DEAL, 79 | "symbol": self.SYMBOL, 80 | "volume": volume, 81 | "type": mt5.ORDER_TYPE_BUY if signal == 1 else mt5.ORDER_TYPE_SELL, 82 | "price": price, 83 | "sl": sl, 84 | "tp": tp, 85 | "deviation": 20, 86 | "magic": self.MAGIC, 87 | "comment": self.Comment, 88 | "type_time": mt5.ORDER_TIME_GTC, 89 | "type_filling": mt5.ORDER_FILLING_IOC, 90 | } 91 | 92 | result = mt5.order_send(request) 93 | if result.retcode != mt5.TRADE_RETCODE_DONE: 94 | print(f"Order sending failed: {result.comment}") 95 | else: 96 | print(f"Position opened: {result.comment}") 97 | print(f"Volume: {volume}, SL: {sl}, TP: {tp}") 98 | 99 | def close_position(self): 100 | positions = mt5.positions_get(symbol=self.SYMBOL) 101 | if positions: 102 | for pos in positions: 103 | if pos.magic == self.MAGIC: 104 | close_request = { 105 | "action": mt5.TRADE_ACTION_DEAL, 106 | "position": pos.ticket, 107 | "symbol": self.SYMBOL, 108 | "volume": pos.volume, 109 | "type": mt5.ORDER_TYPE_BUY if pos.type == 1 else mt5.ORDER_TYPE_SELL, 110 | "price": mt5.symbol_info_tick(self.SYMBOL).bid if pos.type == 0 else mt5.symbol_info_tick(self.SYMBOL).ask, 111 | "deviation": 20, 112 | "magic": self.MAGIC, 113 | "comment": "Position closed", 114 | "type_time": mt5.ORDER_TIME_GTC, 115 | "type_filling": mt5.ORDER_FILLING_IOC, 116 | } 117 | result = mt5.order_send(close_request) 118 | if result.retcode != mt5.TRADE_RETCODE_DONE: 119 | print(f"Failed to close position: {result.comment}") 120 | else: 121 | print(f"Position closed: {result.comment}") 122 | 123 | def manage_open_position(self, current_signal): 124 | positions = mt5.positions_get(symbol=self.SYMBOL) 125 | if positions: 126 | for position in positions: 127 | if position.magic == self.MAGIC: 128 | print(f"Current position state: Profit: {position.profit}, SL: {position.sl}, TP: {position.tp}") 129 | 130 | # Check if the position has hit SL or TP 131 | current_price = mt5.symbol_info_tick(self.SYMBOL).bid if position.type == 0 else mt5.symbol_info_tick(self.SYMBOL).ask 132 | if (position.type == 0 and current_price <= position.sl) or (position.type == 1 and current_price >= position.sl): 133 | print("Stop Loss hit. Closing position.") 134 | self.close_position() 135 | elif (position.type == 0 and current_price >= position.tp) or (position.type == 1 and current_price <= position.tp): 136 | print("Take Profit hit. Closing position.") 137 | self.close_position() 138 | else: 139 | print(f"Position maintained. Current signal: {current_signal}") 140 | 141 | def main(self): 142 | print(f"Starting Gold Trading Bot for {self.SYMBOL} on {self.TIMEFRAME} timeframe") 143 | print(f"Using {self.EMA_PERIOD}-period EMA strategy") 144 | print(f"Stop Loss: {self.SL_PERCENT*100}%, Take Profit: {self.TP_PERCENT*100}%") 145 | print("Bot is now running. Press Ctrl+C to stop.") 146 | 147 | last_candle_time = None 148 | 149 | while True: 150 | try: 151 | current_time = datetime.now() 152 | 153 | # Check if it's the start of a new 5-minute candle 154 | if current_time.minute % 5 == 0 and current_time.second == 0: 155 | if last_candle_time != current_time.replace(second=0, microsecond=0): 156 | print(f"\nScanning at {current_time}") 157 | last_candle_time = current_time.replace(second=0, microsecond=0) 158 | 159 | signal = self.check_signal() 160 | print(f"Signal: {signal} (1: Buy, -1: Sell, 0: No action)") 161 | 162 | positions = mt5.positions_get(symbol=self.SYMBOL) 163 | 164 | if not positions and signal != 0: 165 | print("No open positions. Attempting to open a new position...") 166 | self.open_position(signal) 167 | elif positions: 168 | print("Position is open. Checking if management is needed...") 169 | self.manage_open_position(signal) 170 | else: 171 | print("No action taken.") 172 | 173 | # Optional: Print a dot every minute to show the bot is still running 174 | if current_time.second == 0: 175 | print(".", end="", flush=True) 176 | 177 | time.sleep(1) # Check every second to catch the exact candle close 178 | 179 | except KeyboardInterrupt: 180 | print('\nKeyboardInterrupt received. Stopping the bot.') 181 | break 182 | except Exception as e: 183 | print(f"\nAn error occurred: {e}") 184 | print("Waiting for 60 seconds before retrying...") 185 | time.sleep(60) # Wait for a minute before retrying 186 | 187 | print("Bot has stopped running.") 188 | 189 | if __name__ == '__main__': 190 | trader = GoldTrader() 191 | trader.main() 192 | --------------------------------------------------------------------------------