Clarification of MT5 Python timestamps and Bars CSV spread

Hello,

I am validating historical data from MT5 and need clarification of timestamp and spread-field definitions. Tickmill confirmed that its desktop Bars CSV timestamps use broker server time (GMT+2 in winter, GMT+3 in summer) and that the <SPREAD> field is measured in MT5 points. Tickmill could not confirm how the bar spread is calculated or the Python API timestamp basis.

Could you please confirm:
1. Are time and time_msc returned by copy_rates_from(), copy_rates_range(), copy_rates_from_pos(), copy_ticks_from(), copy_ticks_range(), and symbol_info_tick() UTC Unix epoch values, independent of broker server timezone?
2. For Python API requests, should datetime boundaries be timezone-aware UTC? How are timezone-naive datetime values interpreted, and are numeric boundaries UTC Unix timestamps?
3. In the desktop Market Watch > Symbols > Bars CSV export, what does <SPREAD> represent for each bar (for example, a value at a specific time or an aggregation)? What does 0 mean?
4. Are the exported Forex OHLC prices Bid-based, and do these definitions also apply to older historical data?

Environment: MT5 terminal build 6235; MetaTrader5 Python package 5.0.6231. This is a data-format question, not a request for trading advice.

Thank you.
Update (read-only observation, 13 Oct 2026): The local PC clock was 2026-10-13 20:41:27 at UTC+03:00 (17:41:27 UTC); an independent UTC reference read 17:41:48 UTC shortly afterward.

For EURUSD, symbol_info_tick returned time=1791924084 and time_msc=1791924084230. Interpreted as Unix UTC epochs, these are 20:41:24 UTC and 20:41:24.230 UTC, about three hours ahead of the PC's UTC clock. copy_rates_from_pos("EURUSD", M1, 0, 3) returned raw times 1791923940, 1791924000, and 1791924060, which convert to 20:39, 20:40, and 20:41 UTC, also about three hours ahead.

The copy_ticks_from sample was requested from an aware UTC time ten minutes before the system clock, with count=5. It returned five ticks around 17:31:27 UTC, near the start of that requested interval, so these are not a like-for-like current-time comparison.

No orders were sent and no positions were opened. Could you clarify the expected timestamp basis for symbol_info_tick and copy_rates_from_pos on this broker/server and terminal build? Should these returned epoch values be treated as UTC as documented, or is the observed three-hour difference expected? I preserved the raw values and have not applied an offset.
Further read-only comparison (same EURUSD window; all request datetimes were timezone-aware UTC):
- copy_ticks_range returned 320 ticks from 17:47:15.682Z to 17:52:16.736Z. copy_ticks_from(start=17:47:12Z, count=5) returned the first five near the start of that interval, as expected.
- copy_rates_from and copy_rates_range returned bars aligned with the UTC request window (17:48Z through 17:52Z).
- In contrast, symbol_info_tick().time/time_msc converted as Unix UTC were 10,800 seconds ahead of the local system's UTC reference; copy_rates_from_pos returned M1 bar times 20:50Z–20:52Z while the same bars from the time-based calls were 17:50Z–17:52Z.
- No orders were sent or positions opened. Raw values were preserved and no offset correction was applied.

This appears to isolate the observed three-hour discrepancy to symbol_info_tick and copy_rates_from_pos in this environment, while the time-bounded tick/rate calls align with UTC. Is this expected behavior or a known issue for this terminal/Python package/server combination?
Correction to my previous update: I described the time-bounded calls as UTC-aligned because their returned labels fell inside the UTC request window. That was not enough to establish the timestamps' time basis. A follow-up read-only comparison found no matching quote/bar signatures between symbol_info_tick / copy_rates_from_pos and the time-bounded results, so those records were not proven to be the same events with a three-hour label shift. I am testing whether UTC and candidate broker-server-time request windows select the current records. Please disregard my earlier inference that the time-bounded results were confirmed UTC. No orders were sent, no positions were opened, and no offset correction has been applied.

Read-only follow-up, 13 Oct 2026: I repeated the comparison using five closed EURUSD M1 bars ( copy_rates_from_pos , start_pos=1 ) to exclude the still-forming candle. With timezone-aware UTC boundaries, copy_rates_range returned 12 bars and none matched the five position bars by timestamp and OHLC/volume/spread signature. Shifting the same 12-minute request window by +3 hours returned 10 bars and matched all five bars exactly; every timestamp offset was 0 seconds. No orders were sent and no positions were opened. This is a reproducible observation for the current Tickmill-Demo summer-time setup, but it does not establish winter-time or historical behavior. No timestamp correction has been applied. Is this expected or a known issue despite the Python documentation specifying UTC?

Read-only follow-up, 13 Oct 2026:

I compared the same EURUSD M1 time window using both timezone-aware UTC datetime boundaries and the equivalent numeric Unix-second boundaries. Each UTC query returned 12 bars and matched none of the five most recent closed bars returned by copy_rates_from_pos(start_pos=1).

I then shifted the same boundaries by +3 hours. Both the timezone-aware datetime query and the equivalent numeric Unix-second query returned 10 bars and matched all five closed bars exactly by timestamp and OHLC/volume/spread signature; every timestamp difference was zero.

This suggests the result is not caused solely by Python datetime conversion. For this current Tickmill-Demo setup, the +3-hour candidate window selects the same bars as copy_rates_from_pos. Is this expected behavior for this server/build despite the documentation specifying UTC?

No orders were sent, no positions were opened, and no timestamp correction has been applied.
Correction and historical follow-up, 14 Oct 2026:

Correction: the terminal build used for the guarded Tickmill-Demo tests was 6231 (Python package 5.0.6231); the opening post's build number 6235 was incorrect.

I later compared historical `copy_rates_range` results with the same-terminal `EURUSDM1.csv`. UTC-aware request boundaries matched the CSV's five-bar OHLC/tick-volume signatures without shifting the request window for 2025-01-15, 2025-10-28, and 46 selected windows across 2019–2026. Equivalent integer Unix-second request boundaries returned identical results. This confirms same-source bar/label alignment only; it does not establish the absolute UTC instant represented by the returned raw timestamps.

Therefore, my +3-hour observation in comments #4 and #5 is limited to the specific recent `copy_rates_from_pos` versus `copy_rates_range` comparison and should not be generalized to all historical dates or API calls. No offset correction has been applied; raw timestamps are preserved.