Broker API HubMenu

MetaTrader 5 Python API quickstart: first call

Install MetaTrader5 on Windows, connect to a running terminal, pull ticks, bars and deal history, and send a demo order. Every step sourced.

Independent and unofficialChecked Code not yet run on a demo account

Risk warning: CFDs and spread bets are complex instruments and come with a high risk of losing money rapidly due to leverage. You can lose money on these products, and each provider publishes its own loss figure under FCA rules. You should consider whether you understand how they work and whether you can afford to take the high risk of losing your money. Automated and API trading can amplify losses through bugs, connectivity failures and runaway orders.

Demo accounts only. Credentials are read from environment variables on your own machine. No field on this site asks for a key, a username or a password.

Steps

  1. Windows and a running terminal

    The Python package talks to the MetaTrader 5 terminal by interprocess communication, so the terminal must be installed, running and logged in, ideally to a demo account. Every PyPI build is Windows x86-64. No Linux build, no macOS build, no exceptions.

    pypi.orgchecked

  2. Install the package

    pip install MetaTrader5. MQL5 recommends Python 3.8 or later; PyPI lists 3.6 to 3.14. The current release is 5.0.6231, published on 27 Sep 2026, and MetaQuotes ships new builds often, so upgrade regularly.

    Python
    pip install MetaTrader5
    # Upgrade later with:
    pip install -U MetaTrader5
    
    JavaScript
    // The MetaTrader5 package is Python only. It talks to the terminal on the same
    // Windows machine, so there is no HTTP endpoint to call from JavaScript.
    // Use the Python tab.
    
    curl
    # The MetaTrader5 package is Python only. It talks to the terminal on the same
    # Windows machine, so there is no HTTP endpoint for curl. Use the Python tab.
    

    mql5.comchecked

  3. Connect with initialize()

    initialize() returns True or False. On False, last_error() gives a code and description, such as -6 for failed authorisation. You only need login() to switch account: leave out password and server and it uses the ones saved in the terminal. Always finish with shutdown().

    Python
    import os
    import MetaTrader5 as mt5
    
    # The terminal must be installed, running and logged in to a demo account
    if not mt5.initialize():
        raise SystemExit(f"initialize() failed: {mt5.last_error()}")
    
    print(mt5.version())
    print(mt5.account_info())
    
    # Optional: switch account. Password and server fall back to those saved in the terminal.
    # Values come from environment variables you set yourself, never from the code:
    # mt5.login(int(os.environ["MT5_LOGIN"]), password=os.environ["MT5_PASSWORD"], server=os.environ["MT5_SERVER"])
    
    mt5.shutdown()
    
    JavaScript
    // The MetaTrader5 package is Python only. It talks to the terminal on the same
    // Windows machine, so there is no HTTP endpoint to call from JavaScript.
    // Use the Python tab.
    
    curl
    # The MetaTrader5 package is Python only. It talks to the terminal on the same
    # Windows machine, so there is no HTTP endpoint for curl. Use the Python tab.
    

    mql5.comchecked

  4. First real call: prices

    Select the symbol, then symbol_info_tick gives you bid, ask, last and time. copy_rates_from_pos returns a numpy array of bars with time, open, high, low, close, tick_volume, spread and real_volume. Position 0 is the current bar.

    Python
    import MetaTrader5 as mt5
    
    if not mt5.initialize():
        raise SystemExit(f"initialize() failed: {mt5.last_error()}")
    
    if not mt5.symbol_select("EURUSD", True):
        print("EURUSD not available:", mt5.last_error())
    else:
        tick = mt5.symbol_info_tick("EURUSD")
        print("bid", tick.bid, "ask", tick.ask)
    
        # Last 10 daily bars; position 0 is the current bar
        rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_D1, 0, 10)
        for r in rates:
            print(r['time'], r['open'], r['high'], r['low'], r['close'])
    
    mt5.shutdown()
    
    JavaScript
    // The MetaTrader5 package is Python only. It talks to the terminal on the same
    // Windows machine, so there is no HTTP endpoint to call from JavaScript.
    // Use the Python tab.
    
    curl
    # The MetaTrader5 package is Python only. It talks to the terminal on the same
    # Windows machine, so there is no HTTP endpoint for curl. Use the Python tab.
    

    mql5.comchecked

  5. Your trade history

    history_deals_get(date_from, date_to) returns deals as named tuples with ticket, symbol, type, volume, price and profit, or None on error. Filter with group=, ticket= or position= when you want less.

    Python
    from datetime import datetime, timedelta
    import MetaTrader5 as mt5
    
    if not mt5.initialize():
        raise SystemExit(f"initialize() failed: {mt5.last_error()}")
    
    date_to = datetime.now()
    date_from = date_to - timedelta(days=30)
    deals = mt5.history_deals_get(date_from, date_to)
    if deals is None:
        print("No deals, error code =", mt5.last_error())
    else:
        for d in deals:
            print(d.ticket, d.symbol, d.type, d.volume, d.price, d.profit)
    
    mt5.shutdown()
    
    JavaScript
    // The MetaTrader5 package is Python only. It talks to the terminal on the same
    // Windows machine, so there is no HTTP endpoint to call from JavaScript.
    // Use the Python tab.
    
    curl
    # The MetaTrader5 package is Python only. It talks to the terminal on the same
    # Windows machine, so there is no HTTP endpoint for curl. Use the Python tab.
    

    mql5.comchecked

  6. A demo order, if you want one

    order_send takes a request dict and returns a result. Success is result.retcode equal to TRADE_RETCODE_DONE (10009). The code reads the fill policies the symbol allows from symbol_info(symbol).filling_mode and picks FOK, IOC or RETURN to match, which avoids retcode 10030, unsupported filling mode. Demo account only.

    Python
    import MetaTrader5 as mt5
    
    # Demo account only
    if not mt5.initialize():
        raise SystemExit(f"initialize() failed: {mt5.last_error()}")
    
    symbol = "EURUSD"
    mt5.symbol_select(symbol, True)
    price = mt5.symbol_info_tick(symbol).ask
    
    info = mt5.account_info()
    if info is None or info.trade_mode != mt5.ACCOUNT_TRADE_MODE_DEMO:
        raise SystemExit("Not a demo account. Stopping before any order is sent.")
    
    # Pick a filling mode the symbol allows. filling_mode is a bit mask:
    # 1 = fill or kill (SYMBOL_FILLING_FOK), 2 = immediate or cancel (SYMBOL_FILLING_IOC).
    # A hardcoded ORDER_FILLING_RETURN fails with retcode 10030 on market execution symbols.
    modes = mt5.symbol_info(symbol).filling_mode
    if modes & 1:
        filling = mt5.ORDER_FILLING_FOK
    elif modes & 2:
        filling = mt5.ORDER_FILLING_IOC
    else:
        # allowed in every execution mode except market execution
        filling = mt5.ORDER_FILLING_RETURN
    
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": 0.01,
        "type": mt5.ORDER_TYPE_BUY,
        "price": price,
        "deviation": 20,
        "magic": 234000,
        "comment": "quickstart",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": filling,
    }
    result = mt5.order_send(request)
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print("order_send failed, retcode =", result.retcode)  # 10030: unsupported filling mode
    else:
        print("Filled, order", result.order)
    
    mt5.shutdown()
    
    JavaScript
    // The MetaTrader5 package is Python only. It talks to the terminal on the same
    // Windows machine, so there is no HTTP endpoint to call from JavaScript.
    // Use the Python tab.
    
    curl
    # The MetaTrader5 package is Python only. It talks to the terminal on the same
    # Windows machine, so there is no HTTP endpoint for curl. Use the Python tab.
    

    Unverifiedmql5.com

Sources

Sections