✅ Validating Trade Requests (OrderCheckAsync)¶
Request: Run a dry‑run check of a trade request on MT5. The server simulates the trade and returns balance / equity / margin impact without actually placing an order.
API Information:
- SDK wrapper:
MT5Account.OrderCheckAsync(...)(from NuGet packageMetaRPC.MT5) - gRPC service:
mt5_term_api.TradeFunctions - Proto definition:
OrderCheck(defined inmt5-term-api-trade-functions.proto)
RPC¶
- Service:
mt5_term_api.TradeFunctions - Method:
OrderCheck(OrderCheckRequest) → OrderCheckReply - Low‑level client (generated):
TradeFunctions.TradeFunctionsClient.OrderCheck(request, headers, deadline, cancellationToken) - SDK wrapper (your class):
namespace mt5_term_api
{
public class MT5Account
{
public async Task<OrderCheckData> OrderCheckAsync(
OrderCheckRequest request,
DateTime? deadline = null,
CancellationToken cancellationToken = default);
}
}
Request message:
OrderCheckRequest { mql_trade_request: MrpcMqlTradeRequest }
Reply message:
OrderCheckReply { data: OrderCheckData }
🔽 Input¶
| Parameter | Type | Description |
|---|---|---|
request |
OrderCheckRequest |
Protobuf request wrapping MrpcMqlTradeRequest |
deadline |
DateTime? |
Absolute per‑call UTC deadline → converted to timeout |
cancellationToken |
CancellationToken |
Cooperative cancel for the call/retry loop |
MrpcMqlTradeRequest — Core trade description¶
| Field | Type | Description |
|---|---|---|
Action |
MRPC_ENUM_TRADE_REQUEST_ACTIONS |
Trade operation type (deal, pending order, etc.) |
ExpertAdvisorMagicNumber |
ulong |
EA magic number (use 0 for manual trades) |
Order |
ulong |
Order ticket (for modify/remove operations) |
Symbol |
string |
Trading symbol, e.g. "EURUSD", "XAUUSD" |
Volume |
double |
Volume in lots (must respect symbol min/max/step) |
Price |
double |
Price for validation. Use current Bid/Ask for market |
StopLimit |
double |
StopLimit price (for StopLimit orders) |
StopLoss |
double |
Stop Loss level (optional) |
TakeProfit |
double |
Take Profit level (optional) |
Deviation |
ulong |
Max price deviation in points (optional) |
OrderType |
ENUM_ORDER_TYPE_TF |
Order type: Buy, Sell, BuyLimit, SellStop, etc. |
TypeFilling |
MRPC_ENUM_ORDER_TYPE_FILLING |
Filling mode: FOK, IOC, Return, BOC |
TypeTime |
MRPC_ENUM_ORDER_TYPE_TIME |
Time‑in‑force: GTC, Day, Specified |
Expiration |
Timestamp |
Expiration time (for ORDER_TIME_SPECIFIED) |
Comment |
string |
Order comment (optional) |
Position |
ulong |
Position ticket (for position operations) |
PositionBy |
ulong |
Opposite position ticket (for close-by) |
⬆️ Output — OrderCheckData¶
| Field | Type | Description |
|---|---|---|
MqlTradeCheckResult.ReturnedCode |
uint |
Reply code (0 = OK, other = rejected/error) |
MqlTradeCheckResult.BalanceAfterDeal |
double |
Simulated balance after the trade |
MqlTradeCheckResult.EquityAfterDeal |
double |
Simulated equity after the trade |
MqlTradeCheckResult.Profit |
double |
Simulated floating profit |
MqlTradeCheckResult.Margin |
double |
Required margin for the trade |
MqlTradeCheckResult.FreeMargin |
double |
Simulated free margin after the trade |
MqlTradeCheckResult.MarginLevel |
double |
Margin level after the trade (percent) |
MqlTradeCheckResult.Comment |
string |
Human‑readable explanation for ReturnedCode |
🧱 Related enums (from proto)¶
ENUM_ORDER_TYPE_TF¶
OrderTypeTfBuy— Market Buy orderOrderTypeTfSell— Market Sell orderOrderTypeTfBuyLimit— Buy Limit pending orderOrderTypeTfSellLimit— Sell Limit pending orderOrderTypeTfBuyStop— Buy Stop pending orderOrderTypeTfSellStop— Sell Stop pending orderOrderTypeTfBuyStopLimit— Buy Stop Limit orderOrderTypeTfSellStopLimit— Sell Stop Limit orderOrderTypeTfCloseBy— Close position by opposite one
MRPC_ENUM_ORDER_TYPE_FILLING¶
OrderFillingFok— Fill‑or‑Kill (execute full volume or cancel)OrderFillingIoc— Immediate‑or‑Cancel (execute available volume, cancel rest)OrderFillingReturn— Return (partial fill allowed, rest remains active)OrderFillingBoc— Book‑or‑Cancel (place in DOM, don't execute immediately)
MRPC_ENUM_ORDER_TYPE_TIME¶
OrderTimeGtc— Good‑Till‑CancelledOrderTimeDay— Good till current trade dayOrderTimeSpecified— Good till expiration timeOrderTimeSpecifiedDay— Good till 23:59:59 of specified day
MRPC_ENUM_TRADE_REQUEST_ACTIONS¶
TradeActionDeal— Place market order for immediate executionTradeActionPending— Place pending orderTradeActionSltp— Modify SL/TP of opened positionTradeActionModify— Modify pending order parametersTradeActionRemove— Delete pending orderTradeActionCloseBy— Close position by opposite one
💬 Just the essentials¶
- What it is. Dry‑run validation of a trade request. Returns simulated balance/equity/margin impact without placing a real order.
- Why you need it. Catch errors ("not enough money", wrong lot sizes, bad prices) before calling
OrderSendAsync. - Sanity check. If
ReturnedCode == 0andCommentsays "OK" → trade can proceed.
🎯 Purpose¶
Use it to validate trades before execution:
- Pre‑trade risk checks (margin level, lot size).
- Debug strategy behavior on new brokers.
- Prevent "not enough money" errors.
🧩 Notes & Tips¶
- Broker support: Some brokers don't support
OrderCheck. Server returns error →ApiExceptionMT5. This is a broker limitation. - ⚠️ MetaQuotes-Demo server limitation: On MetaQuotes-Demo broker, OrderCheck returns success (code 0) but all margin/balance/equity values are
-0.00(negative zeros). The server accepts the request but doesn't simulate real values. UseOrderCalcMarginAsync()instead for margin calculations on this broker. - Market orders: Use current Bid/Ask as
Price(Buy → ask, Sell → bid). - Respect symbol limits: Check
SymbolVolumeMin/Max/Stepbefore calling. - Short deadline: 5–10 seconds is enough. Exotic symbols may be slower.
- Alternative: If OrderCheck returns zeros or doesn't work, use
OrderCalcMarginAsync()which is simpler and more reliable across brokers.
🔗 Usage Examples¶
1) Basic market BUY validation¶
// acc — an already connected MT5Account instance
// Get minimal lot for the symbol
var volumeMin = await acc.SymbolInfoDoubleAsync(
"EURUSD",
SymbolInfoDoublePropertyType.SymbolVolumeMin);
var symbol = "EURUSD";
var minLot = volumeMin.Value;
// Current ask price (get from your quote feed)
double ask = /* current ask price here */;
// Build trade request
var tradeRequest = new MrpcMqlTradeRequest
{
Action = MRPC_ENUM_TRADE_REQUEST_ACTIONS.TradeActionDeal,
Symbol = symbol,
Volume = minLot,
Price = ask,
StopLoss = 0.0,
TakeProfit = 0.0,
OrderType = ENUM_ORDER_TYPE_TF.OrderTypeTfBuy,
TypeFilling = MRPC_ENUM_ORDER_TYPE_FILLING.OrderFillingFok,
TypeTime = MRPC_ENUM_ORDER_TYPE_TIME.OrderTimeGtc,
ExpertAdvisorMagicNumber = 12345
};
var checkRequest = new OrderCheckRequest
{
MqlTradeRequest = tradeRequest
};
var checkResult = await acc.OrderCheckAsync(
checkRequest,
deadline: DateTime.UtcNow.AddSeconds(10));
var result = checkResult?.MqlTradeCheckResult;
if (result == null)
{
Console.WriteLine("OrderCheck returned no data.");
}
else
{
Console.WriteLine($"Return code: {result.ReturnedCode}");
Console.WriteLine($"Balance after: {result.BalanceAfterDeal:F2}");
Console.WriteLine($"Equity after: {result.EquityAfterDeal:F2}");
Console.WriteLine($"Required margin: {result.Margin:F2}");
Console.WriteLine($"Free margin: {result.FreeMargin:F2}");
Console.WriteLine($"Margin level: {result.MarginLevel:F2}%");
Console.WriteLine($"Comment: {result.Comment}");
}
2) Send order only if the check passes¶
async Task<bool> TrySendBuyAsync(MT5Account acc, string symbol, double lots)
{
double ask = /* current ask price */;
var tradeRequest = new MrpcMqlTradeRequest
{
Action = MRPC_ENUM_TRADE_REQUEST_ACTIONS.TradeActionDeal,
Symbol = symbol,
Volume = lots,
Price = ask,
OrderType = ENUM_ORDER_TYPE_TF.OrderTypeTfBuy,
TypeFilling = MRPC_ENUM_ORDER_TYPE_FILLING.OrderFillingFok,
TypeTime = MRPC_ENUM_ORDER_TYPE_TIME.OrderTimeGtc,
ExpertAdvisorMagicNumber = 202501
};
var check = await acc.OrderCheckAsync(new OrderCheckRequest
{
MqlTradeRequest = tradeRequest
});
var result = check?.MqlTradeCheckResult;
if (result == null)
throw new Exception("OrderCheck returned null result");
var isOk = result.ReturnedCode == 0; // or your own mapping
if (isOk)
{
// Now we can safely send the order
var sendResult = await acc.OrderSendAsync(new OrderSendRequest
{
MqlTradeRequest = tradeRequest
});
Console.WriteLine($"Order sent, result: {sendResult.ReturnedCode}");
return true;
}
Console.WriteLine($"Order rejected by OrderCheck: {result.ReturnedCode} / {result.Comment}");
return false;
}
3) Simple risk rule by margin level¶
// Example: do not trade if margin level after the deal falls below 200%
var check = await acc.OrderCheckAsync(new OrderCheckRequest
{
MqlTradeRequest = new MrpcMqlTradeRequest
{
Action = MRPC_ENUM_TRADE_REQUEST_ACTIONS.TradeActionDeal,
Symbol = "XAUUSD",
Volume = 0.10,
Price = /* current ask */,
OrderType = ENUM_ORDER_TYPE_TF.OrderTypeTfBuy,
TypeFilling = MRPC_ENUM_ORDER_TYPE_FILLING.OrderFillingFok,
TypeTime = MRPC_ENUM_ORDER_TYPE_TIME.OrderTimeGtc
}
});
var r = check.MqlTradeCheckResult;
if (r.MarginLevel < 200.0)
{
Console.WriteLine($"Risk rule triggered: margin level would drop to {r.MarginLevel:F2}%");
// Skip trading here
}
else
{
Console.WriteLine("Margin level OK, you may proceed with OrderSendAsync.");
}