mt5.order_send() in MetaTrader5 Python: place, change or close a trade
Sends a trade request to the broker: open a position, place a pending order, change stops, or close. Returns a result with a retcode, or None.
Signature
mt5.order_send(request) What it does
order_send() takes a request dict. action says what to do: mt5.TRADE_ACTION_DEAL for a market order, mt5.TRADE_ACTION_PENDING for a pending order, mt5.TRADE_ACTION_SLTP to change a position's stops, mt5.TRADE_ACTION_MODIFY to change a pending order, and mt5.TRADE_ACTION_REMOVE to delete one.
To close a position, send a deal in the opposite direction with position set to the position's ticket.
Parameters
| Parameter | What it is |
|---|---|
request | A dict with action and the fields it needs: symbol, volume, type, price, sl, tp, deviation, type_filling, type_time, expiration, magic, comment, order or position. |
What it returns
- A result with
retcode,deal,order,volume,price,commentand therequestyou sent. Success codes are 10009 (done), 10008 (pending order placed) and 10010 (partly filled). Nonewhen the request never got a reply. Checkmt5.last_error(), and treat the outcome as unknown.
Example
import MetaTrader5 as mt5
if not mt5.initialize():
raise SystemExit(mt5.last_error())
mt5.symbol_select("EURUSD", True)
tick = mt5.symbol_info_tick("EURUSD")
req = {
"action": mt5.TRADE_ACTION_DEAL,
"symbol": "EURUSD",
"volume": 0.10,
"type": mt5.ORDER_TYPE_BUY,
"price": tick.ask,
"sl": round(tick.ask - 0.0030, 5),
"deviation": 10,
"magic": 2410,
"comment": "sig-7781", # lets you find it again
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
res = mt5.order_send(req)
if res is None or res.retcode in (10031, 10012):
# No clear answer: the order may have reached the broker.
# Look for comment "sig-7781" in positions and deals before sending again.
print("unknown outcome:", None if res is None else res.retcode, mt5.last_error())
elif res.retcode not in (10008, 10009, 10010):
print("rejected:", res.retcode, res.comment)
else:
print("filled at", res.price, "deal", res.deal)
mt5.shutdown() Common mistakes
- 10031 (no connection) or a
Noneresult does not mean the order failed. The request may have reached the broker before the link dropped. Look inpositions_get()andhistory_deals_get()before you send again, or you can open the trade twice. - The filling mode must be one the symbol allows, or the send fails with 10030. Brokers differ, so read
symbol_info().filling_moderather than hard-coding one. - Select the symbol in Market Watch and use a fresh price. A stale price brings 10004 requote or 10021 off quotes.
- Algo trading must be on in the terminal, or you get 10027.
expirationis a broker server time, not UTC.
The same with Tickwire on Linux
The package needs a Windows terminal on the same machine. Tickwire runs the terminal for you and gives you a REST API, so the code below runs on Linux, macOS or a server.
Tickwire's trade route takes one JSON body for MT4 and MT5, with actionType such as ORDER_TYPE_BUY, POSITION_MODIFY or POSITION_CLOSE_ID. It picks a filling mode the symbol allows, or takes your own order of preference in fillingModes.
Send an Idempotency-Key with every order. The reply always has numericCode, stringCode and an outcome of applied, no_change, partial, rejected or unknown. The HTTP status is 200 even when the broker refuses.
If the reply's outcome is unknown, the order may have reached the broker. Do not send it again with a new key. Read positions, orders and deals first. Sending the same Idempotency-Key again never places a second order; it returns the first answer. See When the answer is "unknown".
POST /users/current/accounts/{account_id}/tradePOST /users/current/accounts/{account_id}/trade/checkGET /users/current/accounts/{account_id}/positionsGET /users/current/accounts/{account_id}/history-deals/time/{start_time}/{end_time}
import os, requests
API = "https://api.tickwire.io"
h = {"auth-token": os.environ["TW_KEY"]} # your Tickwire key
base = f"{API}/users/current/accounts/{os.environ['TW_ACCOUNT']}"
import uuid
key = str(uuid.uuid4()) # make it once per trading decision; reuse it on retry
r = requests.post(f"{base}/trade", json={
"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.10,
"clientId": "sig-7781",
}, headers={**h, "Idempotency-Key": key,
"X-Actor": "my-script", "X-Reason": "signal 7781"})
res = r.json()
print(res["outcome"], res["stringCode"])
if res["outcome"] == "unknown":
print("check positions and deals for clientId sig-7781 before acting") Related functions
- mt5.order_check() in MetaTrader5 Python: test an order before you send it
- mt5.symbol_info_tick() in MetaTrader5 Python: get the latest bid and ask
- mt5.symbol_info() in MetaTrader5 Python: read a symbol's settings and limits
- mt5.positions_get() in MetaTrader5 Python: read open positions
- mt5.history_deals_get() in MetaTrader5 Python: read past deals and fills
- mt5.last_error() in MetaTrader5 Python: find out why the last call failed
Related error codes
- MT5 error 10031: No connection with the trade server (TRADE_RETCODE_CONNECTION)
- MT5 error 10030: Invalid order filling type (TRADE_RETCODE_INVALID_FILL)
- MT5 error 10004: Requote (TRADE_RETCODE_REQUOTE)
- MT5 error 10006: Request rejected (TRADE_RETCODE_REJECT)
- MT5 error 10012: Request canceled by timeout (TRADE_RETCODE_TIMEOUT)
- MT5 error 10014: Invalid volume (TRADE_RETCODE_INVALID_VOLUME)
- MT5 error 10015: Invalid price (TRADE_RETCODE_INVALID_PRICE)
- MT5 error 10016: Invalid stops (TRADE_RETCODE_INVALID_STOPS)
- MT5 error 10018: Market is closed (TRADE_RETCODE_MARKET_CLOSED)
- MT5 error 10019: Not enough money (TRADE_RETCODE_NO_MONEY)
- MT5 error 10021: No quotes to process the request (TRADE_RETCODE_PRICE_OFF)
- MT5 error 10027: Autotrading disabled by client terminal (TRADE_RETCODE_CLIENT_DISABLES_AT)
- MT5 return code 10009: Request completed (TRADE_RETCODE_DONE)
- MT5 return code 10008: Order placed (TRADE_RETCODE_PLACED)
- MT5 return code 10010: Only part of the request was completed (TRADE_RETCODE_DONE_PARTIAL)
- MT5 Python error -8: Auto-trading disabled (RES_E_AUTO_TRADING_DISABLED)
- MT5 Python error -10001: IPC send failed (RES_E_INTERNAL_FAIL_SEND)
- MT5 Python error -10002: IPC receive failed (RES_E_INTERNAL_FAIL_RECEIVE)
- MT5 Python error -10005: IPC timeout (RES_E_INTERNAL_FAIL_TIMEOUT)
MT5 from Python, on any machine
One REST API for MT4 and MT5, with idempotent orders and an audit log. Read the MT5 Python API page or the quickstart.