Skip to content

Commit f8ce7ec

Browse files
committed
исправлен баг с меткой времени метатрейдера. Теперь метка времени не привязана к часовому поясу метатрейдера, а соответствует GMT/UTC
1 parent af1c209 commit f8ce7ec

File tree

4 files changed

+95
-28
lines changed

4 files changed

+95
-28
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "lib/libp7-baical"]
88
path = lib/libp7-baical
99
url = https://github.com/CMakePorts/libp7-baical.git
10+
[submodule "lib/xtime_cpp"]
11+
path = lib/xtime_cpp
12+
url = https://github.com/NewYaroslav/xtime_cpp.git

code-blocks/example_callback/main.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <iostream>
22
#include <mt-bridge.hpp>
3+
#include <xtime.hpp>
34

45
int main() {
56
const uint32_t port = 5555;
@@ -10,23 +11,28 @@ int main() {
1011
const mt_bridge::MtBridge::EventType event,
1112
const uint64_t timestamp) {
1213
mt_bridge::MtCandle candle = mt_bridge::MtBridge::get_candle("EURUSD", candles);
14+
std::cout << "utc: " << xtime::get_str_date_time() << std::endl;
15+
std::cout << "server utc: " << xtime::get_str_date_time(iMT.get_server_ftimestamp()) << std::endl;
16+
std::cout << "server raw: " << xtime::get_str_date_time(iMT.get_raw_server_timestamp()) << std::endl;
17+
std::cout << "offset: " << iMT.get_offset_timestamp() << std::endl;
18+
1319
switch(event) {
1420
case mt_bridge::MtBridge::EventType::HISTORICAL_DATA_RECEIVED:
15-
std::cout << "history bar: " << timestamp << " minute day: " << ((timestamp / 60) % 1440) << std::endl;
21+
std::cout << "history bar: " << xtime::get_str_date_time(timestamp) << " minute day: " << ((timestamp / 60) % 1440) << std::endl;
1622
if(mt_bridge::MtBridge::check_candle(candle)) {
1723
std::cout << "EURUSD, close: " << candle.close
1824
<< " volume: " << candle.volume
19-
<< " t: " << candle.timestamp << std::endl;
25+
<< " t: " << xtime::get_str_date_time(candle.timestamp) << std::endl;
2026
} else {
2127
std::cout << "EURUSD, error"<< std::endl;
2228
}
2329
break;
2430
case mt_bridge::MtBridge::EventType::NEW_TICK:
25-
std::cout << "news tick: " << timestamp << std::endl;
31+
std::cout << "new tick: " << xtime::get_str_date_time(timestamp) << std::endl;
2632
if(mt_bridge::MtBridge::check_candle(candle)) {
2733
std::cout << "EURUSD, close: " << candle.close
2834
<< " volume: " << candle.volume
29-
<< " t: " << candle.timestamp << std::endl;
35+
<< " t: " << xtime::get_str_date_time(candle.timestamp) << std::endl;
3036
} else {
3137
std::cout << "EURUSD, error"<< std::endl;
3238
}
@@ -36,11 +42,11 @@ int main() {
3642
/* просто проверяем */
3743
std::map<std::string, mt_bridge::MtCandle> candles_2 = iMT.get_candles(timestamp);
3844
mt_bridge::MtCandle candle_2 = mt_bridge::MtBridge::get_candle("EURUSD", candles_2);
39-
std::cout << "news candle: " << timestamp << std::endl;
45+
std::cout << "new candle: " << xtime::get_str_date_time(timestamp) << std::endl;
4046
if(mt_bridge::MtBridge::check_candle(candle_2)) {
4147
std::cout << "EURUSD, close: " << candle_2.close
4248
<< " volume: " << candle_2.volume
43-
<< " t: " << candle_2.timestamp << std::endl;
49+
<< " t: " << xtime::get_str_date_time(candle_2.timestamp) << std::endl;
4450
} else {
4551
std::cout << "EURUSD, error (candle_2)"<< std::endl;
4652
}

include/mt-bridge.hpp

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ namespace mt_bridge {
7171
template<class CANDLE_TYPE = MtCandle>
7272
class MetatraderBridge {
7373
private:
74-
//std::thread thread_server;
7574
std::future<void> server_future; /**< Поток сервера */
7675
std::future<void> callback_future;
7776

@@ -185,7 +184,7 @@ namespace mt_bridge {
185184
uint32_t index_array_offset_timestamp_count = 0;
186185
double last_offset_timestamp_sum = 0;
187186
std::atomic<double> offset_timestamp; /**< Смещение метки времени */
188-
std::atomic<bool> is_autoupdate_logger_offset_timestamp;
187+
std::atomic<int64_t> offset_timezone; /**< Смещение метки времени из-за часового пояса (это значение надо прибавлять к времени сервера) */
189188

190189
/** \brief Обновить смещение метки времени
191190
*
@@ -211,7 +210,16 @@ namespace mt_bridge {
211210
(double)array_offset_timestamp_size;
212211
}
213212

214-
inline uint64_t get_timestamp(
213+
/** \brief Обновить смещение метки времени из-за часового пояса
214+
*
215+
* \param t смещение метки времени
216+
*/
217+
inline void update_offset_timezone(const uint64_t t) {
218+
int64_t temp = (int64_t)((std::abs((double)get_timestamp() - (double)t) / 900.0d) + 0.5d) * 900;
219+
offset_timezone = get_timestamp() > t ? temp : -temp;
220+
}
221+
222+
inline uint64_t get_timestamp(
215223
const uint32_t &day,
216224
const uint32_t &month,
217225
const uint32_t &year,
@@ -259,11 +267,36 @@ namespace mt_bridge {
259267

260268
public:
261269

270+
inline double get_offset_timestamp() {
271+
return offset_timestamp;
272+
}
273+
274+
/** \brief Получить время сервера с дробной частью в часовом поясе терминала
275+
* \return время сервера
276+
*/
277+
inline double get_server_ftimestamp_with_timezone() {
278+
return get_ftimestamp() + offset_timestamp;
279+
}
280+
262281
/** \brief Получить время сервера с дробной частью
263282
* \return время сервера
264283
*/
265284
inline double get_server_ftimestamp() {
266-
return get_ftimestamp() + offset_timestamp;
285+
return get_ftimestamp() + offset_timestamp + offset_timezone;
286+
}
287+
288+
/** \brief Получить метку времени сервера MetaTrader
289+
* \return Метка времени сервера MetaTrader
290+
*/
291+
inline uint64_t get_server_timestamp() {
292+
return server_timestamp + offset_timezone;
293+
}
294+
295+
/** \brief Получить метку времени сервера MetaTrader
296+
* \return Метка времени сервера MetaTrader
297+
*/
298+
inline uint64_t get_raw_server_timestamp() {
299+
return server_timestamp;
267300
}
268301

269302
/// Типы События
@@ -300,8 +333,9 @@ namespace mt_bridge {
300333
server_timestamp = 0;
301334
last_server_timestamp = 0;
302335
offset_timestamp = 0;
336+
offset_timezone = 0;
337+
303338
/* запустим соединение в отдельном потоке */
304-
//thread_server = std::thread([&, port]{
305339
server_future = std::async(std::launch::async,[&, port]() {
306340
while(!is_stop_command) {
307341
/* создадим соединение */
@@ -373,14 +407,19 @@ namespace mt_bridge {
373407
const double close = connection->read_double();
374408

375409
const uint64_t volume = connection->read_uint64();
376-
const uint64_t timestamp = connection->read_uint64();
410+
uint64_t timestamp = connection->read_uint64();
411+
412+
/* если смещение метки времени из-за часового пояса уже известно, учтем это смещение */
413+
if(read_len > 0) timestamp += offset_timezone;
414+
377415
/* сохраняем тик */
378416
{
379417
std::lock_guard<std::mutex> lock(symbol_tick_mutex);
380418
symbol_bid[s] = bid;
381419
symbol_ask[s] = ask;
382420
symbol_timestamp[s] = timestamp;
383421
}
422+
384423
/* сохраняем бар */
385424
{
386425
std::lock_guard<std::mutex> lock(array_candles_mutex);
@@ -396,11 +435,29 @@ namespace mt_bridge {
396435
array_candles[s].back().timestamp = timestamp;
397436
}
398437
}
399-
}
438+
} // for s
439+
400440
/* читаем метку времени сервера */
401441
server_timestamp = connection->read_uint64();
402442

403-
/* если метка времени поменялась, найдем время сервера */
443+
/* если читаем данные в первый раз, обновим метку времени для всех баров */
444+
if(read_len == 0) {
445+
/* обновляем смещение метки времени из-за часового пояса */
446+
update_offset_timezone(server_timestamp);
447+
448+
for(uint32_t s = 0; s < num_symbol; ++s) {
449+
{
450+
std::lock_guard<std::mutex> lock(symbol_tick_mutex);
451+
symbol_timestamp[s] += offset_timezone;
452+
}
453+
std::lock_guard<std::mutex> lock(array_candles_mutex);
454+
for(uint32_t i = 0; i < array_candles[s].size(); ++i) {
455+
array_candles[s][i].timestamp += offset_timezone;
456+
}
457+
}
458+
}
459+
460+
/* если метка времени поменялась, найдем истинное время сервера */
404461
if(last_server_timestamp != server_timestamp) {
405462
last_server_timestamp = (uint64_t)server_timestamp;
406463
double pc_time = get_ftimestamp();
@@ -426,12 +483,12 @@ namespace mt_bridge {
426483
}
427484
const uint32_t DELAY_WAIT = 1000;
428485
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_WAIT));
429-
}
486+
} // while
430487
});
431-
//thread_server.detach();
488+
432489
if(callback == nullptr) return;
490+
433491
/* создаем поток обработки событий */
434-
//std::thread stream_thread = std::thread([&,number_bars, callback] {
435492
callback_future = std::async(std::launch::async,[&, number_bars, callback]() {
436493
while(!is_mt_connected) {
437494
std::this_thread::yield();
@@ -442,7 +499,7 @@ namespace mt_bridge {
442499
uint32_t hist_data_number_bars = number_bars;
443500
while(!is_stop_command) {
444501
const uint64_t init_date_timestamp =
445-
((server_timestamp / SECONDS_IN_MINUTE) * SECONDS_IN_MINUTE) - SECONDS_IN_MINUTE;
502+
(((server_timestamp + offset_timezone) / SECONDS_IN_MINUTE) * SECONDS_IN_MINUTE) - SECONDS_IN_MINUTE;
446503
std::vector<std::map<std::string, CANDLE_TYPE>> hist_array_candles;
447504
init_historical_data(hist_array_candles, init_date_timestamp, hist_data_number_bars);
448505
/* далее отправляем загруженные данные в callback */
@@ -455,7 +512,7 @@ namespace mt_bridge {
455512
timestamp);
456513
}
457514
const uint64_t end_date_timestamp =
458-
((server_timestamp / SECONDS_IN_MINUTE) * SECONDS_IN_MINUTE) -
515+
(((server_timestamp + offset_timezone) / SECONDS_IN_MINUTE) * SECONDS_IN_MINUTE) -
459516
SECONDS_IN_MINUTE;
460517
if(end_date_timestamp == init_date_timestamp) break;
461518
hist_data_number_bars = (end_date_timestamp - init_date_timestamp) / SECONDS_IN_MINUTE;
@@ -568,23 +625,23 @@ namespace mt_bridge {
568625
/** \brief Подождать соединение
569626
*
570627
* Данный метод ждет, пока не установится соединение
628+
* \param callback Лямбда функция, которая вызывается каждую секунду ожидания (время вызова функции обладает низкой точностью!)
571629
* \return вернет true, если соединение есть, иначе произошла ошибка
572630
*/
573-
inline bool wait() {
631+
inline bool wait(std::function<void(const uint64_t second)> callback = nullptr) {
632+
uint64_t tick = 0;
633+
const uint64_t WAIT_DELAY = 10;
634+
const uint64_t MS_IN_SECOND = 1000;
574635
while(!is_error && !is_mt_connected) {
575636
std::this_thread::yield();
576-
std::this_thread::sleep_for(std::chrono::milliseconds(10));
637+
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_DELAY));
638+
if(callback == nullptr) continue;
639+
tick += WAIT_DELAY;
640+
if((tick % MS_IN_SECOND) == 0) callback(tick / MS_IN_SECOND);
577641
}
578642
return is_mt_connected;
579643
}
580644

581-
/** \brief Получить метку времени сервера MetaTrader
582-
* \return Метка времени сервера MetaTrader
583-
*/
584-
inline uint64_t get_server_timestamp() {
585-
return server_timestamp;
586-
}
587-
588645
inline bool update_server_timestamp() {
589646
if(!is_mt_connected) return false;
590647
static uint64_t last_server_timestamp = 0;

lib/xtime_cpp

Submodule xtime_cpp added at 41e21fc

0 commit comments

Comments
 (0)