Анализ рынка на SQL в реальном времени.

 

Добрый день!

Сделал проект хранилища данных для анализа рынков на основе СУБД TimescaleDB – расширении Postgres для работы с временными рядами. (в прошлом разрабатывал корпоративны DWH и ETL на Oracle, так что "немного" шарю в хранилищах)

Устанавливается через docker compose в несколько простых команд.

После первого запуска стека docker вы получите готовую базу данных (изначально заполнены только справочники), которая начнёт немедленно заполнять данными в реальном времени. База данных сохраняется между перезапусками, разумеется.

Как это работает на верхнем уровне.

При помощи особенного кунг-фу "real-time web pumps (parsers)" данные собираются из нескольких открытых онлайн источников (ask, bid, last) в реальном времени (средняя скорость 200+ тик/с, в пике свыше 1000 тик/с) и помещаются в брокер сообщений NATS.

Запущенные вами контейнеры подключаются к брокеру NATS, забирают данные, буферизуют/троттлят их, и с заданной периодичностью (по умолчанию 1 сек) скидывают в базу данных.

Например, за секунду из NATS пришло
USDZAR – 22 тика, USDNOK – 28 тиков, EURGBP – 8 тиков.
в конце секунды в БД будет сброшено по одному последнему значению, для каждой валютной пары (при этом кол-во прошедших тиков также записывается).

Это позволяет с одной стороны иметь приблизительную, но статистически точную картину рынка, с другой стороны, позволяет базе данных "дышать" и обслуживать пользовательские запросы даже с 1-2 CPU.


Проект только запустил на той неделе.

Сейчас по одной самой большой исторической таблице в моей бд статистика такая:

select date_trunc('day', q.evts) as day,
       count(*) as row_cnt,
       sum(q.tick_cnt) as tick_cnt
from mql.quotes q
group by date_trunc('day', q.evts)
order by day    


#|day                          |row_cnt|tick_cnt|
-+-----------------------------+-------+--------+
1|2026-07-23 00:00:00.000 +0300|3843334|15473287|
2|2026-07-24 00:00:00.000 +0300|3919000|14680917|
3|2026-07-27 00:00:00.000 +0300|4162471|15687260|
4|2026-07-28 00:00:00.000 +0300|2561287| 8971931|

select hypertable_size('mql.quotes')::numeric/1024/1024 AS mb;
#|mb                  |
-+--------------------+
1|534.2734375000000000| 


Гипертаблицы (таблицы фактов в терминах TimescaleDB) партицированны по дате evts с шагом 1 час. По умолчанию настроено так, что через 3 часа партиции сжимаются и переводятся в колоночный формат. Можно настроить retention policy, чтобы автоматически удалять данные старше определенного интервала.

select add_retention_policy(relation=>'qml.quotes', drop_after=>interval'3 month', schedule_interval=>interval'1 day');

 

Преимущества использования промышленной СУБД очевидны.

Клиент-сервер. Одна база на VPS или на постоянно включённом компьютере к которой можно подключаться откуда угодно большому кол-ву аналитиков.

SQL знают все, а коннекторов подключения к Postgres навалом в любом языке.

 

Как установить.

Вы должны уметь в командную строку, Docker и желательно в git (чтобы скачивать обновления в будущем).

 

Попробовать проще всего на Docker Desktop (windows).

Выберите папку, где будет располагаться проект (в проекте будет немного текстовых файлов, сама БД будет жить в docker volume)

1.

git clone https://github.com/pv14mn/webdwh_client.git

cd webdwh_client

или просто скачайте и распакуйте https://github.com/pv14mn/webdwh_client/archive/refs/heads/main.zip

и перейдите в командной строке папку webdwh_client

2.

docker compose pull --policy missing

если предыдущая команда не найдет образ под вашу архитектуру, например, если вы на Mac, то надо будет сделать

docker compose build

3.

docker compose up -d timescaledb

(перед этим можете поменять пароли, с которыми будут созданы пользователи бд: postgres, webdwh, viewer в файле ./timescaledb/.env.db.auth.txt)

подождите 5-10 сек, пока пустая база данных создастся

4.

docker compose run --rm db-init

это создаст схемы и таблицы, и заполнит справочники в БД.

5.

! теперь необходимо прописать параметры подключения к брокеру сообщений

откройте текстовый файл
./
node/.env.nats.auth.txt
и вставьте в него

NATS_URL=nats://104.171.138.245:4222
NATS_ENGINE=core
NATS_USER_PUBLIC=UACAUQJ4W2NDUHYQXONWPB4PSBB6UH3IEFB2S6U7CJA2Z5YTY7R4IPK5
NATS_USER_SECRET=SUAFWGEW4KKE4EFNPXA6YV6UAIUP3YTOK2A2DNDPS4Z4LYAP5GIUOTKTNM
NATS_CONS_SECRET=

6.

ну и финальный запуск:

docker compose up -d

 

=====

Подключиться можно вашим любимым sql клиентом на порту 5400.

логин/пароль = webdwh/webdwh по умолчанию (или postgrs/postgres (для администрирования), или viewer/viewer (только для просмотра данных)).

Посмотреть последний слепок рынка Forex на сейчас можно запросом

select t.description, t.scode, q.evts, q.ask, q.bid, q.tick_cnt
  from mql.quotes_last q
  join mql.tickers t
    on t.icode = q.icode
where 1=1
  --and t.scode = 'AUDUSD'
order by q.evts desc

