Понимание C++20 <chrono> в контексте количественных финансов
20 февраля 2023 г.Цель статьи — продемонстрировать преимущества новейших функций современного C++ и std::chrono в различных областях, включая приложения математического моделирования для количественных финансов.
Введение
Управление временем – обычная задача в различных современных отраслях, таких как технологии, медицина и финансы. Это особенно важно для количественных финансов, где время может быть важным фактором, например, с ценными бумагами с фиксированным доходом. В качестве иллюстрации можно рассмотреть кредитные продукты, такие как облигации и CDS (дефолтный своп).
В настоящее время CDS стали взаимозаменяемыми с введением стандартных купонов. Практическое значение этого заключается в том, что должно быть легко заменить один стандартный контракт CDS другим, а стандартные даты платежей CDS были введены относительно 20 марта, июня, сентября и декабря каждого года.
Периодические платежи осуществляются ежеквартально, а суммы платежей рассчитываются в соответствии с соглашением о подсчете ACT/360 дней при оценке премиальной ветви CDS. Чтобы проиллюстрировать это, предположим, что C — купон, а t_0, t_1, ..., t_n — даты начисления (окончания).
Согласно ACT/360, суммы денежных потоков можно рассчитать следующим образом:
C_i = C * (t_i - t_{i - 1}) / 360
Этот простой пример демонстрирует решающую роль вычислений даты и времени для современных приложений финансового ценообразования.
Каноническим языком программирования для создания библиотек ценообразования является C++, в котором есть std::chrono
для работы со временем, начиная с C++11, а начиная с C++20 он имеет новые функции, которые могут помочь специалистам по количественному анализу использовать мощь C++ в своей повседневной работе.
Этими функциями могут быть:
- новые часы:
utc_clock
,tai_clock
,gps_clock
год_месяц_день
оператор sys_days
часы
Цель этой статьи — продемонстрировать на простых фиктивных примерах, как работать с некоторыми из этих новых функций. Код был протестирован в MS Visual Studio 2022, но ожидается, что его можно будет скомпилировать с помощью GCC и Clang, как только будут реализованы соответствующие функции библиотеки.
Перейдем к техническим деталям.
Некоторые полезные функции std::chrono
В первой части статьи мы рассмотрим использование utc_clock
, year_month_day
и operator sys_days
. Затем мы создадим собственный класс часов, имитирующий те, что в std::chrono
. Наконец, мы создадим класс часов, преобразуемый в system_clock
, который является одним из наиболее широко используемых классов часов.
Чтобы начать использовать Chrono, в код необходимо включить заголовок <chrono>
. Далее мы введем псевдоним для пространства имен std::chrono, который будем использовать в следующих примерах:
namespace chr = std::chrono;
С++ 20 имеет широкий набор литералов, которые помогают определить дату. Мы можем сделать это с помощью оператора /
перегрузки
using chr::March;
chr::year_month_day const cds_date = March / 20 / 2023;
или так
using namespace std::literals;
chr::year_month_day const cds_date = 2023y / 03 / 20d;
Экземпляр класса year_month_day
можно легко преобразовать в system_clock::time_point
с помощью нового оператора C++20 sys_days
:
chr::system_clock::time_point const tp_sys = chr::sys_days(cds_date);
и привести его, например, к time_point
для utc_clock
:
chr::time_point<chr::utc_clock> const tp_utc = chr::clock_cast<chr::utc_clock>(tp_sys);
Очевидно, здесь мы можем использовать все механизмы из предыдущего стандарта C++, и хорошим примером здесь является duration_cast
.
В следующей главе мы узнаем, как создать собственный класс часов, совместимый со всеми перечисленными выше функциями C++20 для Chrono.
Как создать собственные часы
Далее мы не будем сильно зацикливаться на финансовых деталях и создадим очень простой пример часов, которые начинаются в начале тысячелетия, то есть 1 января 2000 года
. Но методы, которые мы будем использовать, полностью применимы к финансовым проблемам при работе с датами — мы просто хотим, чтобы все было как можно проще для демонстрационных целей:
#include <cstdint>
#include <chrono>
class millennium_clock final
{
public:
using rep = std::int32_t;
using period = std::ratio<1, 1>;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<millennium_clock>;
static constexpr bool is_steady = false;
static time_point now()
{
return time_point{ std::chrono::duration_cast<duration>(std::chrono::system_clock::now() - epoch) };
}
private:
static std::chrono::sys_time<duration> const epoch;
};
std::chrono::sys_time<millennium_clock::duration> const millennium_clock::epoch { std::chrono::sys_days(std::chrono::January / 1 / 2000) };
static_assert(std::chrono::is_clock_v<millennium_clock>);
Здесь мы имитируем методы, имеющиеся у нас для класса system_clock
, а затем проверяем во время компиляции, что созданный нами класс полностью удовлетворяет всем требованиям к часам chrono
. Также обратите внимание, что период
должен быть равен std::ratio
и что основными единицами измерения для него являются секунды
.
Возможно, мы хотели бы иметь возможность использовать в нашем коде приведения от наших часов к, скажем, system_clock
:
auto const& now_mil = millennium_clock::now();
auto const& now_sys = chr::clock_cast<chr::system_clock>(now_mil);
Для этого нам нужно сделать специализацию для класса clock_time_conversion
:
namespace std::chrono {
// specialization for std::chrono::clock_cast
template <>
struct clock_time_conversion<system_clock, millennium_clock>
{
template <typename Duration>
sys_time<Duration> operator()(time_point<millennium_clock, Duration> const& tp) const
{
return sys_time<Duration>(tp.time_since_epoch() + millennium_clock::epoch);
}
};
}
Последним шагом является предоставление доступа к классу clock_time_conversion
закрытым членам класса millennium_clock
:
class millennium_clock final
{
friend struct std::chrono::clock_time_conversion<std::chrono::system_clock, millennium_clock>;
Вот и все, теперь мы можем преобразовать time_point
с помощью clock_cast
!
Заключение
В статье демонстрируются некоторые передовые методы использования современного C++ при работе с <chrono>
с акцентом на потенциальные приложения для разработки финансовых библиотек. Он наглядно демонстрирует, что можно писать элегантный и эффективный код на C++ и как использовать эти методы с последним стандартом C++.
Ведущий образ создан со стабильной диффузией.
Оригинал