В этом уроке мы рассмотрим свечной график или Candlestick chart. Он широко используется для изображения котировок валют. Сегодня мы агрегируем данные валютной пары за 19 лет и построим график в Google Sheets.
Знания и навыки об агрегации данных для свечного графика позволят работать аналитиком в финансовой сфере.
Candlestick chart
Представим, что у нас есть котировки валюты австралийского доллара относительно американского доллара. Мы хотим узнать, как они меняются со временем. Мы уже умеем строить линейный график, поэтому сначала изобразим его:
На этом рисунке мы видим линейный график котировок валют австралийского доллара относительно американского доллара.
Но такой график для отображения котировок неудобен и неинформативен. Мы видим только изменение текущей цены со временем. Торги на рынке происходят в каком-то окне: есть цена открытия и цена закрытия. Цена открытия — это цена, с которой начинаются торги, а по цене закрытия они заканчиваются. Поэтому таблицы с котировками обычно выглядят более сложно:
currency_exchange
В этой таблице представлены котировки валюты с шагом в один месяц. Она содержит такие столбцы:
- date — дата
- low — минимальное значение цены за этот месяц
- open — цена открытия. Это первая цена за месяц
- high — максимальная цена за месяц
- close — цена закрытия. Это последняя цена за месяц
Из этой таблицы мы понимаем, как торги начинались и заканчивались. Также знаем минимальное и максимальное значение котировок. Для визуального представления таких таблиц используют свечной график или Candlestick chart. Он удобнее линейного графика, потому что позволяет визуализировать все параметры: цену открытия, закрытия, минимальную и максимальную цены.
Посмотрим, из чего он состоит, и где на нем находятся данные из таблицы:
На свечном графике каждый промежуток времени мы изображаем в виде «свечи». У свечи есть тело и фитиль. Нижний и верхний фитили на картинке обозначены как Lower Wick и Upper Wick. Тело свечи отмечено как Real Body. Open и Close — это цены открытия и закрытия.
Тело — это прямоугольник, у которого одна из границ — цена открытия, а вторая — закрытия. Цена открытия бывает меньше или больше цены закрытия — это зависит от трендов на рынке.
Фитиль рисуется узкой вертикальной линией. Верхняя граница фитиля — это максимальная цена за период торгов, а нижняя — минимальная. Если фитиль длинный, а тело нет — это говорит о том, что рынок очень волатильный, то есть быстро меняется.
По таблице CurrencyExchange мы можем построить свечной график котировок. Он будет выглядеть так:
Здесь мы видим свечной график котировок валют. Он содержит в себе не информацию о текущей стоимости валюты, а цену открытия, закрытия, минимальную и максимальную во временном окне, когда идут торги.
Чтобы получить из таблицы, в которой есть только текущая стоимость, таблицу с ценами открытия, закрытия, минимальной и максимальной, мы агрегируем данные. По агрегированной таблице мы уже построим свечной график.
Агрегация курсов валют
Мы будем агрегировать таблицу курса валют помесячно. Для агрегации мы проделаем такие шаги:
- Создадим вспомогательную таблицу с первыми и последними значениями цены за месяц
- Создадим вспомогательную таблицу для цен открытия и закрытия
- Создадим вспомогательные таблицы для минимальных и максимальных значений за месяц
- Объединим эти таблицы с помощью SQL-функции join и проведем итоговую агрегацию
Первые и последние значения цены за месяц
Откроем базу australian_currency.
В базе данных есть таблица exchange с двумя полями:
- date — дата, в которую валюта имела определенную стоимость
- currency — значение котировки валюты
Посмотрим на саму таблицу:
Currency
В этой таблице 5019 строк. Мы видим, что в таблице есть данные за 2000-2019 года.
Нам нужно создать новую таблицу с минимумом, максимумом, первой ценой и последней ценой за определенный период времени. Мы будем агрегировать данные помесячно.
Чтобы получить первую и последнюю цены за месяц, мы создадим вспомогательную таблицу monthly_dates. В нее мы агрегируем первую и последнюю дату за месяц, само значение месяца и уникальный ключ, по которому мы будем джойнить таблицы:
Мы создали таблицу с полями:
- year_month — уникальный строковый ключ с годом и месяцем
- month — значение месяца
- min_date — первая дата за месяц
- max_date — последняя дата за месяц
Агрегируем данные и запишем их в новую таблицу:
Мы записали в таблицу ключ year_month, поле month, минимальное значение даты за месяц min_date и максимальное значение даты max_date.
Функция concat применяется, чтобы объединить несколько строковых значений. date_trunc позволяет «схлопнуть» даты временного промежутка в один. А с помощью значения month в функции date_trunc мы использовали агрегацию в месяц.
Сортировка по дате нужна, чтобы избежать перемешивания дат. Уникальный ключ, в котором есть год и месяц, нам понадобится в дальнейшем для джойна таблиц.
Цены открытия и закрытия
Теперь мы создадим таблицу open, чтобы сохранить в нее первые значения котировок в месяце. В ней тоже будет уникальный ключ year_month, а также первая дата за месяц и значение open цены валюты в эту дату:
Теперь сджойним таблицу monthly_dates с таблицей open по минимальной дате. Мы не будем использовать агрегацию, а только возьмем значения котировок в минимальные даты каждого месяца:
По аналогии с таблицей open создадим таблицу close, в которой будет последнее значение валюты за месяц. Мы будем джойнить ее с таблицей monthly_dates по максимальной дате месяца:
Минимальные и максимальные цены за месяц
Теперь мы создадим таблицу min_max_currency. В ней будет значение месяца, потому что мы агрегируем минимальное и максимальное значения валюты за месяц, и сами минимальное и максимальное значения котировок:
Агрегируем таблицу exchange по минимальным и максимальным помесячным значениям валют и запишем в min_max_currency. Для помесячной агрегации мы используем функцию date_trunc:
Витрина данных и свечной график
Теперь осталось создать таблицу с витриной, в которой будут уникальный ключ, цена открытия и закрытия и минимальная и максимальная цены:
Для создания витрины мы сджойним таблицы monthly_dates, open, close и min_max_currency:
Мы создали витрину данных, по которой будем строить свечной график. Мы сделали джойн таблиц monthly_dates, open и close по ключу year_month и полученной таблицы с min_max_currency по значению месяца month.
Итоговая таблица содержит 240 строк и выглядит так:
data_mart
В ней есть поля:
- year_month — уникальный строковый ключ
- month — месяц, по которому производилась агрегация
- min_currency — минимальное значение валюты за месяц
- open — первое значение валюты за месяц
- max_currency — максимальное значение валюты за месяц
- close - последнее значение валюты за месяц
Поля идут в таком порядке, потому что так по ним удобнее строить Candlestick Chart в Google Sheets.
Построим график по следующим шагам:
- Скопируем витрину в Google Sheets
- Выделим все столбцы, кроме year_month
- Для столбца month выберем «Формат» -> «Числа» -> «Обычный текст»
- В столбцах с котировками заменим все точки на запятые
- Вставим диаграмму и типом диаграммы выберем «График "японские свечи"»
В итоге мы получим график, который видели выше:
Мы построили свечной график по помесячным котировкам. Видим, что он состоит из свечей. Но на нем слишком много данных и мы не можем посмотреть на фитили. Поэтому возьмем только данные за 2019 год и запишем их в таблицу data_mart_new_data:
Здесь мы отобрали все даты, которые больше или равны 1 января 2019 года.
Теперь построим свечной график по этим данным. В дополнительных настройках вертикальной оси установим минимальное значение 1.2, чтобы рассмотреть график на большем масштабе:
Мы построили свечной график котировок валют за 2018-2019 год. На этом графике отчетливо видно, что свечной график состоит из тела свечи и фитилей. Границы тела определяются ценой открытия и закрытия, а фитили — минимальным и максимальным значениями за месяц.
Выводы
В этом уроке мы научились агрегировать данные для свечного графика. Мы взяли котировки валютной пары австралийского доллара и доллара США, сделали помесячную агрегацию валют и построили свечной график в Google Sheets. Агрегация валют позволит работать в финансовой сфере и строить отчеты по валютным парам.
<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 17:16:56 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="iI-6XO-bB9COOevG6qfQlAnm98FVlGN2X5aDn2yqABhnXnFrHeWqsDh6z17mqCDjye_aa12jndTidhnLPq3ndg";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Агрегация для candlestick-диаграмм | Продвинутая аналитика на SQL</title>
<meta name="description" content="Агрегация для candlestick-диаграмм / Продвинутая аналитика на SQL: Учимся строить сandlestick-диаграммы с помощью агрегации">
<link rel="canonical" href="https://ru.hexlet.io/courses/analytics-with-sql/lessons/candlestick-chart/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Агрегация для candlestick-диаграмм">
<meta property="og:title" content="Продвинутая аналитика на SQL">
<meta property="og:description" content="Агрегация для candlestick-диаграмм / Продвинутая аналитика на SQL: Учимся строить сandlestick-диаграммы с помощью агрегации">
<meta property="og:url" content="https://ru.hexlet.io/courses/analytics-with-sql/lessons/candlestick-chart/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="s_p6O2f09LAp3SRNFXBBSGp83rWVx8OOa4go1EoocglcK7EMlYpZ0J-eANUZf7E_qnXzH53wPSzWaLKAGC-VZw" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzY1MywicHVyIjoiYmxvYl9pZCJ9fQ==--5107185de77b3481e0a836f9fc7326c4e1b77be4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20extraction-pana.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk1MywicHVyIjoiYmxvYl9pZCJ9fQ==--963098414ddb264ba6c4deab9bd951f2d6778e4a/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20analysis-amico.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg3MSwicHVyIjoiYmxvYl9pZCJ9fQ==--8175585f43b5401994e29b3ae73d76963d942512/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Browser%20stats-bro.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg2MiwicHVyIjoiYmxvYl9pZCJ9fQ==--04a703ca18d7bf689064f1f3c2721058bd5564e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Statistics-bro.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T17:16:56.417Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"PBYxNmsVxli3YwCFkGXm3O7DfhcNzBeO7r80oEulevbTx_oBmWtrOAEgJB2caharLspTvQX76SxTX670GaKdmA","topics":[{"id":91741,"title":"В описании задания исправьте год в таблице на 2022, а то путает)","plain_title":"В описании задания исправьте год в таблице на 2022, а то путает) ","creator":{"public_name":"Юлия","id":672103,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":181262,"body":"Спасибо, поправил","topic_id":91741}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":92884,"title":"Обращаю внимание, что в той БД, которая прикреплена в теме уже проделаны шаги, описанные в уроке. Не знаю намеренно это сделано или нет, но для того, чтобы самому пройти путь создания таблиц нужно немного почистить БД.","plain_title":"Обращаю внимание, что в той БД, которая прикреплена в теме уже проделаны шаги, описанные в уроке. Не знаю намеренно это сделано или нет, но для того, чтобы самому пройти путь создания таблиц нужно немного почистить БД. ","creator":{"public_name":"Анастасия","id":687978,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":182947,"body":"Да, в ней уже есть расчитанные таблицы, чтобы вы могли свериться с ними.","topic_id":92884}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":91726,"title":"в DB FIDDLE скопипащенная инструкция по первичному заполнению monthly_dates не работает, выходит ошибка. \n\n> Query Error: error: subquery in FROM must have an alias\n\nЯ не прошу с этим помощи, напишу сама, просто для справки. \n\nкстати, базы данных, которые вы скидываете, их предполагается через dbeaver открывать же? у меня он без лицензии не стал открываться, покупать я не стала. кмк, надо написать в первом уроке что он платный чтобы кто не готов платить не скачивал. ну или может альтернатива есть. ну или я что-то криво сделала три раза подряд, такой вариант всегда есть)","plain_title":"в DB FIDDLE скопипащенная инструкция по первичному заполнению monthly_dates не работает, выходит ошибка. Query Error: error: subquery in FROM must have an alias Я не прошу с этим помощи, напишу сама, просто для справки. кстати, базы данных, которые вы скидываете, их предполагается через dbeaver открывать же? у меня он без лицензии не стал открываться, покупать я не стала. кмк, надо написать в первом уроке что он платный чтобы кто не готов платить не скачивал. ну или может альтернатива есть. ну или я что-то криво сделала три раза подряд, такой вариант всегда есть) ","creator":{"public_name":"Alina Amirova","id":284783,"is_tutor":false},"comments":[{"creator":{"public_name":"Данила","id":599868,"is_tutor":false},"id":181767,"body":"Community бесплатный, а PRO платный.","topic_id":91726},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":181436,"body":"Добрый день, мы почти всегда в курсах используем бесплатные инструменты. И dbbeaver тоже бесплатный https://dbeaver.io/\n\nИнструкцию поправлю, спасибо.\n\n","topic_id":91726},{"creator":{"public_name":"Alina Amirova","id":284783,"is_tutor":false},"id":181483,"body":"**Ivan Mamtsev**, да поэтому я и удивилась. ссылка из лекции вела на другой сайт откуда я качала несколько раз и он отказывался запускаться без лицензии но можно было оформить trial","topic_id":91726},{"creator":{"public_name":"Елена Аксенова","id":691460,"is_tutor":false},"id":183453,"body":"У меня тоже не открываюся базы данных DuckDB через DBeaver. Выдает вот такое сообщение.\nIO Error: Trying to read a database file with version number 43, but we can only read version 64.\nThe database file was created with DuckDB version v0.7.0 or v0.7.1.\n\nThe storage of DuckDB is not yet stable; newer versions of DuckDB cannot read old database files and vice versa.\nThe storage will be stabilized when version 1.0 releases.\n\nFor now, we recommend that you load the database file in a supported version of DuckDB, and use the EXPORT DATABASE command followed by IMPORT DATABASE on the current version of DuckDB.","topic_id":91726},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":183535,"body":"Добрый день, вам нужно зайти в настройки драйвера, выбрать нужную версию и скачать её. Но, если не получится, вы всегда можете воспользоваться этой же базой в DB Fiddle.","topic_id":91726}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":96050,"title":"Короче с этим заданием все очень не понятно, как пользоваться реплом - не понятно, в оутпуте выводится таблица в странном виде = столбцы почему то в столбце индекс как значения.Как потом данные переносить в Гугл таблицы тоже не понятно.Откуда их копировать не понятно.Да и сложность задания по сравнению с предыдущим резко выше.Курс сырой сильно и это чувствуется, не приятно.Учился на других никаких вопросов не возникало. ","plain_title":"Короче с этим заданием все очень не понятно, как пользоваться реплом - не понятно, в оутпуте выводится таблица в странном виде = столбцы почему то в столбце индекс как значения.Как потом данные переносить в Гугл таблицы тоже не понятно.Откуда их копировать не понятно.Да и сложность задания по сравнению с предыдущим резко выше.Курс сырой сильно и это чувствуется, не приятно.Учился на других никаких вопросов не возникало. ","creator":{"public_name":"Михаил Лузгин","id":662448,"is_tutor":false},"comments":[{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":186932,"body":"Михаил, добрый день.\n\nСпасибо за фидбек. подумаем, как лучше вывести данные. \nСейчас данные выводятся для удобство отладки кода, подход везде одинаковый. \nКонкретно здесь добавим вывод для копирования.\n\nЧТо касается сырости курса - можете ли вы поделиться обратной связью? Не в рамках топика - а передать куратору, например. Тогда мы будем знать, над чем конкретно нужно поработать, чтобы нашим студентам было лучше учиться","topic_id":96050},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":186933,"body":"Михаил, задание обновил. Можете нажать \"Сброс\", чтобы получить новую версию.","topic_id":96050}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":96049,"title":"Так и не понял как пользоваться Реплом\nВвожу select * from bitcoin_prices и ничего не происходит","plain_title":"Так и не понял как пользоваться Реплом Ввожу select * from bitcoin_prices и ничего не происходит ","creator":{"public_name":"Михаил Лузгин","id":662448,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":186804,"body":"А вы не забываете завершать запрос точкой с запятой?","topic_id":96049}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":97615,"title":"Худшее и бредовое упражнение, что я видел на текущий момент прохождения обучения. Теория об одном, упражнение делается совершенно иначе. Логика студента такая - мне показали как делать, теперь нужно сделать также, только на своих данных, закрепить на практике. Задание в упражнении в контексте теоретической части урока - НЕ РЕШАЕТСЯ! \n\nЗадание простое, но контексте жести из теории оно кажется сложным. Вы хотя бы опишите это подробно - что в этом упражнении нужно сделать не так как в теор. части урока, а вот так и так то. Фраза \"Запросов в файле может быть сколько угодно, главное, чтобы они в итоге выводили нужные данные.\" мне не помогла, потому в теории их тоже МНОГО. В задание нужно дописать \"Необязательно объединять в одну таблицу\" или как-то более подробно.\n\nВ том числе я пытался сделать ключ через CONCAT, YEAR, MONTH (как в примере из теории) - только в своей адаптации DAY и HOUR. Потом у наставника выяснил, что DAY и HOUR - нет в PostgreSQL, также как YEAR, MONTH. Ключ надо было бы создавать через EXTRACT. Так чему вы учите в теории я так и не понял? YEAR, MONTH которых нет в PostgreSQL? Может лучше было бы показать пример на EXTRACT?","plain_title":"Худшее и бредовое упражнение, что я видел на текущий момент прохождения обучения. Теория об одном, упражнение делается совершенно иначе. Логика студента такая - мне показали как делать, теперь нужно сделать также, только на своих данных, закрепить на практике. Задание в упражнении в контексте теоретической части урока - НЕ РЕШАЕТСЯ! Задание простое, но контексте жести из теории оно кажется сложным. Вы хотя бы опишите это подробно - что в этом упражнении нужно сделать не так как в теор. части урока, а вот так и так то. Фраза \"Запросов в файле может быть сколько угодно, главное, чтобы они в итоге выводили нужные данные.\" мне не помогла, потому в теории их тоже МНОГО. В задание нужно дописать \"Необязательно объединять в одну таблицу\" или как-то более подробно. В том числе я пытался сделать ключ через CONCAT, YEAR, MONTH (как в примере из теории) - только в своей адаптации DAY и HOUR. Потом у наставника выяснил, что DAY и HOUR - нет в PostgreSQL, также как YEAR, MONTH. Ключ надо было бы создавать через EXTRACT. Так чему вы учите в теории я так и не понял? YEAR, MONTH которых нет в PostgreSQL? Может лучше было бы показать пример на EXTRACT? ","creator":{"public_name":"Andrei Kholkin","id":189330,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":188748,"body":"Добрый день, эта практика упрощена в сравнении с теорией, потому что теория и так достаточно тяжелая. По поводу функций SQL -- поправил примеры.","topic_id":97615},{"creator":{"public_name":"Юрий Тотышев","id":635711,"is_tutor":false},"id":188857,"body":"То же самое. Проще было подсказку взять, чем сидеть угадывать, че от тебя хотят и каким образом.","topic_id":97615}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":96980,"title":"Очень странная тяжелая теория предшествующая такому простому решению. После прочтения стал дописывать огромное количество новых таблиц как в теории , ничего не работало и уже решил сделать как получается помогла фраза \"Запросов в файле может быть сколько угодно\", в итоге оказалось тем самым верным решением. Не понял для чего была такая подробная теория от \"Агрегация курсов валют\" до конца, которую я все равно понял только поверхностно и ничего не применил для решения упражнения .","plain_title":"Очень странная тяжелая теория предшествующая такому простому решению. После прочтения стал дописывать огромное количество новых таблиц как в теории , ничего не работало и уже решил сделать как получается помогла фраза \"Запросов в файле может быть сколько угодно\", в итоге оказалось тем самым верным решением. Не понял для чего была такая подробная теория от \"Агрегация курсов валют\" до конца, которую я все равно понял только поверхностно и ничего не применил для решения упражнения . ","creator":{"public_name":"Никита Макиевский","id":170707,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":188063,"body":"Эту практику мы решили сделать не слишком сложной, потому что теория и так была достаточно подробная и тяжелая","topic_id":96980},{"creator":{"public_name":"Andrei Kholkin","id":189330,"is_tutor":false},"id":188609,"body":"**Ivan Mamtsev**, Полностью согласен с Никитой. Упражнение бредовое вообще, не совпадает с тем чему учили в теории. Я также начал кучу таблиц создавать и выяснять как же ваша система примет мое решение - это просто бред!","topic_id":96980}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":104787,"title":"Ошибка в условии в каждом дне:\n> Поле min — минимальная цена за день\n\n> Поле max — максимальная цена за день\n\nДля того, чтобы решение было засчитано, нужно выводить сначала max, затем min","plain_title":"Ошибка в условии в каждом дне: Поле min — минимальная цена за день Поле max — максимальная цена за день Для того, чтобы решение было засчитано, нужно выводить сначала max, затем min ","creator":{"public_name":"Артур Файзуллин","id":887252,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":197458,"body":"**Артур Файзуллин**, проверил, разницы нет. Если поменять их местами, то тесты проходят.","topic_id":104787}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":104830,"title":"Странная тема, на вебинаре используются оконные функции, хотя до этого в треке Аналитик данных их не было, и появляются они только через несколько курсов.","plain_title":"Странная тема, на вебинаре используются оконные функции, хотя до этого в треке Аналитик данных их не было, и появляются они только через несколько курсов. ","creator":{"public_name":"Илья","id":382169,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":197536,"body":"Спасибо за замечание, создал тикет на упрощение теории.","topic_id":104830},{"creator":{"public_name":"Илья","id":382169,"is_tutor":false},"id":197546,"body":"Скорее нужно поменять местами некоторые блоки и добавить\\пояснить в текстовом содержании примеры из вебинара.","topic_id":104830}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}},{"id":105683,"title":"Спустя час сидения в теории - упражнение :: упражнение - теория, абсолютный ноль понимания, если до этого я еще когда тупил в упражнениях, я могу пошагово добиваться от таблиц взаимодействия на элементарных командах, то тут, обычный SELECT * FROM bitcoin_prices; выдает таблицу, где наименование столбцов идут строками. Дальше у меня ломается мозг, так как нет элементарного отклика от элементарной команды. Взял подсказку, понимание команд введенных там есть, а почему не работает элементарная команда, нет, понимание логики у меня не появилось. Согласен с тем, кто год назад тут молниями кидался, что это бредовое упражнение, которое не вяжется с теорией, либо сразу за рукав наставника тащите и делайте вместе, либо переходить к следующему, как я и поступил.","plain_title":"Спустя час сидения в теории - упражнение :: упражнение - теория, абсолютный ноль понимания, если до этого я еще когда тупил в упражнениях, я могу пошагово добиваться от таблиц взаимодействия на элементарных командах, то тут, обычный SELECT * FROM bitcoin_prices; выдает таблицу, где наименование столбцов идут строками. Дальше у меня ломается мозг, так как нет элементарного отклика от элементарной команды. Взял подсказку, понимание команд введенных там есть, а почему не работает элементарная команда, нет, понимание логики у меня не появилось. Согласен с тем, кто год назад тут молниями кидался, что это бредовое упражнение, которое не вяжется с теорией, либо сразу за рукав наставника тащите и делайте вместе, либо переходить к следующему, как я и поступил. ","creator":{"public_name":"Пётр Прохоркин","id":490638,"is_tutor":false},"comments":[{"creator":{"public_name":"Любовь","id":725521,"is_tutor":false},"id":198648,"body":"**Ivan Mamtsev**, когда?(","topic_id":105683},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":198463,"body":"Спасибо за замечание. Заменим практику","topic_id":105683},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":198662,"body":"Добрый день, к сожалению точных сроков дать не могу. Но такая задача есть.","topic_id":105683}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Агрегация для candlestick-диаграмм","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":2466,"slug":"analytics_with_sql_candlestick_chart_exercise","name":null,"state":"active","kind":"exercise","language":"sql","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"В таблице `bitcoin_prices` хранится информация о ценах на Bitcoin за 3 дня.\n\n**bitcoin_prices**\n\n| id | price | date_and_time |\n|----|-------|---------------------|\n| 1 | 40000 | 2022-02-01 09:00:00 |\n| 2 | 35000 | 2022-02-01 13:00:00 |\n| 3 | 50000 | 2022-02-01 18:00:00 |\n\nВам нужно сагрегировать из данной таблицы данные для диаграммы \"Японские свечи\". Решение нужно записать в трёх файлах на каждый из дней: первое, второе и третье января. Запросов в файле может быть сколько угодно, главное, чтобы они в итоге выводили нужные данные.\n\nЧтобы получить записи, которые сделали в определенный день, можно сделать так:\n\n```sql\nselect * from bitcoin_prices where date_and_time::date = '2022-01-01';\n```\n\n```\n id | price | date_and_time\n----+-------+---------------------\n 1 | 45000 | 2022-01-01 09:00:00\n 2 | 37000 | 2022-01-01 12:00:00\n 3 | 57000 | 2022-01-01 15:00:00\n 4 | 48000 | 2022-01-01 18:00:00\n(4 rows)\n```\n\n## first_day.sql\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\n## second_day.sql\n\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\n## third_day.sql\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\nВизуализируйте данные в виде Candlestick диаграммы в [Google Sheets](https://docs.google.com/spreadsheets). Для этого скопируйте данные из вывода тестов\n\n```bash\nconsole.log\n ┌─────────────┬─────────┐\n │ (index) │ Values │\n ├─────────────┼─────────┤\n │ max │ '65000' │\n │ min │ '45000' │\n │ open_price │ '49000' │\n │ close_price │ '50000' │\n └─────────────┴─────────┘\n\n# ...\n# дальше идет вывод по другим дням\n```\n\nИз этого вывода нам нужно выделить и скопировать следующие строки\n\n```bash\n max\t65000\n min\t45000\n open_price\t49000\n close_price\t50000\n\n```\n\nи перенести их в Google sheets.\n\nВ итоге должен получиться такой график:\n\n\n\n### Подсказки\n\n* Перед тем как писать запросы в файл, можно зайти в репл `psql` в терминале и поэкспериментировать\n* [Тред](https://stackoverflow.com/questions/15537709/what-does-do-in-postgresql) про `::` в PostgreSQL запросах. Может пригодиться, чтобы получить только дату из поля `date_and_time`.\n* В каждом из файлов необходимо написать 3-4 запроса\n","prepared_readme":"В таблице `bitcoin_prices` хранится информация о ценах на Bitcoin за 3 дня.\n\n**bitcoin_prices**\n\n| id | price | date_and_time |\n|----|-------|---------------------|\n| 1 | 40000 | 2022-02-01 09:00:00 |\n| 2 | 35000 | 2022-02-01 13:00:00 |\n| 3 | 50000 | 2022-02-01 18:00:00 |\n\nВам нужно сагрегировать из данной таблицы данные для диаграммы \"Японские свечи\". Решение нужно записать в трёх файлах на каждый из дней: первое, второе и третье января. Запросов в файле может быть сколько угодно, главное, чтобы они в итоге выводили нужные данные.\n\nЧтобы получить записи, которые сделали в определенный день, можно сделать так:\n\n```sql\nselect * from bitcoin_prices where date_and_time::date = '2022-01-01';\n```\n\n```\n id | price | date_and_time\n----+-------+---------------------\n 1 | 45000 | 2022-01-01 09:00:00\n 2 | 37000 | 2022-01-01 12:00:00\n 3 | 57000 | 2022-01-01 15:00:00\n 4 | 48000 | 2022-01-01 18:00:00\n(4 rows)\n```\n\n## first_day.sql\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\n## second_day.sql\n\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\n## third_day.sql\n\nНапишите отдельные запросы, которые выводят поля:\n\n* Поле `min` — минимальная цена за день\n* Поле `max` — максимальная цена за день\n* Поле `open_price` — цена открытия\n* Поле `close_price` — цена закрытия\n\nВизуализируйте данные в виде Candlestick диаграммы в [Google Sheets](https://docs.google.com/spreadsheets). Для этого скопируйте данные из вывода тестов\n\n```bash\nconsole.log\n ┌─────────────┬─────────┐\n │ (index) │ Values │\n ├─────────────┼─────────┤\n │ max │ '65000' │\n │ min │ '45000' │\n │ open_price │ '49000' │\n │ close_price │ '50000' │\n └─────────────┴─────────┘\n\n# ...\n# дальше идет вывод по другим дням\n```\n\nИз этого вывода нам нужно выделить и скопировать следующие строки\n\n```bash\n max\t65000\n min\t45000\n open_price\t49000\n close_price\t50000\n\n```\n\nи перенести их в Google sheets.\n\nВ итоге должен получиться такой график:\n\n\n\n### Подсказки\n\n* Перед тем как писать запросы в файл, можно зайти в репл `psql` в терминале и поэкспериментировать\n* [Тред](https://stackoverflow.com/questions/15537709/what-does-do-in-postgresql) про `::` в PostgreSQL запросах. Может пригодиться, чтобы получить только дату из поля `date_and_time`.\n* В каждом из файлов необходимо написать 3-4 запроса\n","has_solution":true,"entity_name":"Агрегация для candlestick-диаграмм"},"units":[{"id":8350,"name":"theory","url":"/courses/analytics-with-sql/lessons/candlestick-chart/theory_unit"},{"id":9304,"name":"quiz","url":"/courses/analytics-with-sql/lessons/candlestick-chart/quiz_unit"},{"id":8463,"name":"exercise","url":"/courses/analytics-with-sql/lessons/candlestick-chart/exercise_unit"}],"links":[],"ordered_units":[{"id":8350,"name":"theory","url":"/courses/analytics-with-sql/lessons/candlestick-chart/theory_unit"},{"id":9304,"name":"quiz","url":"/courses/analytics-with-sql/lessons/candlestick-chart/quiz_unit"},{"id":8463,"name":"exercise","url":"/courses/analytics-with-sql/lessons/candlestick-chart/exercise_unit"}],"id":3705,"slug":"candlestick-chart","state":"approved","name":"Агрегация для candlestick-диаграмм","course_order":140,"goal":"Учимся строить сandlestick-диаграммы с помощью агрегации","self_study":"Повторите шаги, описанные в уроке.\n","theory_video_provider":null,"theory_video_uid":null,"theory":"В этом уроке мы рассмотрим свечной график или Candlestick chart. Он широко используется для изображения котировок валют. Сегодня мы агрегируем данные валютной пары за 19 лет и построим график в Google Sheets.\n\nЗнания и навыки об агрегации данных для свечного графика позволят работать аналитиком в финансовой сфере.\n\n## Candlestick chart\n\n<div style=\"padding:56.25% 0 0 0;position:relative;\"><iframe src=\"https://player.vimeo.com/video/830137160?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"DA-candlestick-chart\"></iframe></div><script src=\"https://player.vimeo.com/api/player.js\"></script>\n\nПредставим, что у нас есть котировки валюты австралийского доллара относительно американского доллара. Мы хотим узнать, как они меняются со временем. Мы уже умеем строить линейный график, поэтому сначала изобразим его:\n\n\n\nНа этом рисунке мы видим линейный график котировок валют австралийского доллара относительно американского доллара.\n\nНо такой график для отображения котировок неудобен и неинформативен. Мы видим только изменение текущей цены со временем. Торги на рынке происходят в каком-то окне: есть цена открытия и цена закрытия. Цена открытия — это цена, с которой начинаются торги, а по цене закрытия они заканчиваются. Поэтому таблицы с котировками обычно выглядят более сложно:\n\n**currency_exchange**\n\n| date | low | open | high | close |\n| --- | --- | --- | --- | --- |\n| 2018-01-01 | 1.2338 | 1.2781 | 1.2784 | 1.2393 |\n| 2018-02-01 | 1.2456 | 1.2456 | 1.2839 | 1.2819 |\n| 2018-03-01 | 1.2689 | 1.2883 | 1.3034 | 1.3004 |\n| ... | ... | ... | ... | ... |\n\nВ этой таблице представлены котировки валюты с шагом в один месяц. Она содержит такие столбцы:\n\n1. `date` — дата\n2. `low` — минимальное значение цены за этот месяц\n3. `open` — цена открытия. Это первая цена за месяц\n4. `high` — максимальная цена за месяц\n5. `close` — цена закрытия. Это последняя цена за месяц\n\nИз этой таблицы мы понимаем, как торги начинались и заканчивались. Также знаем минимальное и максимальное значение котировок. Для визуального представления таких таблиц используют **свечной график** или **Candlestick chart**. Он удобнее линейного графика, потому что позволяет визуализировать все параметры: цену открытия, закрытия, минимальную и максимальную цены.\n\nПосмотрим, из чего он состоит, и где на нем находятся данные из таблицы:\n\n\n\nНа свечном графике каждый промежуток времени мы изображаем в виде «свечи». У свечи есть тело и фитиль. Нижний и верхний фитили на картинке обозначены как Lower Wick и Upper Wick. Тело свечи отмечено как Real Body. Open и Close — это цены открытия и закрытия.\n\nТело — это прямоугольник, у которого одна из границ — цена открытия, а вторая — закрытия. Цена открытия бывает меньше или больше цены закрытия — это зависит от трендов на рынке.\n\nФитиль рисуется узкой вертикальной линией. Верхняя граница фитиля — это максимальная цена за период торгов, а нижняя — минимальная. Если фитиль длинный, а тело нет — это говорит о том, что рынок очень волатильный, то есть быстро меняется.\n\nПо таблице CurrencyExchange мы можем построить свечной график котировок. Он будет выглядеть так:\n\n\n\nЗдесь мы видим свечной график котировок валют. Он содержит в себе не информацию о текущей стоимости валюты, а цену открытия, закрытия, минимальную и максимальную во временном окне, когда идут торги.\n\nЧтобы получить из таблицы, в которой есть только текущая стоимость, таблицу с ценами открытия, закрытия, минимальной и максимальной, мы агрегируем данные. По агрегированной таблице мы уже построим свечной график.\n\n## Агрегация курсов валют\n\nМы будем агрегировать таблицу курса валют помесячно. Для агрегации мы проделаем такие шаги:\n\n1. Создадим вспомогательную таблицу с первыми и последними значениями цены за месяц\n2. Создадим вспомогательную таблицу для цен открытия и закрытия\n3. Создадим вспомогательные таблицы для минимальных и максимальных значений за месяц\n4. Объединим эти таблицы с помощью SQL-функции `join` и проведем итоговую агрегацию\n\n<div style=\"padding:56.25% 0 0 0;position:relative;\"><iframe src=\"https://player.vimeo.com/video/830138847?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"DA-candlestick-chart-aggregation\"></iframe></div><script src=\"https://player.vimeo.com/api/player.js\"></script>\n\n### Первые и последние значения цены за месяц\n\nОткроем базу [australian_currency](https://www.db-fiddle.com/f/cMY7J4fTP5PxaZU8j8VmTJ/4).\n\nВ базе данных есть таблица `exchange` с двумя полями:\n\n* date — дата, в которую валюта имела определенную стоимость\n* currency — значение котировки валюты\n\nПосмотрим на саму таблицу:\n\n**Currency**\n\n| date | currency |\n| --- | --- |\n| 2000-01-03 | 1.5172 |\n| 2000-01-04 | 1.5239 |\n| 2000-01-05 | 1.5267 |\n| ... | ... |\n| 2019-12-31 | 1.4225 |\n\nВ этой таблице 5019 строк. Мы видим, что в таблице есть данные за 2000-2019 года.\n\nНам нужно создать новую таблицу с минимумом, максимумом, первой ценой и последней ценой за определенный период времени. Мы будем агрегировать данные помесячно.\n\nЧтобы получить первую и последнюю цены за месяц, мы создадим вспомогательную таблицу monthly_dates. В нее мы агрегируем первую и последнюю дату за месяц, само значение месяца и уникальный ключ, по которому мы будем джойнить таблицы:\n\n```SQL\nCREATE TABLE monthly_dates (\n year_month VARCHAR,\n month DATE,\n min_date DATE,\n max_date DATE\n);\n```\n\nМы создали таблицу с полями:\n\n* year_month — уникальный строковый ключ с годом и месяцем\n* month — значение месяца\n* min_date — первая дата за месяц\n* max_date — последняя дата за месяц\n\nАгрегируем данные и запишем их в новую таблицу:\n\n```SQL\nINSERT INTO monthly_dates (\n SELECT\n TO_CHAR(month, 'YYYY-MM') AS year_month,\n month,\n min_date,\n max_date\n FROM (\n SELECT\n DATE_TRUNC('month', date) AS month,\n MIN(date) AS min_date,\n MAX(date) AS max_date\n FROM exchange\n GROUP BY month\n ) AS subquery\n ORDER BY min_date\n);\n```\n\nМы записали в таблицу ключ `year_month`, поле `month`, минимальное значение даты за месяц `min_date` и максимальное значение даты `max_date`.\n\nФункция `concat` применяется, чтобы объединить несколько строковых значений. `date_trunc` позволяет «схлопнуть» даты временного промежутка в один. А с помощью значения `month` в функции `date_trunc` мы использовали агрегацию в месяц.\n\nСортировка по дате нужна, чтобы избежать перемешивания дат. Уникальный ключ, в котором есть год и месяц, нам понадобится в дальнейшем для джойна таблиц.\n\n### Цены открытия и закрытия\n\nТеперь мы создадим таблицу `open`, чтобы сохранить в нее первые значения котировок в месяце. В ней тоже будет уникальный ключ `year_month`, а также первая дата за месяц и значение `open` цены валюты в эту дату:\n\n```SQL\nCREATE TABLE open (\n year_month VARCHAR PRIMARY KEY,\n date DATE,\n open FLOAT\n);\n```\n\nТеперь сджойним таблицу `monthly_dates` с таблицей `open` по минимальной дате. Мы не будем использовать агрегацию, а только возьмем значения котировок в минимальные даты каждого месяца:\n\n```SQL\nINSERT INTO open\nSELECT\n year_month,\n exchange.date,\n currency AS open\nFROM exchange\nINNER JOIN monthly_dates ON exchange.date = monthly_dates.min_date\nORDER BY date;\n```\n\nПо аналогии с таблицей `open` создадим таблицу `close`, в которой будет последнее значение валюты за месяц. Мы будем джойнить ее с таблицей `monthly_dates` по максимальной дате месяца:\n\n```SQL\nCREATE TABLE close (\n year_month VARCHAR PRIMARY KEY,\n date DATE,\n close FLOAT\n);\n\nINSERT INTO close\nSELECT\n year_month,\n exchange.date,\n currency as close\nFROM exchange\nINNER JOIN monthly_dates ON exchange.date = monthly_dates.max_date\nORDER BY date;\n```\n\n### Минимальные и максимальные цены за месяц\n\nТеперь мы создадим таблицу `min_max_currency`. В ней будет значение месяца, потому что мы агрегируем минимальное и максимальное значения валюты за месяц, и сами минимальное и максимальное значения котировок:\n\n```SQL\nCREATE TABLE min_max_currency (\n month DATE,\n min_currency FLOAT,\n max_currency FLOAT\n);\n```\n\nАгрегируем таблицу `exchange` по минимальным и максимальным помесячным значениям валют и запишем в `min_max_currency`. Для помесячной агрегации мы используем функцию `date_trunc`:\n\n```SQL\nINSERT INTO min_max_currency\nSELECT\n DATE_TRUNC('month', date) AS month,\n MIN(currency) AS min_currency,\n MAX(currency) AS max_currency\nFROM exchange\nGROUP BY month\nORDER BY month;\n```\n\n### Витрина данных и свечной график\n\nТеперь осталось создать таблицу с витриной, в которой будут уникальный ключ, цена открытия и закрытия и минимальная и максимальная цены:\n\n```SQL\nCREATE TABLE data_mart (\n year_month VARCHAR,\n month DATE,\n min_currency FLOAT,\n open FLOAT,\n max_currency FLOAT,\n close FLOAT\n);\n```\n\nДля создания витрины мы сджойним таблицы `monthly_dates`, `open`, `close` и `min_max_currency`:\n\n```SQL\nINSERT INTO data_mart\n(\n SELECT\n monthly_dates.year_month,\n monthly_dates.month,\n min_currency,\n open,\n max_currency,\n close\n FROM monthly_dates\n INNER JOIN open ON monthly_dates.year_month = open.year_month\n INNER JOIN close ON open.year_month = close.year_month\n INNER JOIN min_max_currency ON monthly_dates.month = min_max_currency.month\n ORDER BY month\n);\n```\n\nМы создали витрину данных, по которой будем строить свечной график. Мы сделали джойн таблиц `monthly_dates`, `open` и `close` по ключу `year_month` и полученной таблицы с `min_max_currency` по значению месяца `month`.\n\nИтоговая таблица содержит 240 строк и выглядит так:\n\n**data_mart**\n\n| year_month | month | min_currency | open | max_currency | close |\n| --- | --- | --- | --- | --- | --- |\n| 2000-1 | 2000-01-01 | 1.4954 | 1.5172 | 1.5962 | 1.5669 |\n| 2000-2 | 2000-02-01 | 1.5657 | 1.5835 | 1.6351 | 1.6247 |\n| 2000-3 | 2000-03-01 | 1.6221 | 1.6483 | 1.6622 | 1.6496 |\n| ... | ... | ... | ... | ... | ... |\n| 2019-12 | 2019-12-01 | 1.4225 | 1.4665 | 1.4676 | 1.4225 |\n\nВ ней есть поля:\n\n* year_month — уникальный строковый ключ\n* month — месяц, по которому производилась агрегация\n* min_currency — минимальное значение валюты за месяц\n* open — первое значение валюты за месяц\n* max_currency — максимальное значение валюты за месяц\n* close - последнее значение валюты за месяц\n\nПоля идут в таком порядке, потому что так по ним удобнее строить Candlestick Chart в Google Sheets.\n\nПостроим график по следующим шагам:\n\n1. Скопируем витрину в Google Sheets\n2. Выделим все столбцы, кроме `year_month`\n3. Для столбца `month` выберем «Формат» -> «Числа» -> «Обычный текст»\n4. В столбцах с котировками заменим все точки на запятые\n5. Вставим диаграмму и типом диаграммы выберем «График \"японские свечи\"»\n\nВ итоге мы получим график, который видели выше:\n\n\n\nМы построили свечной график по помесячным котировкам. Видим, что он состоит из свечей. Но на нем слишком много данных и мы не можем посмотреть на фитили. Поэтому возьмем только данные за 2019 год и запишем их в таблицу `data_mart_new_data`:\n\n```SQL\nCREATE TABLE data_mart_new_data (\n year_month VARCHAR,\n month DATA,\n min_currency FLOAT,\n open FLOAT,\n max_currency FLOAT,\n close FLOAT\n);\n\nINSERT INTO data_mart_new_data (\n SELECT * FROM data_mart\n WHERE month >= '2019-01-01'\n);\n```\n\nЗдесь мы отобрали все даты, которые больше или равны 1 января 2019 года.\n\nТеперь построим свечной график по этим данным. В дополнительных настройках вертикальной оси установим минимальное значение 1.2, чтобы рассмотреть график на большем масштабе:\n\n\n\nМы построили свечной график котировок валют за 2018-2019 год. На этом графике отчетливо видно, что свечной график состоит из тела свечи и фитилей. Границы тела определяются ценой открытия и закрытия, а фитили — минимальным и максимальным значениями за месяц.\n\n## Выводы\n\nВ этом уроке мы научились агрегировать данные для свечного графика. Мы взяли котировки валютной пары австралийского доллара и доллара США, сделали помесячную агрегацию валют и построили свечной график в Google Sheets. Агрегация валют позволит работать в финансовой сфере и строить отчеты по валютным парам.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":7100,"name":"theory","url":"/courses/analytics-with-sql/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":7100,"name":"theory","url":"/courses/analytics-with-sql/lessons/intro/theory_unit"}],"id":3144,"slug":"intro","state":"approved","name":"Введение","course_order":50,"goal":"Знакомимся с темой курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"В этом курсе мы изучим тему «Продвинутая аналитика на SQL». Полученные знания и навыки понадобятся, чтобы извлекать данные из больших наборов данных, превращать их в понятную и управляемую форму и создавать отчеты, которые помогут принимать более обоснованные решения.\n\nТакже в результате обучения вы сможете обеспечить безопасность и эффективность хранения и использования данных.\n\n## Какие темы изучим на курсе\n\nВ рамках курса мы изучим следующие темы:\n\n* Концепция витрины\n* Устройство графиков\n* Агрегация для визуализации\n* Агрегация для столбчатой диаграммы\n* Агрегация для candlestick-диаграм\n* Pie Chart\n* Scatter Chart\n* Funnel analysis\n* Устройство таблиц\n\nМы узнаем, что в основе любого графика лежит таблица с данными. В итоге научимся производить агрегацию для визуализации. Полученные навыки пригодятся, если нужно анализировать полученные данные с помощью разных диаграмм. Знания из этого курса помогут построить столбчатую, круговую, точечную и candlestick-диаграммы.\n"},"id":305,"slug":"analytics-with-sql","challenges_count":3,"name":"Продвинутая аналитика на SQL","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы научитесь строить графики на основе данных, полученных с помощью SQL-запросов. Вы узнаете, что в основе любого графика лежит таблица с данными. В итоге вы научитесь производить агрегацию для визуализации. Полученные навыки пригодятся, если вы решите анализировать полученные данные с помощью разных диаграмм. Знания из этого курса помогут построить столбчатую, круговую, точечную и candlestick-диаграммы.","kind":"advanced","updated_at":"2026-01-20T11:54:43.063Z","language":"sql","duration_cache":39420,"skills":["Объединять Google Sheets и SQL","Отображать результаты запросов в виде графиков и диаграмм","Строить и анализировать различные диаграммы","Производить агрегацию для визуализации"],"keywords":[],"lessons_count":10,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTA2OCwicHVyIjoiYmxvYl9pZCJ9fQ==--0d42690e9597873346e7166608b35971ac254007/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"recommendedLandings":[{"stack":{"id":55,"slug":"data-analytics","title":"Аналитик данных","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":80,"duration_in_months":7},"id":98,"slug":"data-analytics","title":"Аналитик данных","subtitle":"Изучите SQL, Python, Pandas, Tableau, Superset и методы A/B-тестов.","subtitle_for_lists":"Изучите SQL, Python, Pandas, Tableau, Superset и методы A/B-тестов.","locale":"ru","current":true,"duration_in_months_text":"7 месяцев","stack_slug":"data-analytics","price_text":"от 4 395 ₽","duration_text":"7 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzY1MywicHVyIjoiYmxvYl9pZCJ9fQ==--5107185de77b3481e0a836f9fc7326c4e1b77be4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20extraction-pana.png"},{"stack":{"id":75,"slug":"sql-for-data-analysts","title":"SQL для анализа данных","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":1100,"duration_in_months":3},"id":133,"slug":"sql-for-data-analysts","title":"SQL для анализа данных","subtitle":"Навык работы с SQL, включая соединения, оконные функции и аналитику, для уверенного написания сложных запросов к БД","subtitle_for_lists":"Изучите SQL, соединения, оконные функции","locale":"ru","current":true,"duration_in_months_text":"3 месяца","stack_slug":"sql-for-data-analysts","price_text":"от 3 900 ₽","duration_text":"3 месяца","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk1MywicHVyIjoiYmxvYl9pZCJ9fQ==--963098414ddb264ba6c4deab9bd951f2d6778e4a/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20analysis-amico.png"},{"stack":{"id":227,"slug":"bi-analyst","title":"BI-аналитик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"not_finished","order":null,"duration_in_months":7},"id":359,"slug":"bi-analyst","title":"BI-аналитик","subtitle":"Изучите SQL, BI-инструменты и визуализацию данных","subtitle_for_lists":"Изучите SQL, BI-инструменты и визуализацию данных","locale":"ru","current":true,"duration_in_months_text":"7 месяцев","stack_slug":"bi-analyst","price_text":"от 4 395 ₽","duration_text":"7 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg3MSwicHVyIjoiYmxvYl9pZCJ9fQ==--8175585f43b5401994e29b3ae73d76963d942512/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Browser%20stats-bro.png"},{"stack":{"id":462,"slug":"product-analyst","title":"Продуктовый аналитик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"not_finished","order":500,"duration_in_months":7},"id":591,"slug":"product-analyst","title":"Продуктовый аналитик","subtitle":"Изучите продуктовые метрики, A/B-тесты и анализ пользовательских данных","subtitle_for_lists":"Изучите продуктовые метрики, A/B-тесты и анализ пользовательских данных","locale":"ru","current":true,"duration_in_months_text":"7 месяцев","stack_slug":"product-analyst","price_text":"от 4 395 ₽","duration_text":"7 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg2MiwicHVyIjoiYmxvYl9pZCJ9fQ==--04a703ca18d7bf689064f1f3c2721058bd5564e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Statistics-bro.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/analytics-with-sql/lessons/candlestick-chart/theory_unit","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Продвинутая аналитика на SQL</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Агрегация для candlestick-диаграмм</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Агрегация для candlestick-диаграмм","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"Продвинутая аналитика на SQL"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>В этом уроке мы рассмотрим свечной график или Candlestick chart. Он широко используется для изображения котировок валют. Сегодня мы агрегируем данные валютной пары за 19 лет и построим график в Google Sheets.</p>
<p>Знания и навыки об агрегации данных для свечного графика позволят работать аналитиком в финансовой сфере.</p>
<h2 id="heading-2-1">Candlestick chart</h2>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/830137160?badge=0&autopause=0&player_id=0&app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media" style="position:absolute;top:0;left:0;width:100%;height:100%" title="DA-candlestick-chart"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
<p>Представим, что у нас есть котировки валюты австралийского доллара относительно американского доллара. Мы хотим узнать, как они меняются со временем. Мы уже умеем строить линейный график, поэтому сначала изобразим его:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTEwMSwicHVyIjoiYmxvYl9pZCJ9fQ==--30b087a760997dffc5141c326f253fa92d64e481/aus_us_linear_chart.png" alt="aus_us_linear_chart" loading="lazy"/></p>
<p>На этом рисунке мы видим линейный график котировок валют австралийского доллара относительно американского доллара.</p>
<p>Но такой график для отображения котировок неудобен и неинформативен. Мы видим только изменение текущей цены со временем. Торги на рынке происходят в каком-то окне: есть цена открытия и цена закрытия. Цена открытия — это цена, с которой начинаются торги, а по цене закрытия они заканчиваются. Поэтому таблицы с котировками обычно выглядят более сложно:</p>
<p><strong>currency_exchange</strong></p>
<div style="--table-min-width:calc(50rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_a100c15 mantine-TableScrollContainer-scrollContainer m_d57069b5 mantine-ScrollArea-root"><div style="overflow-x:hidden;overflow-y:hidden" class="m_c0783ff9 mantine-ScrollArea-viewport" data-offset-scrollbars="x" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><div class="m_62259741 mantine-TableScrollContainer-scrollContainerInner"><table><thead><tr><th>date</th><th>low</th><th>open</th><th>high</th><th>close</th></tr></thead><tbody><tr><td>2018-01-01</td><td>1.2338</td><td>1.2781</td><td>1.2784</td><td>1.2393</td></tr><tr><td>2018-02-01</td><td>1.2456</td><td>1.2456</td><td>1.2839</td><td>1.2819</td></tr><tr><td>2018-03-01</td><td>1.2689</td><td>1.2883</td><td>1.3034</td><td>1.3004</td></tr><tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr></tbody></table></div></div></div></div>
<p>В этой таблице представлены котировки валюты с шагом в один месяц. Она содержит такие столбцы:</p>
<ol>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">date</code> — дата</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">low</code> — минимальное значение цены за этот месяц</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code> — цена открытия. Это первая цена за месяц</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">high</code> — максимальная цена за месяц</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">close</code> — цена закрытия. Это последняя цена за месяц</li>
</ol>
<p>Из этой таблицы мы понимаем, как торги начинались и заканчивались. Также знаем минимальное и максимальное значение котировок. Для визуального представления таких таблиц используют <strong>свечной график</strong> или <strong>Candlestick chart</strong>. Он удобнее линейного графика, потому что позволяет визуализировать все параметры: цену открытия, закрытия, минимальную и максимальную цены.</p>
<p>Посмотрим, из чего он состоит, и где на нем находятся данные из таблицы:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTEwMiwicHVyIjoiYmxvYl9pZCJ9fQ==--42d0a8a7103ab346593c0f09dd998bc8869d3e29/candlestick_chart_explanation.png" alt="candlestick_chart_explanation" loading="lazy"/></p>
<p>На свечном графике каждый промежуток времени мы изображаем в виде «свечи». У свечи есть тело и фитиль. Нижний и верхний фитили на картинке обозначены как Lower Wick и Upper Wick. Тело свечи отмечено как Real Body. Open и Close — это цены открытия и закрытия.</p>
<p>Тело — это прямоугольник, у которого одна из границ — цена открытия, а вторая — закрытия. Цена открытия бывает меньше или больше цены закрытия — это зависит от трендов на рынке.</p>
<p>Фитиль рисуется узкой вертикальной линией. Верхняя граница фитиля — это максимальная цена за период торгов, а нижняя — минимальная. Если фитиль длинный, а тело нет — это говорит о том, что рынок очень волатильный, то есть быстро меняется.</p>
<p>По таблице CurrencyExchange мы можем построить свечной график котировок. Он будет выглядеть так:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTEwMywicHVyIjoiYmxvYl9pZCJ9fQ==--9f32d8ff27b454e2cff40f844cb0825dbb651ba7/full_candlestick_chart.png" alt="full_candlestick_chart" loading="lazy"/></p>
<p>Здесь мы видим свечной график котировок валют. Он содержит в себе не информацию о текущей стоимости валюты, а цену открытия, закрытия, минимальную и максимальную во временном окне, когда идут торги.</p>
<p>Чтобы получить из таблицы, в которой есть только текущая стоимость, таблицу с ценами открытия, закрытия, минимальной и максимальной, мы агрегируем данные. По агрегированной таблице мы уже построим свечной график.</p>
<h2 id="heading-2-2">Агрегация курсов валют</h2>
<p>Мы будем агрегировать таблицу курса валют помесячно. Для агрегации мы проделаем такие шаги:</p>
<ol>
<li>Создадим вспомогательную таблицу с первыми и последними значениями цены за месяц</li>
<li>Создадим вспомогательную таблицу для цен открытия и закрытия</li>
<li>Создадим вспомогательные таблицы для минимальных и максимальных значений за месяц</li>
<li>Объединим эти таблицы с помощью SQL-функции <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">join</code> и проведем итоговую агрегацию</li>
</ol>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/830138847?badge=0&autopause=0&player_id=0&app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media" style="position:absolute;top:0;left:0;width:100%;height:100%" title="DA-candlestick-chart-aggregation"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
<h3 id="heading-3-3">Первые и последние значения цены за месяц</h3>
<p>Откроем базу <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://www.db-fiddle.com/f/cMY7J4fTP5PxaZU8j8VmTJ/4" rel="noopener noreferrer" target="_blank">australian_currency</a>.</p>
<p>В базе данных есть таблица <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">exchange</code> с двумя полями:</p>
<ul>
<li>date — дата, в которую валюта имела определенную стоимость</li>
<li>currency — значение котировки валюты</li>
</ul>
<p>Посмотрим на саму таблицу:</p>
<p><strong>Currency</strong></p>
<div style="--table-min-width:calc(50rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_a100c15 mantine-TableScrollContainer-scrollContainer m_d57069b5 mantine-ScrollArea-root"><div style="overflow-x:hidden;overflow-y:hidden" class="m_c0783ff9 mantine-ScrollArea-viewport" data-offset-scrollbars="x" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><div class="m_62259741 mantine-TableScrollContainer-scrollContainerInner"><table><thead><tr><th>date</th><th>currency</th></tr></thead><tbody><tr><td>2000-01-03</td><td>1.5172</td></tr><tr><td>2000-01-04</td><td>1.5239</td></tr><tr><td>2000-01-05</td><td>1.5267</td></tr><tr><td>...</td><td>...</td></tr><tr><td>2019-12-31</td><td>1.4225</td></tr></tbody></table></div></div></div></div>
<p>В этой таблице 5019 строк. Мы видим, что в таблице есть данные за 2000-2019 года.</p>
<p>Нам нужно создать новую таблицу с минимумом, максимумом, первой ценой и последней ценой за определенный период времени. Мы будем агрегировать данные помесячно.</p>
<p>Чтобы получить первую и последнюю цены за месяц, мы создадим вспомогательную таблицу monthly_dates. В нее мы агрегируем первую и последнюю дату за месяц, само значение месяца и уникальный ключ, по которому мы будем джойнить таблицы:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE monthly_dates (
year_month VARCHAR,
month DATE,
min_date DATE,
max_date DATE
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Мы создали таблицу с полями:</p>
<ul>
<li>year_month — уникальный строковый ключ с годом и месяцем</li>
<li>month — значение месяца</li>
<li>min_date — первая дата за месяц</li>
<li>max_date — последняя дата за месяц</li>
</ul>
<p>Агрегируем данные и запишем их в новую таблицу:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">INSERT INTO monthly_dates (
SELECT
TO_CHAR(month, 'YYYY-MM') AS year_month,
month,
min_date,
max_date
FROM (
SELECT
DATE_TRUNC('month', date) AS month,
MIN(date) AS min_date,
MAX(date) AS max_date
FROM exchange
GROUP BY month
) AS subquery
ORDER BY min_date
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Мы записали в таблицу ключ <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">year_month</code>, поле <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">month</code>, минимальное значение даты за месяц <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min_date</code> и максимальное значение даты <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">max_date</code>.</p>
<p>Функция <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">concat</code> применяется, чтобы объединить несколько строковых значений. <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">date_trunc</code> позволяет «схлопнуть» даты временного промежутка в один. А с помощью значения <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">month</code> в функции <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">date_trunc</code> мы использовали агрегацию в месяц.</p>
<p>Сортировка по дате нужна, чтобы избежать перемешивания дат. Уникальный ключ, в котором есть год и месяц, нам понадобится в дальнейшем для джойна таблиц.</p>
<h3 id="heading-3-4">Цены открытия и закрытия</h3>
<p>Теперь мы создадим таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code>, чтобы сохранить в нее первые значения котировок в месяце. В ней тоже будет уникальный ключ <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">year_month</code>, а также первая дата за месяц и значение <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code> цены валюты в эту дату:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE open (
year_month VARCHAR PRIMARY KEY,
date DATE,
open FLOAT
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Теперь сджойним таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">monthly_dates</code> с таблицей <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code> по минимальной дате. Мы не будем использовать агрегацию, а только возьмем значения котировок в минимальные даты каждого месяца:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">INSERT INTO open
SELECT
year_month,
exchange.date,
currency AS open
FROM exchange
INNER JOIN monthly_dates ON exchange.date = monthly_dates.min_date
ORDER BY date;</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>По аналогии с таблицей <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code> создадим таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">close</code>, в которой будет последнее значение валюты за месяц. Мы будем джойнить ее с таблицей <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">monthly_dates</code> по максимальной дате месяца:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE close (
year_month VARCHAR PRIMARY KEY,
date DATE,
close FLOAT
);
INSERT INTO close
SELECT
year_month,
exchange.date,
currency as close
FROM exchange
INNER JOIN monthly_dates ON exchange.date = monthly_dates.max_date
ORDER BY date;</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h3 id="heading-3-5">Минимальные и максимальные цены за месяц</h3>
<p>Теперь мы создадим таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min_max_currency</code>. В ней будет значение месяца, потому что мы агрегируем минимальное и максимальное значения валюты за месяц, и сами минимальное и максимальное значения котировок:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE min_max_currency (
month DATE,
min_currency FLOAT,
max_currency FLOAT
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Агрегируем таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">exchange</code> по минимальным и максимальным помесячным значениям валют и запишем в <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min_max_currency</code>. Для помесячной агрегации мы используем функцию <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">date_trunc</code>:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">INSERT INTO min_max_currency
SELECT
DATE_TRUNC('month', date) AS month,
MIN(currency) AS min_currency,
MAX(currency) AS max_currency
FROM exchange
GROUP BY month
ORDER BY month;</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h3 id="heading-3-6">Витрина данных и свечной график</h3>
<p>Теперь осталось создать таблицу с витриной, в которой будут уникальный ключ, цена открытия и закрытия и минимальная и максимальная цены:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE data_mart (
year_month VARCHAR,
month DATE,
min_currency FLOAT,
open FLOAT,
max_currency FLOAT,
close FLOAT
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Для создания витрины мы сджойним таблицы <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">monthly_dates</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">close</code> и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min_max_currency</code>:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">INSERT INTO data_mart
(
SELECT
monthly_dates.year_month,
monthly_dates.month,
min_currency,
open,
max_currency,
close
FROM monthly_dates
INNER JOIN open ON monthly_dates.year_month = open.year_month
INNER JOIN close ON open.year_month = close.year_month
INNER JOIN min_max_currency ON monthly_dates.month = min_max_currency.month
ORDER BY month
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Мы создали витрину данных, по которой будем строить свечной график. Мы сделали джойн таблиц <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">monthly_dates</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">open</code> и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">close</code> по ключу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">year_month</code> и полученной таблицы с <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min_max_currency</code> по значению месяца <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">month</code>.</p>
<p>Итоговая таблица содержит 240 строк и выглядит так:</p>
<p><strong>data_mart</strong></p>
<div style="--table-min-width:calc(50rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_a100c15 mantine-TableScrollContainer-scrollContainer m_d57069b5 mantine-ScrollArea-root"><div style="overflow-x:hidden;overflow-y:hidden" class="m_c0783ff9 mantine-ScrollArea-viewport" data-offset-scrollbars="x" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><div class="m_62259741 mantine-TableScrollContainer-scrollContainerInner"><table><thead><tr><th>year_month</th><th>month</th><th>min_currency</th><th>open</th><th>max_currency</th><th>close</th></tr></thead><tbody><tr><td>2000-1</td><td>2000-01-01</td><td>1.4954</td><td>1.5172</td><td>1.5962</td><td>1.5669</td></tr><tr><td>2000-2</td><td>2000-02-01</td><td>1.5657</td><td>1.5835</td><td>1.6351</td><td>1.6247</td></tr><tr><td>2000-3</td><td>2000-03-01</td><td>1.6221</td><td>1.6483</td><td>1.6622</td><td>1.6496</td></tr><tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr><tr><td>2019-12</td><td>2019-12-01</td><td>1.4225</td><td>1.4665</td><td>1.4676</td><td>1.4225</td></tr></tbody></table></div></div></div></div>
<p>В ней есть поля:</p>
<ul>
<li>year_month — уникальный строковый ключ</li>
<li>month — месяц, по которому производилась агрегация</li>
<li>min_currency — минимальное значение валюты за месяц</li>
<li>open — первое значение валюты за месяц</li>
<li>max_currency — максимальное значение валюты за месяц</li>
<li>close - последнее значение валюты за месяц</li>
</ul>
<p>Поля идут в таком порядке, потому что так по ним удобнее строить Candlestick Chart в Google Sheets.</p>
<p>Построим график по следующим шагам:</p>
<ol>
<li>Скопируем витрину в Google Sheets</li>
<li>Выделим все столбцы, кроме <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">year_month</code></li>
<li>Для столбца <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">month</code> выберем «Формат» -> «Числа» -> «Обычный текст»</li>
<li>В столбцах с котировками заменим все точки на запятые</li>
<li>Вставим диаграмму и типом диаграммы выберем «График "японские свечи"»</li>
</ol>
<p>В итоге мы получим график, который видели выше:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTEwNCwicHVyIjoiYmxvYl9pZCJ9fQ==--b93568f3b280a895584e4d6f763f858559a66700/full_candlestick_chart.png" alt="full_candlestick_chart" loading="lazy"/></p>
<p>Мы построили свечной график по помесячным котировкам. Видим, что он состоит из свечей. Но на нем слишком много данных и мы не можем посмотреть на фитили. Поэтому возьмем только данные за 2019 год и запишем их в таблицу <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">data_mart_new_data</code>:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">CREATE TABLE data_mart_new_data (
year_month VARCHAR,
month DATA,
min_currency FLOAT,
open FLOAT,
max_currency FLOAT,
close FLOAT
);
INSERT INTO data_mart_new_data (
SELECT * FROM data_mart
WHERE month >= '2019-01-01'
);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Здесь мы отобрали все даты, которые больше или равны 1 января 2019 года.</p>
<p>Теперь построим свечной график по этим данным. В дополнительных настройках вертикальной оси установим минимальное значение 1.2, чтобы рассмотреть график на большем масштабе:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTEwNSwicHVyIjoiYmxvYl9pZCJ9fQ==--505c169d26a004b2cbbfb201858dee43973306a7/candlestick_chart_2019.png" alt="candlestick_chart_2019" loading="lazy"/></p>
<p>Мы построили свечной график котировок валют за 2018-2019 год. На этом графике отчетливо видно, что свечной график состоит из тела свечи и фитилей. Границы тела определяются ценой открытия и закрытия, а фитили — минимальным и максимальным значениями за месяц.</p>
<h2 id="heading-2-7">Выводы</h2>
<p>В этом уроке мы научились агрегировать данные для свечного графика. Мы взяли котировки валютной пары австралийского доллара и доллара США, сделали помесячную агрегацию валют и построили свечной график в Google Sheets. Агрегация валют позволит работать в финансовой сфере и строить отчеты по валютным парам.</p></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/data-analytics?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">7 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Аналитик данных</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите SQL, Python, Pandas, Tableau, Superset и методы A/B-тестов.</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzY1MywicHVyIjoiYmxvYl9pZCJ9fQ==--5107185de77b3481e0a836f9fc7326c4e1b77be4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20extraction-pana.png" alt="Аналитик данных" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 395 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/sql-for-data-analysts?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">3 месяца</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">SQL для анализа данных</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите SQL, соединения, оконные функции</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk1MywicHVyIjoiYmxvYl9pZCJ9fQ==--963098414ddb264ba6c4deab9bd951f2d6778e4a/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Data%20analysis-amico.png" alt="SQL для анализа данных" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/bi-analyst?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">7 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">BI-аналитик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите SQL, BI-инструменты и визуализацию данных</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg3MSwicHVyIjoiYmxvYl9pZCJ9fQ==--8175585f43b5401994e29b3ae73d76963d942512/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Browser%20stats-bro.png" alt="BI-аналитик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 395 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/product-analyst?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">7 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Продуктовый аналитик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите продуктовые метрики, A/B-тесты и анализ пользовательских данных</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDg2MiwicHVyIjoiYmxvYl9pZCJ9fQ==--04a703ca18d7bf689064f1f3c2721058bd5564e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Statistics-bro.png" alt="Продуктовый аналитик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 395 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/analytics-with-sql/lessons/candlestick-chart/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 10</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/analytics-with-sql/lessons/candlestick-chart/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>