#  |description                                 |scode |evts                         |ask      |bid      |tick_cnt|
---+--------------------------------------------+------+-----------------------------+---------+---------+--------+
1  |Новозеландский доллар / Канадский доллар    |NZDCAD|2026-07-28 16:30:14.779 +0300|  0.81429|  0.81424|       8|
2  |Евро / Гонконгский доллар                   |EURHKD|2026-07-28 16:30:14.779 +0300|  8.91475|  8.91458|       6|
3  |Евро / Австралийский доллар                 |EURAUD|2026-07-28 16:30:14.777 +0300|  1.63071|  1.63068|      13|
4  |Доллар США / Мексиканское песо              |USDMXN|2026-07-28 16:30:14.767 +0300| 17.46614| 17.46557|      26|
5  |Австралийский доллар / Новозеландский доллар|AUDNZD|2026-07-28 16:30:14.757 +0300|  1.20775|  1.20771|       9|
6  |Фунт стерлингов / Японская иена             |GBPJPY|2026-07-28 16:30:14.757 +0300|  217.922|  217.914|      18|
7  |Канадский доллар / Японская иена            |CADJPY|2026-07-28 16:30:14.757 +0300|  116.173|  116.165|       8|
8  |Австралийский доллар / Канадский доллар     |AUDCAD|2026-07-28 16:30:14.756 +0300|  0.98342|  0.98337|      11|
9  |Евро / Новозеландский доллар                |EURNZD|2026-07-28 16:30:14.738 +0300|  1.96948|   1.9694|       8|
10 |Фунт стерлингов / Новозеландский доллар     |GBPNZD|2026-07-28 16:30:14.737 +0300|  2.30386|  2.30377|       9|
11 |Австралийский доллар / Японская иена        |AUDJPY|2026-07-28 16:30:14.736 +0300|   114.24|  114.237|      12|
12 |Фунт стерлингов / Канадский доллар          |GBPCAD|2026-07-28 16:30:14.727 +0300|  1.87592|  1.87585|      10|
13 |Доллар США / Канадский доллар               |USDCAD|2026-07-28 16:30:14.726 +0300|  1.41069|  1.41067|       8|
14 |Норвежская крона / Японская иена            |NOKJPY|2026-07-28 16:30:14.721 +0300|   16.907|   16.905|       3|
15 |Доллар США / Южноафриканский рэнд           |USDZAR|2026-07-28 16:30:14.718 +0300| 16.75069|  16.7486|      23|
16 |Доллар США / Венгерский форинт              |USDHUF|2026-07-28 16:30:14.718 +0300|   317.37|  317.305|      11|
17 |Доллар США / Новый израильский шекель       |USDILS|2026-07-28 16:30:14.717 +0300|  3.05956|  3.05106|       3|
18 |Новозеландский доллар / Сингапурский доллар |NZDSGD|2026-07-28 16:30:14.705 +0300|  0.74648|  0.74642|       5|
19 |Канадский доллар / Швейцарский франк        |CADCHF|2026-07-28 16:30:14.705 +0300|  0.58079|   0.5807|       1|
20 |Евро / китайский офшорный юань              |EURCNH|2026-07-28 16:30:14.705 +0300|  7.69908|  7.69889|       4|
21 |US Dollar vs Brazilian Real                 |USDBRL|2026-07-28 16:30:14.691 +0300|   5.1541|   5.1526|       5|
22 |Фунт стерлингов / Швейцарский франк         |GBPCHF|2026-07-28 16:30:14.687 +0300|  1.08944|  1.08941|       5|
23 |Фунт стерлингов / Австралийский доллар      |GBPAUD|2026-07-28 16:30:14.687 +0300|  1.90759|   1.9075|      18|
24 |Доллар США / Норвежская крона               |USDNOK|2026-07-28 16:30:14.680 +0300|   9.6937|   9.6929|      16|
25 |Фунт стерлингов / Норвежская крона          |GBPNOK|2026-07-28 16:30:14.680 +0300|  12.8928|  12.8882|       3|
26 |Швейцарский франк / Венгерский форинт       |CHFHUF|2026-07-28 16:30:14.665 +0300|  387.477|   387.26|       1|
27 |Австралийский доллар / Доллар США           |AUDUSD|2026-07-28 16:30:14.657 +0300|  0.69712|  0.69711|       9|
28 |Евро / Южноафриканский рэнд                 |EURZAR|2026-07-28 16:30:14.654 +0300| 19.04584| 19.03826|      16|
29 |Евро / Мексиканское песо                    |EURMXN|2026-07-28 16:30:14.654 +0300| 19.85756| 19.85368|       6|
30 |Фунт стерлингов / Датская крона             |GBPDKK|2026-07-28 16:30:14.643 +0300|   8.7452|   8.7432|       2|
31 |Евро / Шведская крона                       |EURSEK|2026-07-28 16:30:14.643 +0300| 11.06448| 11.06278|      13|
32 |Australian Dollar vs Danish Krona           |AUDDKK|2026-07-28 16:30:14.628 +0300|  4.58787|  4.58037|      10|
33 |Фунт стерлингов / Мексиканское песо         |GBPMXN|2026-07-28 16:30:14.622 +0300|  23.2284|  23.2245|       3|
34 |Евро / Канадский доллар                     |EURCAD|2026-07-28 16:30:14.616 +0300|  1.60366|  1.60362|       6|
35 |Доллар США / Гонконгский доллар             |USDHKD|2026-07-28 16:30:14.607 +0300|   7.8417|  7.84162|       1|
36 |Доллар США / Японская иена                  |USDJPY|2026-07-28 16:30:14.604 +0300|  163.872|  163.869|       8|
37 |US Dollar vs South korean won               |USDKRW|2026-07-28 16:30:14.595 +0300|  1459.51|  1459.15|       4|
38 |Австралийский доллар / Сингапурский доллар  |AUDSGD|2026-07-28 16:30:14.583 +0300|  0.90155|  0.90144|       2|
39 |Australian Dollar vs Hong Kong Dollar       |AUDHKD|2026-07-28 16:30:14.580 +0300|  5.46689|  5.46656|       3|
40 |Chinese Yuan Renminbi vs Japanese Yen       |CNHJPY|2026-07-28 16:30:14.580 +0300|     24.2|   24.196|       1|
41 |Сингапурский доллар / Японская иена         |SGDJPY|2026-07-28 16:30:14.580 +0300|  126.731|  126.715|       1|
42 |Новозеландский доллар / Японская иена       |NZDJPY|2026-07-28 16:30:14.569 +0300|   94.594|   94.588|      10|
43 |Фунт стерлингов / Доллар США                |GBPUSD|2026-07-28 16:30:14.557 +0300|  1.32982|  1.32982|       6|
44 |Евро / Норвежская крона                     |EURNOK|2026-07-28 16:30:14.555 +0300|  11.0201|  11.0189|      11|
45 |Canadian Dollar vs Norwegian Krona          |CADNOK|2026-07-28 16:30:14.530 +0300|  6.87255|  6.87093|       4|
46 |Фунт стерлингов / Южноафриканский рэнд      |GBPZAR|2026-07-28 16:30:14.518 +0300|  22.2785|   22.271|      10|
47 |Швейцарский франк / Японская иена           |CHFJPY|2026-07-28 16:30:14.475 +0300|  200.033|  200.026|       4|
48 |Австралийский доллар / Швейцарский франк    |AUDCHF|2026-07-28 16:30:14.469 +0300|  0.57113|  0.57109|       6|
49 |Евро / Японская иена                        |EURJPY|2026-07-28 16:30:14.445 +0300|  186.294|  186.291|       4|
50 |Фунт стерлингов / Шведская крона            |GBPSEK|2026-07-28 16:30:14.443 +0300|  12.9437|  12.9395|       3|
51 |Фунт стерлингов / Гонконгский доллар        |GBPHKD|2026-07-28 16:30:14.419 +0300|  10.4285| 10.42758|       2|
52 |Доллар США / Чешская крона                  |USDCZK|2026-07-28 16:30:14.418 +0300|  21.2714|  21.2676|      12|
53 |Фунт стерлингов / Сингапурский доллар       |GBPSGD|2026-07-28 16:30:14.378 +0300|  1.71976|  1.71952|       2|
54 |Евро / Польский злотый                      |EURPLN|2026-07-28 16:30:14.367 +0300|  4.32435|  4.32335|       9|
55 |Евро / Доллар США                           |EURUSD|2026-07-28 16:30:14.354 +0300|  1.13682|  1.13682|       1|
56 |Доллар США / Датская крона                  |USDDKK|2026-07-28 16:30:14.308 +0300|  6.57579|  6.57551|       5|
57 |Новозеландский доллар / Доллар США          |NZDUSD|2026-07-28 16:30:14.302 +0300|  0.57721|  0.57721|       9|
58 |Евро / Швейцарский франк                    |EURCHF|2026-07-28 16:30:14.267 +0300|  0.93135|  0.93132|       5|
59 |US Dollar vs Indonesian Rupiah              |USDIDR|2026-07-28 16:30:14.266 +0300|18120.325|18120.325|       2|
60 |Фунт стерлингов / Польский злотый           |GBPPLN|2026-07-28 16:30:14.256 +0300|   5.0589|   5.0501|      16|
61 |Швейцарский франк / Польский злотый         |CHFPLN|2026-07-28 16:30:14.227 +0300|  4.64497|  4.64052|       1|
62 |Доллар США / Польский злотый                |USDPLN|2026-07-28 16:30:14.205 +0300|  3.80366|   3.8033|      13|
63 |US Dollar vs Indian Rupee                   |USDINR|2026-07-28 16:30:14.144 +0300|   96.046|   96.031|       4|
64 |US Dollar vs Chilean Peso                   |USDCLP|2026-07-28 16:30:14.110 +0300|    937.6|    936.9|       1|
65 |Новозеландский доллар / Швейцарский франк   |NZDCHF|2026-07-28 16:30:14.105 +0300|  0.47291|  0.47287|       6|
66 |Доллар США / Швейцарский франк              |USDCHF|2026-07-28 16:30:14.003 +0300|  0.81922|  0.81922|       1|
67 |Доллар США / Шведская крона                 |USDSEK|2026-07-28 16:30:13.993 +0300|   9.7324|   9.7317|       2|
68 |Норвежская крона / Шведская крона           |NOKSEK|2026-07-28 16:30:13.956 +0300|  1.00411|  1.00396|       2|
69 |Евро / Венгерский форинт                    |EURHUF|2026-07-28 16:30:13.869 +0300|  360.833|  360.721|      10|
70 |Канадский доллар / Сингапурский доллар      |CADSGD|2026-07-28 16:30:13.818 +0300|  0.91677|  0.91666|       1|
71 |Фунт стерлингов / Турецкая лира             |GBPTRY|2026-07-28 16:30:13.817 +0300| 63.05926| 63.04143|       1|
72 |Евро / Сингапурский доллар                  |EURSGD|2026-07-28 16:30:13.779 +0300|  1.47015|  1.47003|       4|
73 |Доллар США / китайский офшорный юань        |USDCNH|2026-07-28 16:30:13.729 +0300|  6.77235|  6.77223|       1|
74 |Доллар США / Китайский юань                 |USDRMB|2026-07-28 16:30:13.729 +0300|  6.77235|  6.77223|       1|
75 |Фунт стерлингов / Венгерский форинт         |GBPHUF|2026-07-28 16:30:13.614 +0300|  422.032|  421.807|       1|
76 |Шведская крона / Японская иена              |SEKJPY|2026-07-28 16:30:13.515 +0300|   16.845|   16.833|       1|
77 |Швейцарский франк / Сингапурский доллар     |CHFSGD|2026-07-28 16:30:13.061 +0300|  1.57858|  1.57839|       1|
78 |Швейцарский франк / Шведская крона          |CHFSEK|2026-07-28 16:30:12.981 +0300| 11.88216| 11.87624|       6|
79 |Доллар США / Сингапурский доллар            |USDSGD|2026-07-28 16:30:12.967 +0300|  1.29318|  1.29313|       4|
80 |Евро / Турецкая лира                        |EURTRY|2026-07-28 16:30:12.929 +0300| 53.90273| 53.89604|       2|
81 |Евро / Фунт стерлингов                      |EURGBP|2026-07-28 16:30:12.856 +0300|  0.85489|  0.85488|       4|
82 |Швейцарский франк / Датская крона           |CHFDKK|2026-07-28 16:30:12.784 +0300|  8.02738|  8.02564|       5|
83 |Доллар США / Тайский бат                    |USDTHB|2026-07-28 16:30:12.738 +0300|   33.556|   33.551|       4|
84 |Фунт стерлингов / Чешская крона             |GBPCZK|2026-07-28 16:30:10.995 +0300|  28.3143|  28.2525|       1|
85 |Мексиканское песо / Японская иена           |MXNJPY|2026-07-28 16:30:10.374 +0300|    9.385|    9.382|       1|
86 |Swiss Franc vs South African Rand           |CHFZAR|2026-07-28 16:30:10.339 +0300| 20.45003| 20.44309|       1|
87 |Датская крона / Шведская крона              |DKKSEK|2026-07-28 16:30:10.303 +0300|  1.48025|  1.47972|       1|
88 |Австралийский доллар / Шведская крона       |AUDSEK|2026-07-28 16:30:10.266 +0300|  6.78486|  6.78364|       1|
89 |Australian Dollar vs Norwegian Krona        |AUDNOK|2026-07-28 16:30:10.266 +0300|  6.75788|  6.75678|       1|
90 |Швейцарский франк / Норвежская крона        |CHFNOK|2026-07-28 16:30:09.711 +0300| 11.83271| 11.83073|       1|
91 |Новозеландский доллар / Датская крона       |NZDDKK|2026-07-28 16:30:09.340 +0300|  3.79633|    3.795|       4|
92 |Новозеландский доллар / Шведская крона      |NZDSEK|2026-07-28 16:30:09.304 +0300|  5.61866|  5.61663|       2|
93 |Евро / Датская крона                        |EURDKK|2026-07-28 16:30:08.659 +0300|  7.47547|  7.47534|       2|
94 |Zloty vs Japanese Yen                       |PLNJPY|2026-07-28 16:30:08.233 +0300|   43.104|   43.062|       1|
95 |Доллар США / Турецкая лира                  |USDTRY|2026-07-28 16:30:07.941 +0300|  47.3799|  47.3783|       1|
96 |Гонконгский доллар / Японская иена          |HKDJPY|2026-07-28 16:30:07.682 +0300|     20.9|   20.895|       2|
97 |US Dollar vs Colombian Peso                 |USDCOP|2026-07-28 16:30:07.386 +0300|  3218.28|   3211.2|       2|
98 |Евро / Чешская крона                        |EURCZK|2026-07-28 16:30:06.789 +0300|  24.1815|   24.178|       4|
99 |Сингапурский доллар / Гонконгский доллар    |SGDHKD|2026-07-28 16:30:05.523 +0300|  6.06462|  6.06348|       1|
100|Южноафриканский рэнд / Японская иена        |ZARJPY|2026-07-28 16:30:05.259 +0300|    9.784|    9.782|       2|
101|Турецкая лира / Японская иена               |TRYJPY|2026-07-28 16:30:04.520 +0300|    3.458|    3.455|       1|
102|Australian Dollar vs Zloty                  |AUDPLN|2026-07-28 16:30:03.637 +0300|  2.65583|  2.64733|       1|
103|Евро / Российский рубль                     |EURRUB|2026-07-28 16:25:22.947 +0300|    91.04|    88.62|       1|
104|US Dollar vs Nigerian Naira                 |USDNGN|2026-07-28 16:25:07.417 +0300| 1366.178| 1364.962|       1|
105|Доллар США / Российский рубль               |USDRUB|2026-07-28 16:09:38.445 +0300|   79.225|   77.725|       1|

   

