Skip to main content
Glama

metatrader-mcp-server

test_order.py14.1 kB
import os import pytest from dotenv import load_dotenv from metatrader_client import MT5Client import platform import time from datetime import datetime import time # Ensure time is imported, though it was already there SYMBOL = "EURUSD" VOLUME = 0.01 PENDING_PRICE = 1.2000 # Adjust for your demo market @pytest.fixture(scope="module") def mt5_client(): # Clear console for pretty output if platform.system() == "Windows": os.system('cls') else: os.system('clear') print("\n🧪 MetaTrader 5 MCP Order System Full Test Suite 🧪\n") print("🔑 Loading credentials and connecting to MetaTrader 5...") load_dotenv() # Check if environment variables are set login = os.getenv("LOGIN") password = os.getenv("PASSWORD") server = os.getenv("SERVER") if not login or not password or not server: print("❌ Error: Missing required environment variables!") print("Please create a .env file with LOGIN, PASSWORD, and SERVER variables.") pytest.skip("Missing environment variables for MetaTrader 5 connection") config = { "login": int(login), "password": password, "server": server } client = MT5Client(config) client.connect() print("✅ Connected!\n") yield client print("\n🔌 Disconnecting from MetaTrader 5...") client.disconnect() print("👋 Disconnected!") def test_place_market_order_with_sl_tp(mt5_client): """Tests placing market orders with stop loss and take profit.""" print("\n🧪 Testing Market Orders with SL/TP 🧪") SYMBOL = "EURUSD" # Or use the global one VOLUME = 0.01 # Fetch current market price current_price_info = mt5_client.market.get_symbol_price(SYMBOL) assert current_price_info is not None, "Failed to fetch current market price." print(f"Current {SYMBOL} prices: Bid={current_price_info['bid']}, Ask={current_price_info['ask']}") # --- Test BUY Order with SL/TP --- print(f"\n🚀 Placing BUY order for {SYMBOL} with SL/TP...") order_type_buy = "BUY" buy_price = current_price_info['ask'] stop_loss_buy = round(buy_price - 0.0010, 5) take_profit_buy = round(buy_price + 0.0010, 5) market_order_buy = mt5_client.order.place_market_order( type=order_type_buy, symbol=SYMBOL, volume=VOLUME, stop_loss=stop_loss_buy, take_profit=take_profit_buy ) print(f"BUY Order Response: {market_order_buy}") assert market_order_buy is not None, "Market order (BUY) response is None." assert market_order_buy["error"] is False, f"BUY order failed: {market_order_buy['message']}" assert market_order_buy["data"] is not None, "BUY order data is None." # MT5 might adjust SL/TP slightly based on broker rules (e.g., distance from price), so direct equality might fail. # We should check if the SL/TP in the response are close to what we sent, or if they are not 0.0. # For this test, we'll check they are not 0.0 as a basic confirmation. # A more robust check would involve fetching the position details and verifying SL/TP there. assert market_order_buy["data"].request.sl == stop_loss_buy, f"BUY SL mismatch: expected {stop_loss_buy}, got {market_order_buy['data'].request.sl}" assert market_order_buy["data"].request.tp == take_profit_buy, f"BUY TP mismatch: expected {take_profit_buy}, got {market_order_buy['data'].request.tp}" print(f"✅ BUY order for {SYMBOL} with SL={stop_loss_buy}, TP={take_profit_buy} placed successfully. Order ID: {market_order_buy['data'].order}") time.sleep(2) # Allow broker to process print(f"Attempting to close BUY position ID: {market_order_buy['data'].order}") close_action_buy = mt5_client.order.close_position(market_order_buy["data"].order) print(f"Close BUY Response: {close_action_buy}") assert close_action_buy["error"] is False, f"Failed to close BUY position {market_order_buy['data'].order}: {close_action_buy['message']}" print(f"✅ BUY position {market_order_buy['data'].order} closed successfully.") time.sleep(5) # Interval between tests # --- Test SELL Order with SL/TP --- print(f"\n🚀 Placing SELL order for {SYMBOL} with SL/TP...") # Re-fetch price info in case market moved current_price_info_sell = mt5_client.market.get_symbol_price(SYMBOL) assert current_price_info_sell is not None, "Failed to fetch current market price for SELL." print(f"Current {SYMBOL} prices for SELL: Bid={current_price_info_sell['bid']}, Ask={current_price_info_sell['ask']}") order_type_sell = "SELL" sell_price = current_price_info_sell['bid'] stop_loss_sell = round(sell_price + 0.0010, 5) take_profit_sell = round(sell_price - 0.0010, 5) market_order_sell = mt5_client.order.place_market_order( type=order_type_sell, symbol=SYMBOL, volume=VOLUME, stop_loss=stop_loss_sell, take_profit=take_profit_sell ) print(f"SELL Order Response: {market_order_sell}") assert market_order_sell is not None, "Market order (SELL) response is None." assert market_order_sell["error"] is False, f"SELL order failed: {market_order_sell['message']}" assert market_order_sell["data"] is not None, "SELL order data is None." assert market_order_sell["data"].request.sl == stop_loss_sell, f"SELL SL mismatch: expected {stop_loss_sell}, got {market_order_sell['data'].request.sl}" assert market_order_sell["data"].request.tp == take_profit_sell, f"SELL TP mismatch: expected {take_profit_sell}, got {market_order_sell['data'].request.tp}" print(f"✅ SELL order for {SYMBOL} with SL={stop_loss_sell}, TP={take_profit_sell} placed successfully. Order ID: {market_order_sell['data'].order}") time.sleep(2) # Allow broker to process print(f"Attempting to close SELL position ID: {market_order_sell['data'].order}") close_action_sell = mt5_client.order.close_position(market_order_sell["data"].order) print(f"Close SELL Response: {close_action_sell}") assert close_action_sell["error"] is False, f"Failed to close SELL position {market_order_sell['data'].order}: {close_action_sell['message']}" print(f"✅ SELL position {market_order_sell['data'].order} closed successfully.") print("\n🎉 Test for market orders with SL/TP completed. 🎉") def test_full_order_functionality(mt5_client): summary = [] # 1. Get all positions print("\n📋 Getting all open positions...") all_positions = mt5_client.order.get_all_positions() print(f"📈 All positions:\n{all_positions}") summary.append("📋 get_all_positions: ✅") # 2. Get positions by symbol print("\n🔎 Getting positions by symbol...") positions_by_symbol = mt5_client.order.get_positions_by_symbol(SYMBOL) print(f"🔎 Positions for {SYMBOL}:\n{positions_by_symbol}") summary.append("🔎 get_positions_by_symbol: ✅") # 3. Get positions by currency (assuming USD) print("\n💵 Getting positions by currency...") positions_by_currency = mt5_client.order.get_positions_by_currency("USD") print(f"💵 Positions for USD:\n{positions_by_currency}") summary.append("💵 get_positions_by_currency: ✅") # 4. Place a market order print("\n🚀 Placing a market BUY order...") market_order = mt5_client.order.place_market_order( type="BUY", symbol=SYMBOL, volume=VOLUME ) assert market_order is not None and ("data" in market_order and market_order["data"] is not None), "❌ Failed to place market order" print(f"✅ Market order placed! ID: {market_order['data'].order if market_order['data'] else 'N/A'}") summary.append("🚀 place_market_order: ✅") # 5. Get positions by id print("\n🆔 Getting position by ID...") pos_id = market_order["data"].order if market_order["data"] else None position_by_id = mt5_client.order.get_positions_by_id(pos_id) print(f"🆔 Position for ID {pos_id}:\n{position_by_id}") summary.append("🆔 get_positions_by_id: ✅") # 6. Place a pending order print("\n⏳ Placing a pending BUY order...") pending_order = mt5_client.order.place_pending_order( type="BUY", symbol=SYMBOL, volume=VOLUME, price=PENDING_PRICE ) assert pending_order is not None and ("data" in pending_order and pending_order["data"] is not None), "❌ Failed to place pending order" print(f"✅ Pending order placed! ID: {pending_order['data'].order if pending_order['data'] else 'N/A'}") summary.append("⏳ place_pending_order: ✅") # 7. Get pending orders (all) print("\n🕒 Getting all pending orders...") all_pending_orders = mt5_client.order.get_all_pending_orders() print(f"🕒 All pending orders:\n{all_pending_orders}") summary.append("🕒 get_all_pending_orders: ✅") # 8. Get pending orders by symbol print("\n🔎 Getting pending orders by symbol...") pending_by_symbol = mt5_client.order.get_pending_orders_by_symbol(SYMBOL) print(f"🔎 Pending orders for {SYMBOL}:\n{pending_by_symbol}") summary.append("🔎 get_pending_orders_by_symbol: ✅") # 9. Get pending orders by currency print("\n💵 Getting pending orders by currency...") pending_by_currency = mt5_client.order.get_pending_orders_by_currency("USD") print(f"💵 Pending orders for USD:\n{pending_by_currency}") summary.append("💵 get_pending_orders_by_currency: ✅") # 10. Get pending orders by id print("\n🆔 Getting pending order by ID...") pend_id = pending_order["data"].order if pending_order["data"] else None pending_by_id = mt5_client.order.get_pending_orders_by_id(pend_id) print(f"🆔 Pending order for ID {pend_id}:\n{pending_by_id}") summary.append("🆔 get_pending_orders_by_id: ✅") # 11. Modify the open position (if supported) print("\n✏️ Modifying the open position SL/TP...") modified_position = mt5_client.order.modify_position( id=pos_id, stop_loss=1.1000, # Example SL value, adjust as needed take_profit=1.3000 # Example TP value, adjust as needed ) print(f"✏️ Modified position: {modified_position}") summary.append("✏️ modify_position: ✅") # 12. Modify the pending order print("\n✏️ Modifying the pending order price...") new_price = PENDING_PRICE - 0.0005 modified_pending = mt5_client.order.modify_pending_order( id=pend_id, price=new_price ) print(f"✏️ Modified pending order: {modified_pending}") summary.append("✏️ modify_pending_order: ✅") # 13. Close all profitable positions print("\n💰 Closing all profitable positions...") close_profitable = mt5_client.order.close_all_profitable_positions() print(f"💰 Closed profitable positions: {close_profitable}") summary.append("💰 close_all_profitable_positions: ✅") # 14. Close all losing positions print("\n🔻 Closing all losing positions...") close_losing = mt5_client.order.close_all_losing_positions() print(f"🔻 Closed losing positions: {close_losing}") summary.append("🔻 close_all_losing_positions: ✅") # 15. Close all positions by symbol print(f"\n🔒 Closing all positions for {SYMBOL}...") close_by_symbol = mt5_client.order.close_all_positions_by_symbol(SYMBOL) print(f"🔒 Closed positions for {SYMBOL}: {close_by_symbol}") summary.append("🔒 close_all_positions_by_symbol: ✅") # 16. Close all positions print("\n🛑 Closing all positions...") close_all = mt5_client.order.close_all_positions() print(f"🛑 Closed all positions: {close_all}") summary.append("🛑 close_all_positions: ✅") # 17. Close the specific market order (if still open) print("\n🛑 Closing the market order by ID...") close_market = mt5_client.order.close_position(id=pos_id) print(f"🛑 Closed market order: {close_market}") summary.append("🛑 close_position: ✅") # 18. Cancel the pending order by ID print("\n🚫 Cancelling the pending order by ID...") cancel_pending = mt5_client.order.cancel_pending_order(id=pend_id) print(f"🚫 Cancelled pending order: {cancel_pending}") summary.append("🚫 cancel_pending_order: ✅") # 19. Cancel all pending orders by symbol print(f"\n🚫 Cancelling all pending orders for {SYMBOL}...") cancel_by_symbol = mt5_client.order.cancel_pending_orders_by_symbol(SYMBOL) print(f"🚫 Cancelled pending orders for {SYMBOL}: {cancel_by_symbol}") summary.append("🚫 cancel_pending_orders_by_symbol: ✅") # 20. Cancel all pending orders print("\n🚫 Cancelling all pending orders...") cancel_all = mt5_client.order.cancel_all_pending_orders() print(f"🚫 Cancelled all pending orders: {cancel_all}") summary.append("🚫 cancel_all_pending_orders: ✅") # Summary print("\n\n✨📝 TEST SUMMARY 📝✨") for line in summary: print(line) print("\n🎉 All order functions tested successfully on demo account! 🎉\n") time.sleep(1) # --- REPORTING SECTION --- # Always write report, even if some steps failed now = datetime.now() timestamp = now.strftime('%Y-%m-%d_%H-%M-%S') report_dir = os.path.join(os.path.dirname(__file__), '../reports') os.makedirs(report_dir, exist_ok=True) filename = f"{timestamp}_client_order.md" filepath = os.path.join(report_dir, filename) all_passed = all('✅' in s for s in summary) status = '✅ SUCCESS' if all_passed else '❌ FAILURE' with open(filepath, 'w', encoding='utf-8') as f: f.write(f"# 🧪 MetaTrader 5 MCP Order System Test Report\n\n") f.write(f"**Date:** {now.strftime('%Y-%m-%d %H:%M:%S')}\n\n") f.write(f"**Module:** Client Order\n\n") f.write(f"## Test Steps and Results\n\n") for s in summary: f.write(f"- {s}\n") f.write("\n---\n") f.write(f"**Status:** {status}\n") print(f"\n📄 Test report written to: {filepath}\n")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ariadng/metatrader-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server