Your strategy as an MT5 bot · Daily-loss lock built incontact@stratcorealpha.com · DE
All trading software errors

MT4 · code and request checks

MT4 error 4107: log the exact price before changing it

Your entry can look valid and still fail. My MT4 test returned error 4107 for an over-precise entry, then accepted current Ask.

Native MT4 tester: fractional-point entry fails with 4107, current Ask succeeds and stored entry matches. Zero account orders.

Arnold Holm · 2026-10-24

What the error means

A trader testing XAUUSD reported an invalid price of 2347.42500000. The number looked close to the market. The trader had checked for negative inputs and tried normalization, but the error remained. Without the source and symbol settings, that report does not establish which argument was wrong. A plausible-looking number is not enough to diagnose an OrderSend call. I start by keeping three things together: the exact request, the function return value, and the error captured immediately after the call. The request includes entry, stop loss and take profit. Looking only at the entry price can miss a problem in a calculated stop or target. Printing fewer decimal places can also hide the input that the function actually received. The official MQL4 error table lists 4107 as ERR_INVALID_PRICE_PARAM. It separately lists 129 as ERR_INVALID_PRICE and 130 as ERR_INVALID_STOPS. Those numbers should not be swapped in a log or folded into one guessed explanation. The OrderSend reference describes price-thread and precision conditions for 129, and stop-distance conditions for 130. Record the number that your own terminal returned. I built a small native MT4 Strategy Tester test case to isolate an over-precise entry. On supplied EURUSD H4 history, it first submitted a simulated BUY at Ask plus 0.1234567 of one point. The deliberately altered price returned ticket -1 and error 4107. The next simulated BUY used the current Ask without that extra fraction. It returned a positive ticket and error 0. A fresh order selection confirmed that the stored entry matched Ask within half a point. The simulated position was then closed inside the tester. No order went to an account. The screenshot is the actual tester output from this run, not a mock trading result. The test case uses one EURUSD dataset and a fixed 20-point spread. It does not reproduce the trader's XAUUSD setup, inspect that person's source, or establish a universal rounding rule for gold. I diagnose the exact request before adding another retry. A retry with the same invalid input adds no new information. A retry after silently rounding a pending entry can change the trading rule. Keep the original value in the record, identify the field that fails validation, and decide whether a corrected candidate still satisfies the intended rule.

Three code paths to check

  1. 1. An entry calculation adds unsupported precision

    In the native test case, adding a fractional point to Ask was enough to produce 4107. For a market BUY, use the current Ask for the actual order symbol. For a market SELL, use current Bid. A calculated pending entry has a different validation path and must retain the intended distance and direction after alignment.

  2. 2. A calculated stop or target is the bad input

    Record stop loss and take profit alongside the entry. Check that every nonzero value is finite, has the intended sign and sits on the permitted price increment. Zero can mean no stop or target. Do not reject zero indiscriminately or silently replace a requested protective stop with zero.

  3. 3. Decimal formatting is mistaken for a valid price grid

    Digits controls decimal precision. A symbol can also have a tradable price increment that needs separate handling. Rounding to a number of decimal places does not by itself prove that a calculated price is on that grid. Read the symbol specifications and keep point, tick increment and pip conventions distinct.

Keep the failing input and immediate error in one record

The excerpt is deliberately invalid and belongs only in a tester. Its purpose is to show the input that caused this local failure. It is not an EA entry routine. The full test case refuses to initialize outside IsTesting, checks the successful order by ticket, reads back its open price, closes the simulated position and requires every expected result before printing PASS. The change in this test case was to stop altering a valid terminal quote. It was not a general instruction to round every value. For a real EA, first select the correct symbol and request type. Read fresh prices for that symbol. Validate calculated pending prices and stops against their own requirements. If alignment moves a level, check that the resulting request still represents the rule you intended to trade. ResetLastError before the attempt and capture GetLastError immediately afterward. Other calls can change the saved error. Treat a failed ticket as a failed attempt, not as an open position. If the request is accepted, select the returned ticket and read the stored values. That gives you evidence of what happened instead of relying on a success message alone.