Продолжение следует...
GitHub - pv14mn/webdwh_client
GitHub - pv14mn/webdwh_client
  • pv14mn
  • github.com
A turnkey Docker Compose solution for streaming real-time market indicators (Forex, etc.) directly into your local or VPS time-series database.
 

TimescaleDB предоставляет удобные функции для работы с временными рядами.

Например, вы зачем-то захотели построить 13 минутные свечи.

Для этого будет удобно воспользоваться функцией time_bucket или time_bucket_gapfill


select time_bucket('13 min', q.evts) AS tbucket,
       any_value(t.scode) as scode,
       first((ask + bid) / 2, evts) AS first_price,
       last((ask + bid) / 2, evts) AS last_price,
       min((ask + bid) / 2) AS min_price,
       max((ask + bid) / 2) AS max_price,
       sum(tick_cnt) AS total_ticks 
 from mql.quotes q
 join mql.tickers t
   on t.icode = q.icode
where 1 = 1
  and q.evts >= date_trunc('day', now())
  and t.scode = 'EURUSD'
group by t.scode, tbucket
order by t.scode, tbucket

# |tbucket                      |scode |first_price           |last_price            |min_price             |max_price             |total_ticks|
--+-----------------------------+------+----------------------+----------------------+----------------------+----------------------+-----------+
1 |2026-07-28 00:00:00.000 +0300|EURUSD|1.13677500000000000000|1.13719000000000000000|1.13677500000000000000|1.13753000000000000000|        325|
2 |2026-07-28 00:13:00.000 +0300|EURUSD|1.13719000000000000000|1.13733500000000000000|1.13717000000000000000|1.13741500000000000000|        270|
3 |2026-07-28 00:26:00.000 +0300|EURUSD|1.13739500000000000000|1.13708500000000000000|1.13696000000000000000|1.13739500000000000000|        830|
4 |2026-07-28 00:39:00.000 +0300|EURUSD|1.13708500000000000000|1.13727000000000000000|1.13699000000000000000|1.13734000000000000000|        695|
5 |2026-07-28 00:52:00.000 +0300|EURUSD|1.13726000000000000000|1.13702000000000000000|1.13692000000000000000|1.13732000000000000000|        829|
6 |2026-07-28 01:05:00.000 +0300|EURUSD|1.13704000000000000000|1.13709500000000000000|1.13688000000000000000|1.13715000000000000000|       1014|
7 |2026-07-28 01:18:00.000 +0300|EURUSD|1.13708500000000000000|1.13696000000000000000|1.13691000000000000000|1.13712000000000000000|        848|
8 |2026-07-28 01:31:00.000 +0300|EURUSD|1.13695000000000000000|1.13696500000000000000|1.13692500000000000000|1.13706000000000000000|        669|
9 |2026-07-28 01:44:00.000 +0300|EURUSD|1.13696500000000000000|1.13690000000000000000|1.13689500000000000000|1.13698000000000000000|        611|
10|2026-07-28 01:57:00.000 +0300|EURUSD|1.13691000000000000000|1.13702500000000000000|1.13682500000000000000|1.13705000000000000000|        757|
11|2026-07-28 02:10:00.000 +0300|EURUSD|1.13704000000000000000|1.13704000000000000000|1.13695000000000000000|1.13705500000000000000|        526|

