@@ -71,7 +71,6 @@ namespace mt_bridge {
71
71
template <class CANDLE_TYPE = MtCandle>
72
72
class MetatraderBridge {
73
73
private:
74
- // std::thread thread_server;
75
74
std::future<void > server_future; /* *< Поток сервера */
76
75
std::future<void > callback_future;
77
76
@@ -185,7 +184,7 @@ namespace mt_bridge {
185
184
uint32_t index_array_offset_timestamp_count = 0 ;
186
185
double last_offset_timestamp_sum = 0 ;
187
186
std::atomic<double > offset_timestamp; /* *< Смещение метки времени */
188
- std::atomic<bool > is_autoupdate_logger_offset_timestamp;
187
+ std::atomic<int64_t > offset_timezone; /* *< Смещение метки времени из-за часового пояса (это значение надо прибавлять к времени сервера) */
189
188
190
189
/* * \brief Обновить смещение метки времени
191
190
*
@@ -211,7 +210,16 @@ namespace mt_bridge {
211
210
(double )array_offset_timestamp_size;
212
211
}
213
212
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 (
215
223
const uint32_t &day,
216
224
const uint32_t &month,
217
225
const uint32_t &year,
@@ -259,11 +267,36 @@ namespace mt_bridge {
259
267
260
268
public:
261
269
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
+
262
281
/* * \brief Получить время сервера с дробной частью
263
282
* \return время сервера
264
283
*/
265
284
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;
267
300
}
268
301
269
302
// / Типы События
@@ -300,8 +333,9 @@ namespace mt_bridge {
300
333
server_timestamp = 0 ;
301
334
last_server_timestamp = 0 ;
302
335
offset_timestamp = 0 ;
336
+ offset_timezone = 0 ;
337
+
303
338
/* запустим соединение в отдельном потоке */
304
- // thread_server = std::thread([&, port]{
305
339
server_future = std::async (std::launch::async,[&, port]() {
306
340
while (!is_stop_command) {
307
341
/* создадим соединение */
@@ -373,14 +407,19 @@ namespace mt_bridge {
373
407
const double close = connection->read_double ();
374
408
375
409
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
+
377
415
/* сохраняем тик */
378
416
{
379
417
std::lock_guard<std::mutex> lock (symbol_tick_mutex);
380
418
symbol_bid[s] = bid;
381
419
symbol_ask[s] = ask;
382
420
symbol_timestamp[s] = timestamp;
383
421
}
422
+
384
423
/* сохраняем бар */
385
424
{
386
425
std::lock_guard<std::mutex> lock (array_candles_mutex);
@@ -396,11 +435,29 @@ namespace mt_bridge {
396
435
array_candles[s].back ().timestamp = timestamp;
397
436
}
398
437
}
399
- }
438
+ } // for s
439
+
400
440
/* читаем метку времени сервера */
401
441
server_timestamp = connection->read_uint64 ();
402
442
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
+ /* если метка времени поменялась, найдем истинное время сервера */
404
461
if (last_server_timestamp != server_timestamp) {
405
462
last_server_timestamp = (uint64_t )server_timestamp;
406
463
double pc_time = get_ftimestamp ();
@@ -426,12 +483,12 @@ namespace mt_bridge {
426
483
}
427
484
const uint32_t DELAY_WAIT = 1000 ;
428
485
std::this_thread::sleep_for (std::chrono::milliseconds (DELAY_WAIT));
429
- }
486
+ } // while
430
487
});
431
- // thread_server.detach();
488
+
432
489
if (callback == nullptr ) return ;
490
+
433
491
/* создаем поток обработки событий */
434
- // std::thread stream_thread = std::thread([&,number_bars, callback] {
435
492
callback_future = std::async (std::launch::async,[&, number_bars, callback]() {
436
493
while (!is_mt_connected) {
437
494
std::this_thread::yield ();
@@ -442,7 +499,7 @@ namespace mt_bridge {
442
499
uint32_t hist_data_number_bars = number_bars;
443
500
while (!is_stop_command) {
444
501
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;
446
503
std::vector<std::map<std::string, CANDLE_TYPE>> hist_array_candles;
447
504
init_historical_data (hist_array_candles, init_date_timestamp, hist_data_number_bars);
448
505
/* далее отправляем загруженные данные в callback */
@@ -455,7 +512,7 @@ namespace mt_bridge {
455
512
timestamp);
456
513
}
457
514
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) -
459
516
SECONDS_IN_MINUTE;
460
517
if (end_date_timestamp == init_date_timestamp) break ;
461
518
hist_data_number_bars = (end_date_timestamp - init_date_timestamp) / SECONDS_IN_MINUTE;
@@ -568,23 +625,23 @@ namespace mt_bridge {
568
625
/* * \brief Подождать соединение
569
626
*
570
627
* Данный метод ждет, пока не установится соединение
628
+ * \param callback Лямбда функция, которая вызывается каждую секунду ожидания (время вызова функции обладает низкой точностью!)
571
629
* \return вернет true, если соединение есть, иначе произошла ошибка
572
630
*/
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 ;
574
635
while (!is_error && !is_mt_connected) {
575
636
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);
577
641
}
578
642
return is_mt_connected;
579
643
}
580
644
581
- /* * \brief Получить метку времени сервера MetaTrader
582
- * \return Метка времени сервера MetaTrader
583
- */
584
- inline uint64_t get_server_timestamp () {
585
- return server_timestamp;
586
- }
587
-
588
645
inline bool update_server_timestamp () {
589
646
if (!is_mt_connected) return false ;
590
647
static uint64_t last_server_timestamp = 0 ;
0 commit comments