Это интервью с Антоном Батяевым (batiaev) из Технологического Центра Дойче Банка. Мы поговорим о том, чем занимаются финансовые математики, откуда берутся данные в банках, как обрабатываются и оптимизируются. О сложности попадания в финансовую сферу, торговле на бирже и общей необходимости в банках.
Что и как считают в банке?
— Представься, пожалуйста: расскажи, кто ты, чем занимаешься.
Я перешел в ТехЦентр Дойче Банка в начале января этого года и сейчас занимаюсь разработкой серверной части на проекте, который считает различного рода риски по финансовым инструментам для множества разных трейдеров по всему миру и иных команд, которым требуются эти данные.
В рамках проекта построена довольно обширная инфраструктура, которая использует много популярных стандартных фреймворков, нереляционные базы данных, работает с большими данными на Kafka. Также мы работаем с гридом на десятки тысяч CPU, используем различные кастомные проекты, оптимизируем работу с protobuf, реализуем расчеты в финансовой математике,
В рамках инфраструктуры есть ряд дополнительных оптимизаций и фишек. Возможно, это очевидно, но последовательно и логично рассказать, что происходит в банке — крайне непросто.Пару процентов накинули и получили финрез — это сложная математика, алгоритмы и большие инфраструктурные, технические и оптимизационные задачи.
— Давай по порядку. Ты сказал, что в ТехЦентре вы занимаетесь расчетами для глобальной банковской платформы. А что вообще можно считать в банке?
Исходя из моего опыта, в рамках инвестиционной деятельности считаются как цены, так и ряд других показателей различных инструментов. Если говорить об акциях, то всё понятно: котировка — это есть их цена. Для облигаций это будет процент от номинала.
Если говорить о деривативах (производных финансовых инструментах), там цена — размер премии, которую надо уплатить за этот инструмент. Она рассчитывается по множеству различных формул. Есть формула Black-Scholes, которая оценивает стоимость опционов — это функция, которая зависит от функции текущей котировки, базового актива, волатильности, времени до экспирации и множества других факторов.
Есть модели, которые позволяют рассчитать стоимость портфеля трейдера. У отдела или компании есть набор сделок, производных финансовых инструментов в портфеле, и нужно посчитать, сколько они сейчас стоят. В отдельности может быть одна цена, а в совокупности они могут как-то коррелировать, давать скидки и так далее. По отдельности может быть одна цена, а в совокупности — они могут как-то коррелировать, давать скидки и так далее. Например, синтетические позиции: как из опционов собрать позицию, эквивалентную фьючерсной. Это подходит, например, для нелинейных активов типа опционов, но не обязательно верно для всех типов деривативов. Оценка строится на основании котировки базового актива, на котором построен дериватив. Например, котировка одной или нескольких валютных пар. Деривативы могут быть построены на разных базовых активах: для валютных базовыми активами будут евро, доллар и так далее; для товарных деривативов – нефть, золото, пшеница; для спотовых – различные акции и облигации.
Помимо оценки деривативов также считаются риски — что случится, если цены на рынке будет штормить сильнее (изменится волатильность). Или что случится, если доллар будет стоить по отношению к одной или всем другим валютам не 60, а 100 рублей. Что произойдет с конкретным инструментом, портфелем.
Нужно рассчитывать это в режиме реального времени, а также аппроксимировать текущее состояние портфеля на различные неблагоприятные исходы движения цены по каждой из валют, изменению волатильности на рынке. Для этого строим матрицу всех возможных изменений, которая показывает, что есть сейчас, что произойдет завтра и что будет, если случится кризис на рынке.
Это нужно для того, чтобы оценивать, что покупать и продавать в текущем моменте и какие есть риски. И, в том числе, оценивать, что произойдет в будущем, оценивать торговые стратегии и точнее реагировать на изменение рынка. К примеру, кто-то из квантов придумал новый алгоритм расчёта рисков — нужно проверить на исторических данных, прогнать, например, по всей биржевой информации за десятки лет и посмотреть, что будет.
Под эти нужды есть инфраструктура, подключенная к различным биржевым площадкам, которые транслируют нам рыночные данные. Поскольку у нашей компании очень много данных по всему миру, нужно их как-то хранить и строить предагрегаты, чтобы их быстро обрабатывать.
— Прежде чем мы перейдем к инфраструктурной части, хочется поспрашивать о том, что ты уже рассказал. Ты говорил про кучу всяких алгоритмов анализа, откуда эти алгоритмы берутся? Это какие-то книжные знания или ваши наработки?
Тут есть несколько моментов. Во-первых, берутся общеизвестные формулы, алгоритмы, придуманные математиками. Например, общепринятая модель ценообразования опционов — формула Блэка-Шоулза. Но, помимо этого, есть свои внутренние доработки: в частности, используем другие законы распределения цен, подкручиваем коэффициенты в этих формулах. Формула кривой распределения цен, сделок и других показателей может сильно отличаться.
Если говорить про оптимизации, это уже внутренние доработки. Например, разработчики могут вместо того, чтобы рассчитывать показатели в каждой точке, считать ключевые значения и заниматься аппроксимацией, которая будет стоить в 20 раз меньше компьютерного времени, но при этом даст допустимую и достаточную точность.
Все данные постоянно меняются, и нам это важно не только для отчетности, а также для того, чтобы давать трейдерам актуальную картину состояния рынка.
— Это довольно сложная информация, и её, наверное, довольно сложно передать от человека к человеку. Какой у вас размер команды, и как вы передаете знания между собой?
На нашем проекте в Москве работает 35 человек. Это несколько команд, которые занимаются теми или иными кусочками функциональности: UI, бэкенд, инфраструктура, финансовая математика. Каждая такая команда обладает глубокой экспертизой в функционале конкретного модуля. Но помимо этих людей есть еще столько же человек, которые занимаются связанными с нашим проектом системами.
Вся информация о нашем проекте описана аналитиками на Confluence, также она содержится в описаниях задач в JIRA, где есть ссылки на стандартные механизмы и публичные формулы. Примеры использования функциональности можно найти в тестах. Ну и человеческое общение никто не отменял.
— Финансовые математики: сколько их и кто это такие? Какие-то важные ученые?
Да, в основном это специалисты (кванты), которые сидят в Лондоне и строят финансовые модели того, как работает рынок. Чаще всего у них PhD в области финансов или математики. Они знают, как работает рынок, что необходимо трейдерам, и могут придумать какую-то математическую модель, которая описывает состояние рынка, алгоритмы расчетов рисков и корректной оценки деривативов.
Например, мой коллега Александр написал статью на Хабре, где уже упоминал опыт работы с квантом.
— А обычные разработчики могут с ними общаться? Как это общение происходит? Ведь у математики и обычной разработки миры совсем разные.
Могут общаться и общаются: понятно, что какие-то верхнеуровневые бизнесовые задачи и концепции обсуждаются с лидами, но в рамках конкретных расчетов рисков или иных показателей происходит прямое общение разработчика с трейдером или квантом, который строил эту модель.
Но на самом деле это обоюдный процесс взаимодействия, поскольку не всегда теоретический алгоритм реализуем на практике. Поэтому разработчики могут предлагать изменения в модели, чтобы она ложилась на текущую архитектуру приложения.
Способов взаимодействия много — тот же скайп, телефон, все стандартные инструменты связи.
— Софт, который получается в результате, — автоматический? Это роботы или есть что-то для трейдеров, которые техническим анализом занимаются — графики или что-то ещё такое?
Есть несколько вариантов использования софта: первый — автоматический, т.е. торговые роботы, второй представляет собой помощника для трейдера, который показывает текущее состояние портфеля, детализацию имеющихся рисков по разным показателям, варианты торговых операций, которые он сейчас может сделать, а также будущее состояние портфеля и рисков по результатам этих операций. Есть также показатели для трейдеров, расчет рисков и данные по состоянию портфелей.
— Другая метрика — частота анализа данных, как часто вы это делаете? С одной стороны спектра, как я понимаю, какие-то микросекунды, а с другой — анализ больших данных, которые могут неделями идти.
В зависимости от сложности и важности показателей, это могут быть live-показатели, которые пересчитываются на каждый тик, и тогда расчет идет на миллисекунды. А в случае если мы рассчитываем стоимость портфелей, то обновления происходят раз в секунду, чтобы человеческий взгляд успевал это воспринимать.
Если описывать долгие расчеты (например, какие-то сложные риски), данные по которым нужны в течение дня, то задачи отправляются на грид, считается сценарий изменения котировок валют. Общий механизм выглядит следующим образом: ты считаешь все новые сделки в рамках определенного цикла, потом делаешь тяжелую задачу на гриде на пересчет показателей по всей совокупности сделок на текущем состоянии рынка.
Такие задачи могут обновляться раз в час. Если нужно прогнать торговые стратегии — это долгая задача, закинули, и несколько часов она считается, в зависимости от сложности и объема данных. Таски на гриде могут быть как очень маленькими, например, посчитать одну формулу и выдать один результат, так и большими, например, для таблиц, где нужно посчитать корреляции всех возможных сценариев рисков и отдать совокупный результат.
Тут появляется задача оптимизации нагрузки грида и предсказания времени расчета задачи в зависимости от типа инструмента, объема данных и других показателей, чтобы загрузить его по-максимуму. Потому что, если закинуть одну большую задачу, все остальные будут ждать в очереди, хотя за это время можно было посчитать что-то еще.
В общем, задача о рюкзаке и прочие оптимизации. Там, где пинг до грида дольше, чем время самого расчета, мы будем делать это на бэкенде, где уже развернут мини-кластер для таких маленьких задач.
— Можно это как-то уложить в какую-то структуру? Насколько я понимаю, в зависимости от объема задач применяются разные методы оптимизации. На маленьких задачах имеет смысл оптимизировать JIT-компилятор, а на больших что-то другое. Расскажи, какие есть области задач и какие методы там используются для ускорения и оптимизации.
Пример большой задачи — расчет всех финансовых инструментов и рисков при изменении котировок каждой из валют на 1-2-3-10%. В этом случае оптимизация будет заключаться в группировке сделок в пачки таким образом, чтобы в рамках одной пачки были сделки на один тип портфеля или одну валюту.
Чтобы не было множества расчетов рисков по каждой сделке, мы их представляем как одну сделку на большой объем, а затем пропорционально дробим полученные результаты. Таким образом мы снижаем количество необходимых расчетов.
Ещё пример оптимизации — на этот раз с валютными парами. Допустим есть две пары «рубль-доллар» и «рубль-евро». В первой паре можно представить, что рубль падает, а можно — что доллар растет. По факту это одно и то же. То же самое и с парой «рубль-евро». Соответственно, разные на первый взгляд пары мы можем считать в одной пачке, исходя из того, что рубль меняется в обоих случаях.
Уменьшается количество расчетов и ускоряется результат. Вроде бы поменяли одну валюту (в нашем примере — рубль), а на деле посчитали риски по разнородным активам.
— А можно решить задачу в лоб и раскатать её на огромный-огромный кластер?
Такой кластер есть, но он уже загружен множеством расчетов. Кластер не резиновый, несмотря на десятки тысяч CPU, которые там сейчас есть.
— А с точки зрения софта, In-Memory DataGrid или Hadoop?
Да, есть и Hadoop, и Kafka для процессинга всего этого, и база данных ClickHouse для оптимизации работы с большими данными. В плане укладки данных понятно, что гонять JSON-ы, мягко говоря, неэффективно. В связи с этим появляются моменты оптимизации работы с Protobuf. Нам важно не просто уложить бинарные данные, но при этом сделать это максимально плотно, используя словари.
В них мы будем хранить, например, однотипные для всех сделок спецификации контрактов. За счёт этой оптимизации со словарями коллега сэкономил 30% занимаемой памяти.
— Это словари лежат на конкретных нодах и дублируются или находятся в центральной базе?
По-разному. В основном в центральной базе. А есть словари, которые передаешь на грид вместе с пачкой расчетов. Её хочется иметь максимально компактную, чтобы не тащить множество данных, так как интернет-каналы не резиновые.
Как это работает. Ты отправляешь на грид задачу расчета со всей необходимой для нее информацией, которую упаковываешь в словари, чтобы избежать дубликатов. Внутри уже будет весь контент, и не нужно ходить в дополнительные хранилища. Это экономит сетевой трафик и уменьшает задержки в расчетах.
— Насколько я знаю, в банках есть анализ на исторических данных, который представляет собой одну огромную пачку данных на гигабайты-терабайты. И подход с единой базой данных не прокатит? Ты можешь по ключу положить 2 ТБ, но это же нехорошо.
Да, такие моменты решаются порционированием. У тебя будут лежать локальные кэши по странам, разложенные по биржевой информации, потому что переслать информацию о всех сделках из Нью-Йорка в Сингапур ресурсоемко. Понятно, что тут разделение по страновому признаку логично: например, сделки в США будут размещаться в американских датацентрах. Аналогичная ситуация с котировками — нужно строить роутинг и определять, что это за сделка, к какому региону принадлежит, чтобы понять, где лежат кэши, отправлять её на нужные хранилища и базы данных и не гонять лишний раз данные.
— А бывает так, что нужно джойнить данные из разных регионов?
Да, бывает, и это сложная задача. Понятно, что мы не будем выкачивать терабайты данных из всех регионов, чтобы получить агрегированные результаты. Скорее всего в каждом регионе ты посчитаешь локальный агрегат этого региона и потом соберешь уже все эти результаты для получения суммарных данных.
— Скорее всего, есть внешние данные, например, биржевая история. И как их обрабатывать? Зеркалируете себе внутрь, или есть способы их обработки?
Есть протоколы и подключения к стандартным провайдерам данных: Reuters, Bloomberg, которые предоставляют биржевую информацию. Те данные, которые необходимы, мы сохраняем на внутренних хранилищах, но часть вещей можно перезапросить у поставщика данных. Опять же по регионам, чтобы не гонять трафик.
Понятно, что у них тоже развернуты сервера по всему миру для обеспечения скорости и производительности.
— А данные на чтение или чтение/запись? Если на запись, не страшно ворочать такими объемами?
В основном, на чтение, запись идет во время фиксации информации о сделках и иной информации, требуемой регуляторами. В основном расчеты для внутренних нужд: риски, стоимость портфелей и так далее. Это внутренняя кухня, ты ворочаешь данные какого-то региона или дата-центра, не отправляя вовне.
— Если от Луны отломится кусок и прилетит в датацентр, то что произойдет? Всё, конец?
Данные в датацентрах зеркалируются. Понятно, что в рамках региона данные не лежат на одном жестком диске в одном датацентре. Иначе как в той байке, любая уборщица случайно могла бы вырубить сервер. Всё копируется в онлайне: есть поток данных в обе стороны, ты считаешь с ближайшего зеркала, а на запись синхронизируешься, чтобы обеспечить консистентность.
Но, как правило, на запись доступно куда меньше информации, потому что надо отображать пользователю. Если он увидит пересчет не сейчас, а на 2 секунды позже и с другого источника, грустно, но жить можно. Понятно, что данные, которые нужны для регуляторов, внешних маркетеров и участников рынка, дублируется и синхронизируется в нескольких источниках, чтобы ничего не потерять.
Как в ТехЦентре Дойче Банка готовят данные и собирают мусор
— Вопрос про подготовку данных. Насколько понимаю, каждый источник имеет свой формат, и мгновенно конвертировать их — не самая лучшая идея. Вы их как-то предварительно подготавливаете для расчетов?
Есть внутренний единый формат. Понятно, что удобнее работать с однотипными данными, но это выливается в необходимость конвертировать их. Тут есть потоки данных и команды, которые отвечают за биржевую информацию, подключение к поставщикам. Они формируют и обогащают данные в наш единый формат. Для решения проблем с производительностью будет два потока данных, один из них — это быстрый цикл, который будет отдавать информацию, поступающую из биржевого потока данных. Благодаря этому реже случается необходимость ходить в различные хранилища и формировать стандартную структуру. На ней можно посчитать показатели, необходимые в режиме реального времени.
И есть более медленный цикл, который обрабатывает тот же поток, но со всем необходимым набором полей, в нашем формате. На нем проводятся все более медленные расчеты, которые требуют кучу дополнительной информации, полей и всего остального.
— Как это выглядит с точки зрения разработчика? Ты всегда знаешь, какую область базы данных затронут «тяжелые» расчёты?
Тебе прилетает какое-то событие, поля в котором могут быть заполнены как на 100%, так и лишь частично. На быстрых событиях ты считаешь показатели, которые пересчитываются в онлайне, быстро. На долгом и более медленном цикле с полным набором данных, ты пересчитываешь задачи, которые требуют всех показателей. Это если не углубляться, так как всё зависит от специфики задач.
— А данные хранятся на чем? HDD, SSD, RAM, целиком и полностью в RAM?
В основном в памяти. Мы работаем с большими хипами на бэкендах, которые потребляют и хранят у себя данные либо в стандартных структурах в Java, либо на каких-то In-Memory Data Grid — в зависимости от того, насколько быстро и насколько близкие данные тебе нужны. Понятно, что исторические данные уже прошедших дней будут храниться на SSD и дисках. Но то, что надо или может понадобиться для расчетов, будет подгружаться в кэш, в память.
— Возможно ли что-то делать не кэшируя, а с потерей информации, используя неточные вычисления?
Да. Я немного упоминал, что иногда нужно посчитать риск на цепочке изменения какого-то актива от 0 до 100%, как изменились показатели. График распределения строится по процентам, согласно формуле или линейной зависимости. Ты строишь ключевые точки и занимаешься аппроксимацией. Получаются приближенные результаты, которые не будут совпадать с реальным значением на 100%, если бы мы считали в каждой конкретной точке графика, но будут достаточны для работы с этими данными.
Этот подход часто используется, потому что позволяет, например, не делать все расчеты при изменении стоимости каждой валюты по отношению ко всем остальным валютам, с шагом в одну копейку. Ты вычисляешь либо двигаясь с редким шагом, либо выбрав несколько конкретных точек, а остальное интерполируешь. Значения по точности будут достаточные.
— Это всегда большие хипы в Java или всё лежит на оффхипе?
В основном лежит на хипе.
— Как тогда вы боретесь со сборкой мусора?
Помимо стандартного мониторинга аллокаций и частоты срабатывания сборщика мусора, ты начинаешь подкручивать какие-то вещи вроде huge pages, занимаешься рядом моментов вроде выбора правильного сборщика мусора и так далее. Например, можно попробовать использовать Shenandoah. Часть компонентов строится и тюнится из расчёта на отсутствие full GC как явления.
Это итеративный процесс: каждый день вживую собираешь flame graph, смотришь, кто и где потребляет ресурсы, смотришь частоту аллокаций и на что они выпадают, и начинаешь заниматься переписыванием горячих алгоритмов в коде на более оптимальные либо оптимизировать расчет в целом.
— А чем вы собираете метрики, чем строите flame graph?
В инструментарии ничего фантастического нет, это либо какие-то написанные нами Java-агенты, которые подключаются и собирают информацию, либо стандартные средства профилирования и другие инструменты. Есть механизмы для заворачивания событий в ELK-стек, есть логи со сборкой метрик по GC-паузам и показателям потребления памяти, есть ручные или полуавтоматические запросы по выгрузке состояния хипа, показателей дампов и их обработка. Снять хип на 150 ГБ и обработать — задача, которая требует определенных ухищрений. Коллеги написали статью на Хабре о том, как разбираться с мусором на 150 ГБ и что из этого получается. Я глубоко не копал, поэтому в деталях не расскажу.
— Какая у вас Java и какие GC используются?
Java 8, сейчас тестируется 11-я на некоторых бэкендах. Сравниваем производительность. В качестве сборщика мусора используется, в основном, G1.
— Старых коллекторов нет вообще?
Да, используем новые. Ну и подкручиваем их ключами JVM.
— Как я понял, большая часть работы связана с оптимизацией, перформансом. Можно ли как-то протестировать оптимизации, и можно ли это делать автоматически?
Да, можно. У нас есть свой тестовый фреймворк, который позволяет подключаться к тестовым контурам и измерять расчеты каждого показателя. У нас выделенная команда занимается его созданием. Можно замерить скорость на проде и юате (UAT — user acceptance testing) — посмотреть, не просела ли производительность. Можно проверить корректность математики, частоту запросов и время их выполнения, можно проверить работу с гридом. Если на проде работает 2 минуты, а на юате — 3 минуты, нужно понять, почему так происходит.
Процедура тестирования запускается автоматически. Производится подключение к двум контурам, измеряются показатели, и дальше можно кидать кастомные запросы, сравнивать результаты по времени ответа и задержки на разных версиях прода. Можно сравнивать, насколько чаще стала срабатывать сборка мусора и так далее.
— Ты рассказал про большое количество компонентов, есть какие-то тесты, которые захватывают всю систему, глобальные интеграционные тесты? Или это всё микробенчмарки?
Это комплексная инфраструктурная штука. Она прогоняется по всей системе в целом: можно узнать размер хипа, время срабатывания GC, размер live set в памяти и прочее. Какие-то комплексные вещи. Ключевая особенность этой системы — возможность отловить даже малейшие изменения в числах на всем пути расчетов. По сути, это наша последняя линия обороны. Мы можем быть уверены, что не внесли неожиданных изменений нигде внутри всей этой огромной системы.
Данные о производительности можно детализировать по определенной бизнес-функциональности, каким-то показателям. Посмотреть, как быстро и часто они считаются. Можно создавать кастомные запросы, запускать их на разных копиях и выдавать JSON diff. В этом JSON находятся изменившиеся данные и показатели производительности.
Есть отдельная команда, которая всё это разрабатывает. Например, подключение к разным окружениям, поддержку визуализации и другой функциональности. Это внутренняя разработка.
— А есть способ молодому или старому разработчику сделать ошибку, которая испортит производительность настолько, что вся система остановится?
Сделать так не получится, потому что подобными изменениями не затрагиваются все приложения сразу, ведь у нас используется модульная система с микросервисами. Хотя с хипом под 100 ГБ они не очень «микро», но тем не менее. Они могут быть чуть меньше или больше по размеру, в зависимости от решаемых задач. Вряд ли ты сможешь повлиять на всю систему целиком и кардинально сломаешь производительность.
Ты закоммитил в master, по нажатию кнопки запускается развертывание на боевых серверах, всё это разворачивается и прогоняется через регрессионное тестирование, и далее проблемы могут выявляться при ручном и других видах тестирования. И просадку в производительности за счет того, что тестовый фреймворк покрывает не только корректную часть расчетов, но и работу с производительностью, памятью и всем остальным, можно будет заметить. В инвестиционной деятельности скорость расчетов и принятия на их базе торговых решений имеет существенную роль.
Даже по флеймграфам, которые выгружаются раз в день по итогам, ты заметишь, что вчера был один результат, а сегодня совершенно иной. Ты понимаешь, какой код приводит к проблемам, где произошла просадка производительности и всё остальное. Я уж и не говорю про стандартные тесты и CI, которые решат явные логические баги.
— А что с логическими багами на уровне финансовой математики?
Ты за счет тестового фреймворка сверяешь расхождения в показателях. Сам — если хватает экспертизы, или с аналитиками и квантами, которые придумывали математику. Вы разбираетесь, корректны ли изменения, почему они такие, прогоняете на реальных и синтетических сделках, чтобы проверить результат. Если кто-то ошибся, это нужно исправлять и перепроверять.
О финансовом бэкенде
— Напомни, чем ты в этой огромной системе занимаешься.
Я занимаюсь бэкендом — системой, которую использует сервис, реализующий саму математику. Я подготавливаю запросы к этим условным калькуляторам, отправляю их туда, получаю ответы по рискам, стоимости портфеля и показателям, делаю какие-то преобразования.
Условно говоря, в одном месте нужно считать стоимость риска по какому-то инструменту, а в другом месте — делать на основе какого-то одного базового риска его вариации, то есть расширять этот результат на варианты и отправлять на UI, чтобы отобразить данные. Это такой бэкенд, который строит данные расчетов, ходит в систему, непосредственно обсчитывающую всю самую жесткую математику, и отправляет результаты на UI.
— А что там за технологии используются? Это чисто ваши собственные наработки или можно работать и с «общечеловеческими» вещами вроде Spring?
Там стандартные вещи типа Spring, Java, MongoDB и Protobuf, различные стандартные системы для dependency injection. Ещё всякие UI на React, взаимосвязи через gRPC со внешними системами, чтобы отдавать им данные.
— Я услышал Mongo, но не услышал Oracle. У вас есть полномасштабная реляционная база данных или что-нибудь такое?
Да, есть, но используется в другом формате. На бэкенды прилетает обновление биржевой информации в виде отдельных сообщений и событий. И если ты ходишь в БД за какими-то данными за прошлые периоды, то соединяешься через стандартный JDBC драйвер. Здесь нет каких-то более высокоуровневых библиотек вроде SpringData и всего остального, только чистые запросы к JDBC. Это вопрос производительности, компактности запросов и всего остального, что трудно достигнуть, используя обычные фреймворки для высокоуровневых задач.
— А вы пробовали где-нибудь использовать CQRS?
Пробовали, есть, но это в основном биржевая информация.
От безопасника к фьючерсам
— А изначально ты на кого учился? Программист, математик…
Я безопасник.
— А как ты к этому пришел? Если однажды занялся безопасностью, с этого тяжело слезть.
Диплом безопасника не говорит, что я занимался только безопасностью. Я ей обучался, но по большей части с первого курса кодил, устроившись С++ разработчиком. Писал для касс со встроенным GNU/Linux, а потом перешел на Java. Писал стандартные бэкенды и бизнес-автоматизацию, работал в брокерской сфере в одной финансовой корпорации. Реализовывал расчеты деривативов, расчеты рисков. Был простым разработчиком, лидом, архитектором, начальником отдела. Многое успел поделать.
Я здесь с января, а до этого около двух лет занимался финансовой математикой.
— Как тебя так бросило из математики в простую разработку?
На самом деле, трудно назвать финансовую математику «простой» разработкой. Даже если ты не занимаешься непосредственно реализацией алгоритма, рассчитывающего оценку дериватива, какого-то риска или иного показателя, ты все равно занимаешься какими-то расчетами. Тут не только чистый бэкенд, я ранее уже говорил, что на бэкендах есть мини-кластеры для «простых» быстрых расчетов. Иными словами, то, что я не затрагиваю сервисы, которые считают основную математику, еще не значит, что я вообще не занимаюсь расчетами.
— Что в этой работе интересного и клевого?
Во-первых, то, что ты можешь разбираться в финансах. Меня
лично очень сильно это вдохновляет: финансовая математика, торговля, биржа и все такое. Мне очень нравится рассчитывать показатели. Понятно, что ты на бэкенде не считаешь сложную математику, но так или иначе, стандартные финансовые вещи всё равно рассчитываешь сам. Никаких особых сложностей с этим нет, но это интересно.
Это и большие объемы данных, ведь нечасто приходится в бэкенде работать с хипом по 150 гигабайт, который надо по байтам уложить. Это перформанс-штуки по оптимизации вычислений. Увлекательно погружаться в математику бизнеса, в сущность процессов.
Модели, потоки данных, реактивные стримы, обработка укладки данных. Как нагрузить грид и посчитать предагрегаты данных, чтобы не загружать терабайт данных из БД, а получить накапливаемый предагрегат, который отправляется одним легким запросом — это весьма интересно. Понимаешь, как всё работает в банке, зачем это нужно и какие масштабы за всем этим стоят.
Можно ли волку-одиночке торговать без банка и как это сделать
— А есть какие-то интересные вещи, которые обычные люди или разработчики не понимают, и ими можно поделиться, чтобы взорвать людям
Первое, что приходит на ум — это описание идеи и сложность задачи финансовых расчетов. Торговать на бирже, особенно какими-то деривативами, означает не просто взять цену с торгового терминала и выставить заявку на какой-то объем. Необходимо определить, является ли цена правильной и актуальной. Ты должен провести расчеты, которые могут представлять из себя формулы на два листа А4, исписанные интегралами.
Есть небольшая история из тех времён, когда я только пришел в эту сферу и начал что-то программировать. Однажды мне предложили ознакомиться с расчетами одного показателя — а там два листа с интегралами и вторыми производными. И вот тогда ты начинаешь понимать, зачем вообще в универе преподавали высшую математику и где она может пригодиться.
С университетской программой проблема в том, что ты не понимаешь, зачем эти знания в реальной жизни нужны. А тут ты видишь, что в реальной жизни действительно используются все эти показатели.
— Если какой-нибудь волк-одиночка решит потягаться во всей этой финансовой математике с банком, насколько тяжело ему придется?
Смотря что понимать под фразой «потягаться в финансовой математике». Одно дело — повторить торговые алгоритмы с определенными ограничениями, и совсем другое дело — торговать на том же уровне, на котором торгует банк.
Обычный волк-одиночка может придумать какую-то торговую стратегию, подключиться к конкретной бирже, реализовать прайсинг публично торгуемых деривативов и возможно в чем-то даже оказаться быстрее банка. Но торговать профессионально на том же уровне, что и банк, обычный человек не сможет.
Банки торгуют на межбанковском рынке, куда просто так не попасть. Вдобавок, профессиональная торговля деривативами без использования безрисковой ставки невозможна, и зачастую даже средние банки не могут иметь доступ к ней. Поэтому инвестиционные банки — это всегда крупнейшие банки. Даже миллиардные хедж-фонды используют банки как посредников, чтобы избежать необходимости заключать соглашения со всеми участниками сделок. Это такой прокси, в бизнес-смысле.
Так что да, прийти поторговать одиночка сможет, но после некоторых объемов начинаются другие правила. Если одиночка их перейдет, он уже точно будет не одиночкой, а какой-то организацией (инвестиционным или хедж-фондом, или чем-то подобным).
— В чём именно может помочь банк?
Банк предоставляет ряд дополнительных вещей. Ты можешь не уследить за рисками, и здесь банк дает возможность оценить финансовые показатели и результаты. Ты можешь начать торговать, но у тебя нет огромной базы знаний и опыта по историческим данным, показателям и ликвидности.
Когда ты — небольшой участник, который может торговать, могут возникнуть проблемы, если захочешь сделать что-то глобальное. Нужна подушка ликвидности денежных средств, и если ты торгуешь через организацию — у них есть резервы, которые могут тебе это позволить.
Всё это ты не сможешь обеспечить своими деньгами. Опять же, контроль рисков и удобство: если ты будешь делать более сложную систему, то сам физически её не построишь из-за больших объемов данных, на обработку которых потребуются мощные сервера с кучей железа.
Если у тебя узкоспециализированная задача, например, ты торгуешь каким-то одним инструментом по определенной стратегии, то иногда у тебя есть шанс получить больший профит самому, нежели отдавать деньги брокеру или банку. Если хочешь решать более комплексную задачу, собирать сложные портфели, защищаться от различных моментов, решать вопросы с налоговой, одному — тяжело и трудно. Поэтому ты обращаешься к экспертам, у которых есть проторенные пути, они знают, как всё считать и в каком виде формировать.
Как попасть в финансовую математику (всё не так страшно, как кажется)
— А если человек просто хочет заняться финансовой математикой и разработкой, он может просто пойти к вам на работу? Какие требования к такому человеку?
Если ты хочешь разобраться и попробовать поучаствовать в написании подобных систем, понятно, у тебя должен быть сильный бэкграунд разработки на Java. Нужно понимать механизмы вроде dependency injection, алгоритмы, стандартные коллекции, оптимизации — что будет работать быстрее, а что медленнее. Как оптимально решить задачу формирования тех или иных кэшей, агрегатов и всего прочего. Нужно решать сложные задачи и иметь аналитический склад ума. Пример задачи: у тебя есть набор данных, и необходимо за минимальный оверхед по памяти и времени получить какой-то агрегат.
Очень важно заботиться о многопоточности, потому что будешь упираться в проблемы с производительностью. Если начнешь параллелить вычисления, важно понимать, что будет вызывать установку барьеров, как правильно делать синхронизацию, где будет возникать happens-before. Нужно решать, в каком порядке будут запускаться вычисления, как использовать нестандартные вещи для большей и более плотной укладки.
Как вы знаете, такие штуки как IntStream#distinct
подразумевают оборачивание примитивов в Java-типы и впоследствии — обратную операцию. Вроде не очень страшно, но на больших объемах данных массовый боксинг и анбоксинг будет заметен, память будет использоваться напрасно. Нужно понимать кишки самой Java, ведь на мелочах вроде боксинга можно породить кучу дополнительных аллокаций, которые тебе не нужны. А чтобы это вовремя заметить, нужно уметь пользоваться инструментами для оценки перформанса, сбора метрик и разбираться в других стандартных вещах.
— А надо ли знать банковскую специфику?
Да нет, в принципе. Все мы понимаем, что те люди, кто знает банковскую специфику, уже работают в банках. Когда приходишь из другой сферы, ты скорее всего её не знаешь. В самом начале можно изучить документы по общим моментам: что такое фьючерс, что такое опцион, чем они отличаются, какие есть риски. И ты просто погружаешься и начинаешь разбираться в бизнес-специфике.
Но тем не менее, она важна. Вначале ты можешь просто реализовывать функциональность, которая не привязана к определенной бизнес-специфике, но постепенно изучаешь более сложные и привязанные к предметной области вещи. Что здесь, что на прошлом месте работы (когда я, будучи начальником отдела, принимал на работу сотрудников) — замечаешь, что, если из десяти людей хотя бы один понимает, что такое фьючерс, это уже хорошо.
Если у тебя есть знания алгоритмов, многопоточности и Java в целом, то изучить бизнес-специфику не составит особого труда. Это само получается, когда погружаешься в эту среду, читаешь документы и разбираешься.
— Как вы собираетесь проверять такие глубокие знания Java на собеседовании? Это вообще реально?
Понятно, что их, скорее всего, не проверишь. Но есть стандартные задачи на логику, алгоритмы, понимание внутренних структур. Это и тестовое задание, и whiteboard coding. Например, задание на реализацию кэша в очереди, которое даст понимание, разбирается ли кандидат в многопоточности — гонках, дедлоках и всём остальном. По ходу дела можно задавать вопросы про то, сколько это потребляет памяти, почему TreeMap, а не HashMap. Таким образом, решая одну общую задачу, можно пробежаться по моментам из разной специфики. Тут, скорее, практика, по которой вычисляются определенные нюансы.
— Как думаешь, что нужно сделать, чтобы стать лучше как программист?
Развиваться! Кодить и смотреть, какие есть технологии и алгоритмы, какие новые языки, решать алгоритмические задачки. По сути, многое зависит от опыта. Если ты много решал задачи на алгоритмы, то сможешь найти что-то подобное из прошлых задач в новой незнакомой. Нужно развивать
Языки меняются, технологии и фреймворки преобразуются. Приходят новые паттерны, но остаются и какие-то шаблоны, которые используют все. Java-конференции без докладов про Reactive Streams и разговоров о Kotlin уже не проходят. Сидеть в коконе и не понимать, что сейчас event sourcing, в каком-то смысле, постепенно захватывает мир — странно.
Нужно нарабатывать бэкграунд. Например, книги Кнута до сих пор актуальны. База плюс новые технологии. И нужно знать, где и что гуглить.
— В чем последнем сам разбирался?
В корутинах Kotlin. Прикольно, мне нравится. И по синтаксису, и по логике. Смотрю, как работать в нем с многопоточностью и асинхронностью. Раньше приходилось использовать Kotlin крайне мало. Сейчас я активно его изучаю, некоторые проекты его уже эксплуатируют. Он даже есть в некоторых небольших модулях на проде.
Автор: Олег Чирухин