С учётом описанного выше способа буферизации, данные, конечно, получатся приблизительными (например, за секунду вы можете пропустить реальный всплеск max/min)

 

бегло глянул Git, что-то незаметил "как именно забираются данные из mql то есть часть которая в терминале" и механику заполнения пропусков (а-ля терминал ушёл в аут и после рестарта надо заливать пропуски). Может правда плохо искал :-)

просто я подобное делал, но с Influx и Telegraph - идейно всё совпадает. Эвенты и данные льются в роутер, роутер отдаёт получателям (в том числе базе), кому нужна аналитика лезет к базе и не мешает терминалам. Модели push/poll разные, но не суть

 

найдём top роста/падения за последние 30 минут по наклону регрессионной линии (slope_norm)

with src as (
select t.scode,
       q.evts,
       extract(epoch from q.evts)/60/60 as unix_evts,
       (q.ask + q.bid)/2 as last_pr
  from mql.quotes q
  join mql.tickers t
    on t.icode = q.icode
 where q.evts >= now() - interval '30 minute'
   -- and t.scode not in ('USDIDR')
),
scaled as (
  select src.*,
         (last_pr - avg(last_pr) over (partition by scode))
         /
         stddev(last_pr) over (partition by scode) as last_pr_norm
    from src
)
select *
  from (
 select min(s.evts) as date_b,
        max(s.evts) as date_e,
        s.scode,
        round(regr_slope(s.last_pr_norm, s.unix_evts)::numeric, 6) as slope_norm,
        round(regr_slope(s.last_pr, s.unix_evts)::numeric, 6) as slope,
        -- stddev(s.last_pr_sc) as stddev_norm, == 1
        round(stddev(s.last_pr), 6) as stddev,
        count(*) as cnt
   from scaled s
  group by s.scode
 having count(*) >= 25
)
order by abs(slope_norm) desc
limit 10