// Native tester test case only. OnInit rejects !IsTesting().
double badPrice = Ask + Point * 0.1234567;
ResetLastError();
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, badPrice,
                       10, 0, 0, "FIX26 invalid", 260026, 0, clrNONE);
int error = GetLastError();
// Observed in this test case: ticket = -1, error = 4107.
// A separate call using current Ask returned a positive ticket and error 0.

Native MT4 offline tester, supplied EURUSD H4 history, 3 May 2021, fixed 20-point spread. One invalid entry and one accepted simulated entry. No XAUUSD diagnosis, broker execution, latency or strategy performance claim.

How you know it is fixed

Negative case: preserve the deliberately invalid input

Run the supplied test case only in the Strategy Tester. Its fractional-point entry must fail with ticket -1 and captured error 4107 in the documented environment. An unexpected result is a failed test, not permission to change the expected number.

Positive case: read back the accepted simulated entry

The current-Ask call must return a positive ticket and error 0. Select that ticket again and compare its stored entry with the requested Ask. Close the simulated position and keep the complete result log.

Your five-minute source check

Find the failing OrderSend. Print its symbol, operation, entry, stop, target, Digits, Point, symbol price increment, Bid and Ask. Keep enough precision to expose the actual arguments. Check all three price fields before changing rounding or retry behaviour.

Your own source

Find the next line to check

Start with the free EA-Check. Your code stays in your browser. It highlights patterns with line numbers; it does not prove the broker accepts an order.

Check my EA locally

Want one small change shown on your own case?

DEMO0: send the problem and try a free compiled demo first. R49: one authorised, reproducible MT4/MT5 defect in readable source up to 500 lines, with three agreed cases. 49 USD fixed. Delivery within 48 hours after source review and funding. The exact case is agreed before funded work.

Send the expected and actual behaviour

Common questions

Does 4107 prove that my broker rejected the order?

The number alone does not establish a broker-side rejection. Keep the exact request and local return value. This offline test case reproduced 4107 without sending any account order.

Will NormalizeDouble fix every invalid-price report?

No. Decimal precision, the symbol price increment, request direction and stop distances are separate checks. The right correction depends on the actual failing field and intended rule.

Did this test solve the original XAUUSD report?

No. The original report did not include enough source and symbol details. This is an independently reproduced EURUSD precision failure with an explicit before-and-after check.

Sources and limits

These public questions explain the error; use your own EA log to check whether the same cause applies.

Trading risk disclosure

Futures and forex trading contains substantial risk and is not for every investor. An investor could potentially lose all or more than the initial investment. Risk capital is money that can be lost without jeopardizing one's financial security or lifestyle. Only risk capital should be used for trading, and only those with sufficient risk capital should consider trading. Past performance is not necessarily indicative of future results.

Hypothetical performance disclosure

Hypothetical performance results have many inherent limitations. No representation is being made that any account will or is likely to achieve profits or losses similar to those shown. There are frequently sharp differences between hypothetical performance results and the actual results subsequently achieved by any particular trading program. Hypothetical results are generally prepared with the benefit of hindsight, do not involve financial risk, and cannot completely account for the impact of financial risk in actual trading. Market conditions, the ability to withstand losses, and adherence to a trading program can all materially affect actual results.

NinjaTrader trademark disclosure

NinjaTrader® is a registered trademark of NinjaTrader Group, LLC. No NinjaTrader company has any affiliation with the owner, developer, or provider of the products or services described herein, or any interest, ownership or otherwise, in any such product or service, or endorses, recommends or approves any such product or service.

Testimonials, when shown, may not represent the experience of other clients and are not a guarantee of future performance or success. Virtual-currency trading carries additional risks. See the CFTC customer advisories. Read the full financial risk disclaimer.