Смотрим в будущее на Go — Theta прогнозирование финансового модуля ERP
- понедельник, 8 июня 2026 г. в 00:00:11
Салют, Хабр.
Зачем предприятия ведут учёт? Отчётность перед ФНС? Или может воронка клиентов? Сотни ответов российского рынка учётных систем на этот простой вопрос.
1С говорит владельцам: мы дадим вам идеальную, вылизанную до последней проводки отчётность перед налоговой.
Битрикс24, Amo… говорят: мы поможем вам сохранить каждого клиента, ведь не будет клиента - не будет денег.
Притянуто за уши, но картина понятна - среди учётных систем можно выделить два лагеря:
БУХ-центричные;
CRM-центричные.
Меня зовут Серафим Недошивин, я скромный Go разработчик, и меня всегда тревожил один вопрос: разве не финансы как таковые должны являться центром учёта предприятий?
Какой толк от зелёной воронки лидов, каждый из которых в сухом остатке является убыточным? Какой смысл в причесанной отчётности без банального понимания рентабельности вашего дела?
Год назад я невольно стал заложником терзающих мой разум раздумий о смысле учётных систем. Так был написан первый, второй… пятый модуль мультитенантной ERP-подобной системы для малого бизнеса (Go + pgx | Next.js + TS), вопреки рынку ставящей именно модуль финансов в центр всей системы.
А работая с финансовым модулем, то есть с бесчисленным множеством временных рядов, вы неизбежно спросите себя - а что если?.. добавить простейшее прогнозирование финансов на основе фактических данных конкретной организации?
Об этом и пойдёт речь в этой статье. Прогнозирование, Theta, Holt-Winters, SES модели и где заканчивается точность?
Kroncl | Github - Разработчикам | Apache 2.0 client+server

Начнём с базы - структуры данных финансового модуля. В Kroncl реализована транзакционная модель учёта: каждая операция - отдельная запись в базе данных с привязкой к направлению - трата / доход. Удаление операций невозможно (ибо грех), только сторнирование.
Финансовый модуль тесно интегрирован со всеми остальными модулями: например, каждая конкретная сделка имеет свою историю трат / доходов, льющихся в единую базу операций.
Таким образом, каждая операция (транзакция) характеризуется прежде всего:
суммой;
направлением;
временной меткой.
Набор таких записей представляет собой не что иное как временной ряд, а сам факт существования временного ряда в системе открывает возможности анализа и прогнозирования.
В рамках такого временного ряда точкой разумнее всего считать день, а в качестве значений брать балансы, рассчитанные как доходы - расходы.
Итак, мы знаем, с чем работаем, теперь задача попроще - как прогнозировать?
На первый взгляд задача прогнозирования ряда не является чем-то невероятным - берём ряд, находим тренд, примешиваем сезонность и экстраполируем на горизонт прогноза.
Существуют десятки моделей, учитывающих разный набор параметров и требующих разный объём данных для анализа при составлении прогноза, так вот задача выбрать модель гораздо сложнее, чем реализовать.
Большинство моделей опираются на три основных компонента:
уровень (среднее значение ряда в данный момент);
тренд (устойчивый рост или падение);
сезонность (повторяющийся паттерн фиксированной длины).
Давайте взглянем на фаворитов:
Выкидываем сезонность и тренд. Иными словами, просто находим среднее значение временного ряда, вокруг которого колеблются все остальные.
прогноз = α × сегодняшнее_фактическое + (1-α) × вчерашний_прогноз
Казалось бы, просто и делать 2 минуты, но даже здесь мы нехотя будем перебирать коэффициент сглаживания (α), минимизирующий ошибку прогноза.
Три компонента: уровень, тренд, сезонность. Для каждого компонента свой коэффициент сглаживания соответственно: α, β, γ. Каждый рассчитывается по своей формуле.
Не будем расписывать все формулы. Можно почитать тут.
Просто заметим, что для нормальной работы модели нужно как минимум:
длина сезона известна заранее: это не что иное как статичное значение в конфиге конкретной организации, а это всегда минус, ибо владельцы сами зачастую понятия не имеют о точной сезонности предприятия;
минимум 2 сезона: в случае с недельным сезоном - 14 дней, в случае с месячным - 60. Хотите, чтобы работало? - ведите учёт минимум N дней;
перебор 3 параметров (α, β, γ) или использование стандартных -> снижение точности.
Разложение временного ряда на две линии:
первую сглаживаем и экстраполируем (консервативная): простое экспоненциальное сглаживание. Берём исходный ряд и прогоняем через SES (первая модель) с коэффициентом α = 0.3 (начальное приближение в большинстве библиотек). После этого считаем тренд - на сколько в среднем росла или падала эта плавная кривая. Экстраполируем: SES_прогноз = последнее_значение + тренд × h;
вторую экстраполируем без сглаживания (агрессивная): проводим прямую через все точки методом наименьших квадратов. Считаем наклон (slope) и пересечение (intercept). Экстраполируем: регрессия_прогноз = slope × (n + h) + intercept.
Итоговый прогноз - среднее между двумя полученными линиями:
прогноз = (SES_прогноз + (θ - 1) × регрессия_прогноз) / θ
Стандарт θ = 2, тогда:
прогноз = (SES_прогноз + регрессия_прогноз) / 2
У модели Theta есть одна очень важная в случае с Kroncl особенность: прогнозирование возможно уже начиная со второй точки, то есть достаточно 2 дней ведения финансовой отчётности. Для малого бизнеса - это слишком хорошо. Да, мы теряем сезонность, да, точность прогнозирования всё ещё напрямую зависит от количества точек анализа, но это решается добавлением уровня точности в ответ клиенту.
Существуют методы вроде Prophet, добавляющих дополнительные параметры при расчёте прогноза, но, повторюсь, в случае с Kroncl именно Theta даёт разумную точность на коротких рядах без ручного конфигурирования сезонности.
Замечу, что кодовая база сервера Kroncl превысила 40 тысяч строк кода, включая конфигурации разрешений и прочего добра, но интегрировать forecast_ подсистему в модуль fm (управление финансами) не составило большого труда.
Сделаем два базовых метода:
forecast/timeline - базовое получение ряда прогноза, полученного с помощью Theta;
forecast/summary - агрегация поверх timeline, динамический подсчёт баланса, трат, доходов, чистого потока к концу горизонта прогноза.
Реализация расчётов упакована здесь.
Ограничиваем возможный горизонт прогноза для сохранения точности: горизонт <= 2 × кол-во точек анализа.
И конечно, испытаем оргазм от результата, рассмотрим прогноз на 1400 операциях (около 200 точек анализа), преимущественно траты, с горизонтом в 100 дней. Автор лентяй и не будет проводить детальное сравнение рядов разной длины, думаю, принцип понятен.

В итоге, достаточно 2(!) точек для построения минимально точного прогноза. В идеале, прогнать аналогичные ряды через все три модели: SES, Theta, Holt-Winters и сравнить степень сглаживания и точность. Если вам нечем заняться - вперёд.
В заключение ничего не будет. Просто Theta прогнозирование финансового модуля на Go. Kroncl - облачная ERP система для малого бизнеса. Физическая изоляция данных, ролевая модель на 70+ разрешениях, 5 модулей, 130 тысяч кода.