# |date_b                   |date_e                   |scode |slope_norm|slope    |stddev  |cnt |
--+-------------------------+-------------------------+------+----------+---------+--------+----+
1 |'2026-07-28 21:41:53.922'|'2026-07-28 22:11:43.199'|CADNOK| -6.816649|-0.007877|0.001156|1041|
2 |'2026-07-28 21:41:47.540'|'2026-07-28 22:11:45.729'|AUDCAD|  6.657076| 0.000912|0.000137|1268|
3 |'2026-07-28 21:41:48.598'|'2026-07-28 22:11:46.295'|GBPJPY|  6.625107| 0.104702|0.015804|1145|
4 |'2026-07-28 21:41:48.598'|'2026-07-28 22:11:46.945'|NZDCAD|  6.381547| 0.000503|0.000079| 874|
5 |'2026-07-28 21:41:54.096'|'2026-07-28 22:11:21.675'|EURTRY|  6.166117| 0.032611|0.005289| 329|
6 |'2026-07-28 21:41:47.888'|'2026-07-28 22:11:46.956'|GBPCAD|  6.160634| 0.001347|0.000219|1373|
7 |'2026-07-28 21:41:47.888'|'2026-07-28 22:11:46.359'|USDMXN| -6.036042|-0.016140|0.002674|1463|
8 |'2026-07-28 21:42:00.444'|'2026-07-28 22:11:42.278'|USDBRL| -6.034108|-0.003886|0.000644| 458|
9 |'2026-07-28 21:41:54.117'|'2026-07-28 22:11:44.292'|USDTHB| -5.966338|-0.019541|0.003275| 168|
10|'2026-07-28 21:41:48.778'|'2026-07-28 22:11:41.875'|EURCAD|  5.944364| 0.001022|0.000172| 932|
 
Maxim Kuznetsov #:

бегло глянул Git, что-то незаметил "как именно забираются данные из mql то есть часть которая в терминале" и механику заполнения пропусков (а-ля терминал ушёл в аут и после рестарта надо заливать пропуски). Может правда плохо искал :-)

просто я подобное делал, но с Influx и Telegraph - идейно всё совпадает. Эвенты и данные льются в роутер, роутер отдаёт получателям (в том числе базе), кому нужна аналитика лезет к базе и не мешает терминалам. Модели push/poll разные, но не суть

в гите клиентская часть

а данные собираются из нескольких открытых онлайн источников.

терминал не используется

 
nakachu #:
терминал не используется

разочаровал ты меня.

честно говоря от публикации на форуме MQL ожидал интеграция с терминалом. И решений узкоспецифичных проблем именно между ними двумя (терминалом и базой)

а просто TimeSeries DB, даже и неспортивно.

Да ещё с порезанными тиками и без стакана.

Кстати не понял смысла прорежать тики, они и в полном-то объёме не то чтобы совсем дохрена. Много, ну на то она и база чтобы хранить и обрабатывать большие объёмы и потоки.
А без тиков львиную долю задач вообще не решить. Спреды/синтетики/арбитражи отлетают

Стаканы конечно. Есть идеи как эффективно сохранять историю стакана, чтобы одновременно компактно, быстро и удобно работать  ? 

 
Maxim Kuznetsov #:

разочаровал ты меня.

честно говоря от публикации на форуме MQL ожидал интеграция с терминалом. И решений узкоспецифичных проблем именно между ними двумя (терминалом и базой)

а просто TimeSeries DB, даже и неспортивно.

Да ещё с порезанными тиками и без стакана.

Кстати не понял смысла прорежать тики, они и в полном-то объёме не то чтобы совсем дохрена. Много, ну на то она и база чтобы хранить и обрабатывать большие объёмы и потоки.
А без тиков львиную долю задач вообще не решить. Спреды/синтетики/арбитражи отлетают

Стаканы конечно. Есть идеи как эффективно сохранять историю стакана, чтобы одновременно компактно, быстро и удобно работать  ? 

Если бы я записывал все тики в базу, то у меня было бы 15.7 млн строк в день, вместо 4.2 млн.

Дело ещё и в железке под базой. Не каждый может себе позволить сортировать гигабайты.


Решение делалось скорее для статистического анализа на короткие и не очень дистанции. Типа найти все похожие графики за интервал времени.

На SQL такое конечно трудновато сделать (можно заморочиться с pgvector, искать косинусные расстояния).

Но есть другие способы – Python, R в связке с БД. Сейчас с ИИ это не очень сложно.

Для такого рода задач все тики не нужны и даже вредны, если цель сглаживать и обобщать. Даже 10 секундный буфер уменьшит базу в 10 раз без особых потерь в качестве анализа.

А так-то можно и не пропускать ничего. Из NATS идёт всё что тикает
тут
https://www.mql5.com/ru/quotes/currencies/forex-matrix

и тут
https://www.profinance.ru/quotes

Про стаканы не подскажу.

Тепловая карта валют | Матрица Форекс
Тепловая карта валют | Матрица Форекс
  • www.mql5.com
Отслеживайте поведение рынков благодаря витрине курсов, представленной в виде матрицы. Кликните по любой паре, чтобы получить больше информации.
 

хочу спросить у сообщества вот что.

1.

как думаете, что за данные мелькают тут:

https://www.mql5.com/ru/quotes/currencies/forex-matrix

это средняя температура по брокерской больнице?

2.

кто-считал корреляцию Пирсона по USDCNH-USDRMB?

у меня по вышеобозначенному источнику c  2026-07-24 00:00:00 по н.в.  получается корреляция 0.9999995658 (что кажется нереалистично если только данные не синтетические)

3.

какие геополитические индексы вы используете / хотели бы иметь под рукой для анализа: например, посматриваете ли иногда VIX (Индекс волатильности S&P 500), индекс пиццы пентагона, кол-во сделок в секунду на Polymarket или что-то в этом роде?

Тепловая карта валют | Матрица Форекс
Тепловая карта валют | Матрица Форекс
  • www.mql5.com
Отслеживайте поведение рынков благодаря витрине курсов, представленной в виде матрицы. Кликните по любой паре, чтобы получить больше информации.
 
nakachu #:
получается корреляция 0.9999995658

Это логично

USDCNH: Доллар США / китайский офшорный юань

USDRMB: Доллар США / Китайский юань

 

возможно кому-то будет интересно. abs(корреляция) >= 0.9 начиная с 2026-07-24 00:00:00

отрицательная - значит в противофазе.

где небольшой baskets_count скорей всего какая-то хрень из-за небольшого пересечения по времени торгов на рынке (не смотрите).

#  |scode1|scode2|corr         |baskets_count|
---+------+------+-------------+-------------+
1  |USDCNH|USDRMB| 0.9999995710|         1650|
2  |EURUSD|USDDKK|-0.9999543610|         1650|
3  |HKDJPY|USDJPY| 0.9999222009|         1626|
4  |AUDDKK|EURAUD|-0.9998639124|         1624|
5  |EURHKD|USDDKK|-0.9998298676|         1650|
6  |EURHKD|EURUSD| 0.9998241269|         1651|
7  |GBPHKD|GBPUSD| 0.9997405177|         1614|
8  |AUDHKD|AUDUSD| 0.9996511160|         1651|
9  |CHFDKK|EURCHF|-0.9995834205|         1588|
10 |EURNZD|NZDDKK|-0.9995239199|         1593|
11 |EURGBP|GBPDKK|-0.9995127052|         1647|
12 |SGDHKD|USDSGD|-0.9992909159|         1627|
13 |DKKSEK|EURSEK| 0.9986675884|         1593|
14 |HKDJPY|TRYJPY| 0.9965799989|         1589|
15 |TRYJPY|USDJPY| 0.9961300870|         1589|
16 |CNHJPY|USDJPY| 0.9958730468|         1612|
17 |EURHKD|EURTRY| 0.9956606449|         1647|
18 |EURTRY|USDDKK|-0.9955731675|         1646|
19 |CNHJPY|HKDJPY| 0.9953925452|         1612|
20 |EURTRY|EURUSD| 0.9952130807|         1647|
21 |CNHJPY|SGDJPY| 0.9943471689|         1612|
22 |SGDJPY|USDJPY| 0.9921813218|         1651|
23 |HKDJPY|SGDJPY| 0.9919057944|         1626|
24 |GBPHKD|GBPTRY| 0.9895201707|         1614|
25 |GBPTRY|GBPUSD| 0.9878066483|         1651|
26 |EURCNH|EURUSD| 0.9874787464|         1614|
27 |EURCNH|USDDKK|-0.9871939526|         1613|
28 |EURCNH|EURHKD| 0.9870467054|         1614|
29 |CNHJPY|TRYJPY| 0.9865126099|         1575|
30 |SGDJPY|TRYJPY| 0.9864844713|         1589|
31 |CADJPY|SGDJPY| 0.9855501699|         1651|
32 |CNHJPY|MXNJPY| 0.9852217286|         1609|
33 |NZDSGD|NZDUSD| 0.9846261389|         1650|
34 |EURHKD|USDCZK|-0.9824911401|         1651|
35 |MXNJPY|SGDJPY| 0.9824392366|         1624|
36 |GBPUSD|USDCHF|-0.9820638952|         1650|
37 |EURUSD|USDCZK|-0.9819851650|         1651|
38 |CADJPY|CNHJPY| 0.9819389896|         1612|
39 |GBPTRY|USDPLN|-0.9819233999|         1651|
40 |GBPHKD|USDCHF|-0.9819034097|         1613|
41 |USDCZK|USDDKK| 0.9813850388|         1650|
42 |USDCZK|USDPLN| 0.9805707652|         1651|
43 |CADJPY|USDJPY| 0.9802030092|         1651|
44 |CADJPY|HKDJPY| 0.9792310523|         1626|
45 |CHFSGD|USDCHF|-0.9787975784|         1626|
46 |USDPLN|USDSEK| 0.9786847721|         1648|
47 |EURHKD|USDPLN|-0.9784531933|         1651|
48 |EURUSD|USDPLN|-0.9783152334|         1651|
49 |CADJPY|GBPJPY| 0.9782684104|         1651|
50 |GBPTRY|NZDUSD| 0.9780296910|         1651|
51 |MXNJPY|USDJPY| 0.9777017850|         1624|
52 |USDDKK|USDPLN| 0.9775671864|         1650|
53 |HKDJPY|MXNJPY| 0.9774829853|         1623|
54 |NZDUSD|SGDHKD| 0.9765946287|         1627|
55 |EURCNH|USDCAD|-0.9764328548|         1614|
56 |GBPUSD|SGDHKD| 0.9764045600|         1627|
57 |EURCNH|EURTRY| 0.9763431426|         1610|
58 |NZDUSD|USDPLN|-0.9761392640|         1651|
59 |GBPHKD|SGDHKD| 0.9761189749|         1614|
60 |EURUSD|GBPTRY| 0.9758569107|         1651|
61 |EURHKD|GBPTRY| 0.9751727040|         1651|
62 |GBPUSD|USDSGD|-0.9748816714|         1650|
63 |GBPTRY|USDDKK|-0.9746716292|         1650|
64 |GBPJPY|SGDJPY| 0.9739523436|         1651|
65 |NZDUSD|USDSEK|-0.9739416561|         1648|
66 |GBPHKD|USDSGD|-0.9738790502|         1614|
67 |NZDUSD|USDSGD|-0.9737849487|         1650|
68 |SGDHKD|USDCHF|-0.9737653795|         1626|
69 |USDCHF|USDSGD| 0.9734423124|         1649|
70 |GBPHKD|NZDUSD| 0.9731802454|         1614|
71 |EURCNH|USDCZK|-0.9727190523|         1614|
72 |GBPUSD|NZDUSD| 0.9724305071|         1651|
73 |GBPHKD|USDPLN|-0.9712766267|         1614|
74 |EURTRY|GBPTRY| 0.9709309591|         1647|
75 |EURTRY|USDPLN|-0.9707817305|         1647|
76 |CHFJPY|GBPJPY| 0.9707061620|         1648|
77 |EURTRY|USDCZK|-0.9704194306|         1647|
78 |EURUSD|USDSEK|-0.9684201376|         1648|
79 |GBPTRY|SGDHKD| 0.9683610082|         1627|
80 |GBPUSD|USDPLN|-0.9681920934|         1651|
81 |USDDKK|USDSEK| 0.9681609448|         1647|
82 |EURHKD|USDSEK|-0.9676981881|         1648|
83 |MXNJPY|TRYJPY| 0.9676153643|         1586|
84 |CADJPY|TRYJPY| 0.9676069494|         1589|
85 |EURTRY|USDSEK|-0.9664993209|         1644|
86 |GBPTRY|USDCHF|-0.9661859213|         1650|
87 |CADJPY|EURJPY| 0.9657031960|         1651|
88 |SGDHKD|USDPLN|-0.9656793704|         1627|
89 |EURSGD|USDCLP|-0.9639873311|          249|
90 |GBPTRY|USDSGD|-0.9639866116|         1650|
91 |GBPTRY|USDCZK|-0.9637528421|         1651|
92 |AUDNZD|AUDSEK| 0.9634016614|         1609|
93 |NZDCAD|NZDUSD| 0.9627745598|         1650|
94 |EURJPY|GBPJPY| 0.9624247317|         1651|
95 |GBPTRY|USDSEK|-0.9618052222|         1648|
96 |NZDUSD|USDCHF|-0.9615267943|         1650|
97 |NZDJPY|PLNJPY| 0.9605751768|         1626|
98 |USDPLN|USDSGD| 0.9600466613|         1650|
99 |EURCAD|USDSEK|-0.9593437674|         1648|
100|EURCAD|USDCNH|-0.9593239243|         1650|
101|EURCAD|USDRMB|-0.9593147406|         1650|
102|EURCAD|USDZAR|-0.9592323263|         1647|
103|CADJPY|MXNJPY| 0.9590659530|         1624|
104|EURCNH|GBPTRY| 0.9587039756|         1614|
105|AUDNZD|AUDPLN| 0.9574995934|         1626|
106|CNHJPY|GBPJPY| 0.9569530539|         1612|
107|AUDPLN|AUDSEK| 0.9568147897|         1609|
108|TRYJPY|USDCOP| 0.9567705422|          306|
109|USDCZK|USDSEK| 0.9566420457|         1648|
110|SGDHKD|USDSEK|-0.9565553468|         1624|
111|EURUSD|USDCAD|-0.9563881489|         1651|
112|EURHKD|USDCAD|-0.9562163277|         1651|
113|NZDSGD|USDSEK|-0.9559034857|         1647|
114|SGDHKD|TRYJPY|-0.9556901829|         1589|
115|AUDCAD|AUDSGD| 0.9555509792|         1627|
116|USDCHF|USDPLN| 0.9553681322|         1650|
117|CADCHF|USDCHF| 0.9553154644|         1650|
118|USDCAD|USDDKK| 0.9553106721|         1650|
119|AUDDKK|GBPAUD|-0.9552935092|         1624|
120|USDCOP|USDJPY| 0.9550350351|          313|
121|TRYJPY|USDSGD| 0.9548401334|         1589|
122|EURAUD|GBPAUD| 0.9547302410|         1651|
123|HKDJPY|USDCOP| 0.9547295979|          313|
124|EURUSD|GBPHKD| 0.9544868752|         1614|
125|GBPTRY|NZDSGD| 0.9541005579|         1650|
126|EURUSD|NZDUSD| 0.9539559095|         1651|
127|NZDSGD|USDPLN|-0.9537474104|         1650|
128|USDSEK|USDZAR| 0.9534244775|         1647|
129|EURCAD|EURTRY| 0.9533335500|         1647|
130|HKDJPY|USDSGD| 0.9532372588|         1626|
131|EURHKD|GBPHKD| 0.9530881525|         1614|
132|NZDUSD|USDDKK|-0.9529663475|         1650|
133|EURHKD|NZDUSD| 0.9529195208|         1651|
134|HKDJPY|SGDHKD|-0.9527744494|         1626|
135|GBPHKD|USDDKK|-0.9527222312|         1613|
136|USDJPY|USDSGD| 0.9523942115|         1650|
137|EURCNH|USDPLN|-0.9522064877|         1614|
138|EURJPY|PLNJPY| 0.9520756988|         1626|
139|USDSEK|USDSGD| 0.9520546194|         1647|
140|SGDHKD|USDJPY|-0.9518811496|         1627|
141|CNHJPY|USDCOP| 0.9510973623|          313|
142|NZDUSD|TRYJPY|-0.9510792762|         1589|
143|GBPHKD|USDCZK|-0.9503825645|         1614|
...
abs(corr) between 0.9 and 0.95 (Длина сообщения не должна превышать 64000 символов)

сравните визуально графики на ТФ М15 и ниже, чтобы увидеть сходство или зеркальность.