AAYMA
RU
Войти

Заказ без разовых всплесков

Streamlit-сервис для менеджера закупа: рассчитывает объяснимые рекомендуемые заказы поставщикам IEK и Systeme Electric по Excel-выгрузкам, допускает…

Доведённый продукт
Команда «27» 6💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 27
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Доведённый продукт

Задача кейса: Автоматический расчёт заказов поставщикам для пополнения склада, с утверждением менеджером

Суть

Streamlit-сервис для менеджера закупа: рассчитывает объяснимые рекомендуемые заказы поставщикам IEK и Systeme Electric по Excel-выгрузкам, допускает правки менеджера и выдаёт CSV только после утверждения.

Как устроено

Importer читает шесть типов Excel-источников в Pydantic-модели. Детерминированный engine учитывает продажи, сезонность, рост, свободный остаток, поставки в пути, компенсацию stockout, исключение разовых крупных покупок (в том числе нескольких накладных одного клиента), MOQ и кратность. Review привязывает утверждение к отпечатку версии и сбрасывает его при любых изменениях. Опциональный AI через собственный ограниченный цикл вызовов инструментов (get_dataset_status, calculate_replenishment, prepare_order) только поясняет позицию и готовит проект заказа; утверждать или отправлять заказ он не может. Backtest оценивает ошибку прогноза продаж.

Ключевые решения

  • детерминированный расчёт пополнения
  • исключение выбросов/разовых продаж
  • компенсация stockout
  • MOQ/кратность
  • function calling
  • backtest прогноза продаж

Метрики

180 тестов passed; синтетические сценарии: заказ 85 шт. (контроль), 135 со stockout, 140 с сезонностью/ростом, 45 с учётом остатка и пути

Особенности

Воспроизводимые синтетические сценарии для жюри с ожидаемыми числами. Утверждение привязано к отпечатку версии заказа. AI отделён от числовой рекомендации и не может утверждать. Данные партнёра во внешний API не отправляются.

Стек

Python · Streamlit · pandas · openpyxl · Pydantic · pytest · OpenAI SDK

Модели

gpt-6-luna · gpt-6-sol (OpenAI, через конфиг)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-b9ec458c-27.

README

README.md

Заказ без разовых всплесков

Сервис для менеджера закупа: показывает рекомендуемый заказ и объясняет каждое количество исходными продажами, сезонностью, ростом, остатком и поставками в пути. Кейс ТОО «Электрокомплект», HackAlem AI. Поддерживаются выданные форматы IEK и Systeme Electric. Интерфейс и весь расчёт работают локально без API-ключа.

Менеджер сейчас объединяет продажи, остатки и поставки вручную в Excel. Решение автоматизирует подготовку объяснимого проекта закупки, оставляя проверку человеку. Автоматической отправки заказа поставщику нет.

Что реализовано

  • Чтение шести типов локальных Excel-источников по каждому поставщику с валидацией.
  • Расчёт по продажам, сезонности, росту, свободному запасу и датам поставок в пути.
  • Отбор по поставщикам/категориям и отдельные периоды закупки по категориям.
  • Компенсация stockout при заданных днях отсутствия и консервативное исключение разовых крупных покупок, включая несколько накладных одного обезличенного клиента.
  • Минимальные партии, кратность, срочность, обоснования и ссылки на ячейки источников.
  • Корректировки менеджера и CSV только после утверждения текущей версии заказа.
  • Отдельные учебные сценарии, историческая оценка ошибки прогноза и опциональный AI.

Неполные данные не превращаются в числовой заказ. В таблицах закупки показаны только положительные рекомендации, расчёты остальных корректных позиций доступны для просмотра. Наличие механизма не означает полный охват реальных данных — ограничения указаны ниже.

Основной пользовательский сценарий

  1. Выбрать учебный сценарий или загрузить локальные файлы партнёра.
  2. Указать дату, период закупки и срок поставки; при необходимости задать фильтры и подтверждённые уточнения менеджера.
  3. Нажать «Рассчитать рекомендации»: получить рассчитанные позиции и отдельно заблокированные строки с причинами.
  4. Проверить заказ по поставщику, открыть слагаемые и источники, при необходимости изменить количество и указать причину.
  5. Утвердить текущую версию и скачать CSV. Изменение входов/количества или отклонение снимает утверждение; поставщику ничего не отправляется.

Технологии

КомпонентТехнология
Расчёт и приложениеPython; основной текущий прогон на Python 3.14.7 / Windows
ИнтерфейсStreamlit 1.64.0
Таблицы и чтение XLSXpandas 3.0.6, openpyxl 3.1.5
Контракты и валидацияPydantic 2.13.5
Тестыpytest 9.1.1, Streamlit AppTest
Опциональный AI-адаптерopenai 3.19.0, Chat Completions и function calling

Версии закреплены в requirements.txt и requirements-agent.txt. Для ядра не нужны Node.js, внешний API, отдельная база данных, векторное хранилище или отдельный HTTP backend.

Архитектура

Excel → importer → Dataset / Pydantic → engine → Calculation
Учебный генератор ────────┘                          ↓
                                        Streamlit: проверка и правки
                                                   ↓
                                      Утверждение версии → review → CSV
  • app.py — интерфейс, состояние сессии и явные действия менеджера.
  • replenishment/importer.py, models.py — загрузка данных и контракты.
  • engine.py — детерминированные вычисления; review.py — проверка количеств, привязка утверждения к отпечатку версии и экспорт.
  • demo.py, scenarios.py — полностью синтетические данные; backtest.py — историческая оценка прогноза продаж, не создание исторических заказов.
  • agent.py, agent_client.py — необязательное пояснение и проект одной позиции через инструменты get_dataset_status, calculate_replenishment, prepare_order.

AI не становится источником числовой рекомендации и не имеет инструмента утверждения или отправки заказа. Реализован собственный ограниченный цикл вызовов инструментов, не OpenAI Agents SDK. Состояние UI хранится в Streamlit-сессии, не в постоянной БД.

Установка и запуск

Нужны Git и Python; основной текущий прогон проверен на Python 3.14.7 / Windows. Учебные данные создаются кодом, поэтому для первого запуска не требуются закрытые Excel и API-ключ. В PowerShell:

git clone https://github.com/BAITC-Hacks/hack-b9ec458c-27.git
cd hack-b9ec458c-27
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m streamlit run app.py

Если проект уже скачан, перейдите в его корень и начните с создания окружения. Активация .venv не нужна: команды вызывают её Python напрямую. На Linux/macOS создайте окружение через python3 -m venv .venv и используйте .venv/bin/python вместо .venv\Scripts\python.exe. Эти команды приведены для соответствующей ОС; зафиксированный тестовый прогон выполнен на Windows. Откройте адрес, указанный Streamlit (обычно http://localhost:8501). Переменные окружения и Node.js для этого MVP не нужны. .env.example не содержит ключей.

Необязательное подключение AI

В Streamlit подключён опциональный AI-помощник по одной выбранной позиции. После расчёта введите вопрос и нажмите «Запросить AI-пояснение». Checkbox подготовки заказа создаёт отдельный проект, который требует собственного Approve; Reject снимает его. Для адаптера установите .\.venv\Scripts\python.exe -m pip install -r requirements-agent.txt и задайте AGENT_API_KEY в окружении запуска. Простое пояснение использует gpt-6-luna; «Усиленное AI-пояснение» и подготовка проекта используют gpt-6-sol. Модели можно переопределить через AGENT_MODEL_LIGHT и AGENT_MODEL_COMPLEX (старый AGENT_MODEL задаёт одну для обеих задач). Это значения конфигурации проекта, а не гарантия доступности моделей в любом аккаунте. AGENT_BASE_URL по умолчанию — https://api.openai.com/v1. .env автоматически не читается. Без ключа сохраняется локальный расчёт, AI сообщает model_unavailable. Переменные задаются в окружении процесса, из которого запускается Streamlit. После их изменения перезапустите приложение. Не вставляйте ключ в исходники. Пример скрытого ввода для PowerShell с поддержкой -MaskInput:

$env:AGENT_API_KEY = Read-Host "API-ключ" -MaskInput
.\.venv\Scripts\python.exe -m streamlit run app.py

Список безопасных переменных — .env.example. В других оболочках задайте их средствами локального окружения. Внешний API может тарифицировать запросы; для проверки основного сценария он не нужен. AI в текущем UI доступен только для SYNTHETIC/TRAINING; данные партнёра во внешний API не отправляются. Контракт: docs/AGENT_CONTRACT.md. Живой запрос через Streamlit проверен на SYNTHETIC/TRAINING: пояснение и подготовка проекта до pending_approval. Approve открывает CSV, Reject снимает утверждение. Автотесты дополнительно проверяют ошибки и повторные запуски.

Запускайте Streamlit из корня репозитория: .streamlit/config.toml скрывает встроенную выгрузку таблиц. Утверждённый CSV доступен через кнопки приложения после Approve. Это управление экспортом в интерфейсе; показанные данные остаются доступны пользователю.

Как проверить решение

Повторяемый сценарий для жюри

  1. Оставьте режим «Учебный пример» → «Базовый пример», явно помеченный SYNTHETIC/TRAINING.
  2. Дата 22.09.2026, демонстрационные параметры: 30 дней между закупками, 7 дней поставки.
  3. Нажмите «Рассчитать рекомендации». У пары REGULAR/SPIKE одинаковая потребность: заказ 85 шт., у SPIKE отдельно видна исключённая разовая часть в 5 000 единиц. Для этих чисел отдельные правила категорий должны быть выключены.
  4. Раскройте историю и слагаемые. Отредактируйте количество при необходимости (соблюдая кратность), укажите причину и утвердите текущую версию.
  5. Скачайте CSV. Изменение параметров, данных или количества снимает утверждение. «Отклонить» также снимает его. Сервис ничего не отправляет поставщику.

Другие сценарии выбираются в поле «Учебный сценарий». При тех же параметрах:

СценарийЧто сравнить
Один клиент — несколько накладныхОдин синтетический ID, три накладные в один день; разовая часть 5000 исключена, заказ 85, как у контроля
Несколько разовых клиентовДва разных синтетических клиента; исключено 8000, заказ 85, как у контроля
Сценарные периоды stockoutУ DEMO-SCENARIO отсутствие 06–15 июля и 05–19 августа 2026; заказ 135 против 85 без компенсации
Сезонность и устойчивый ростУчебный сезонный пик ×1,5 осенью и рост продаж 2026 года на 50%; заказ 140 против контрольных 85
Изменение остатка и товаров в путиДополнительные 20 шт. запаса и 20 шт. поставки уменьшают заказ с 85 до 45

Все ID, продажи и периоды этих сценариев полностью синтетические. Они не добавляются в данные партнёра. Смена сценария сбрасывает старый расчёт, ручные уточнения и утверждение. В «Период закупки по категориям» можно явно задать отдельный горизонт: для DEMO вместо 30 выбрать 60 дней, пересчитать и сравнить количество. Это правило менеджера, не выдуманная расшифровка категории: в базовом примере получится 175 вместо 85 шт. CSV отражает фактически использованный период. Подробный маршрут демонстрации: docs/DEMO.md.

CLI для независимой проверки без браузера:

.\.venv\Scripts\python.exe -m replenishment --demo --as-of 2026-09-22 --horizon 30 --lead 7
.\.venv\Scripts\python.exe -m pytest -v
.\.venv\Scripts\python.exe -m pip check

Проверка перед публикацией README и текущего кода: 180 passed in 50.59s. Тесты проверяют импорт, расчёт, сценарии, UI, ошибки, approval и повторные запуски; проверки AI с подменённой моделью не требуют ключа. Фактические прогоны и границы проверок описаны в docs/STATUS.md.

Данные и интеграции

В режиме «Файлы партнёра» укажите две локальные папки с выданными Excel, по одной на строку, и нажмите «Загрузить источники». Они читаются без изменений. При первоначальном чтении больших файлов возможна задержка; далее используется кэш, который инвалидируется при изменении пути, размера или времени изменения файла. Кнопка расчёта требует явно введённых горизонта и срока новой поставки — их нет в справочнике поставщика.

.\.venv\Scripts\python.exe -m replenishment --source "ПУТЬ_К_IEK" --source "ПУТЬ_К_SYSTEME" --as-of 2026-09-22 --horizon 30 --lead 7

В этом примере 30 и 7 — сценарные параметры, а не подтверждённые условия компании. Исходные файлы не включены в Git из соображений приватности. Жюри может проверить алгоритм на автономном учебном примере или подключить выданные данные.

ИсточникИспользование
Ежемесячные продажиОсновной ряд по коду 1С; пропуски сохраняются, итоги не суммируются повторно
Динамика продажНакладные и signed-количества, поиск аномалий, сверка месячных итогов
Ежемесячные остаткиИсторические наблюдения и предупреждения о возможном stockout
Сезонность12 переданных коэффициентов из колонки «СЕЗОННОСТЬ»
Товары в путиКоличества и сроки; в Systeme Electric также свободный остаток, категории, годовой прирост
MOQМинимум отгрузки IEK; кратность Systeme Electric

Дополнительные листы с повторной сезонностью в книге продаж/поставок не складываются с отдельным источником сезонности. Они не являются независимыми продажами. Пустая ячейка количества внутри перечисленной поставки остаётся неизвестной, а не нулём: для такого товара полнота поступлений не подтверждена и заказ блокируется. Отсутствие товара в источнике поставок также оставляет transit_known=False. В «Подтверждённых уточнениях менеджера» товар выбирается по названию, поставщику, артикулу и коду. Если есть исторический остаток, показываются его дата и источник. Остаток IEK на начало сентября не является текущим свободным остатком 22 сентября и не подставляется в расчёт автоматически; поставки от 22.09 не делают его актуальным.

Выходной CSV: разделитель ;, кодировка UTF-8 BOM, поставщик, код 1С, артикул, единица, количество, срочность, обоснование, источники и параметры расчёта. Прямого подключения к 1С нет, импорт в конкретную конфигурацию не проверен.

Зафиксированный прогон реальных файлов на срезе 22.09.2026: 12 источников, 3909 объединённых позиций; 378 рассчитаны, 3459 требуют данных, 72 содержат ошибки. 23 рассчитанные позиции имеют положительное количество. Это охват, не доказанная точность закупки на всём ассортименте. Исходные файлы не изменялись.

Методика

  1. Точный ключ — поставщик + строковый код 1С. Не удаляем ведущие нули.
  2. По умолчанию анализируются 12 завершённых месяцев. Неполный текущий месяц исключается; пустые месяцы не превращаются в нули. При недостатке истории — needs_data.
  3. Положительные операции группируются по анонимному клиенту/дню, если ID передан; иначе по товару/дню. Номер накладной не является ID клиента. Данные заказов покупателей не складываются с накладными.
  4. Кандидат во всплески должен превышать оба порога: 4 × медиана и медиана + 6 × MAD, где MAD — медиана абсолютных отклонений. Эти два параметра доступны в интерфейсе. Нужны минимум 6 обычных событий и минимум 3 обычных на каждое крупное. Исключение допускается, если у клиента только одно крупное событие в окне, а соседние наблюдаемые дни содержат обычные продажи. Это позволяет обработать несколько разных разовых клиентов. Повторные крупные покупки одного клиента, соседние высокие дни и несколько всплесков при неполных клиентских ID сохраняются для проверки менеджером. Вычитается превышение над обычной медианой, сама продажа остаётся в истории. Это консервативная эвристика, не доказательство намерения покупателя или полной устойчивости ко всем аномалиям.
  5. Исключение возможно, только если подписанные количества накладных за месяц совпадают с месячным итогом. При расхождении автоматическое исключение блокируется. Возвраты сохраняют знак; отрицательный чистый месячный спрос ограничивается нулём с предупреждением, а не преобразуется в положительные продажи.
  6. Снимаем сезонность, получаем дневную потребность. При подтверждённых днях stockout делим продажи на дни наличия. Для полного stockout используем медиану наблюдаемых очищенных дневных значений других месяцев. При отсутствии опоры расчёт блокируется.
  7. База — среднее очищенных, скорректированных дневных значений последних трёх известных завершённых месяцев. Если это старые месяцы, интерфейс предупреждает.
  8. Устойчивый годовой тренд — медиана трёх отношений к соответствующим месяцам прошлого года, только если все три направлены одинаково. Переданный коэффициент роста Systeme Electric имеет приоритет как явно обозначенная входная оценка; ручной сценарий менеджера — выше него. Поправки не перемножаются между собой. Если исключён всплеск, исходный коэффициент пересчитывается по очищенной истории: иначе выброс мог бы вернуться в прогноз через коэффициент роста.
  9. На каждый день срок поставки + период между закупками применяем сезонность календарного месяца и годовой рост в степени дни/365. Рост не накладывается сразу за целый год на короткий горизонт.
  10. max(0, прогноз − свободный запас − поступления внутри горизонта), затем минимум партии и округление вверх по кратности. Для штук сохраняется целочисленность. Поздние и просроченные поступления не выдаются за доступный товар.

Срочность определяется первой датой отрицательного прогнозного баланса, а не баллами. Если дефицит наступает раньше новой поставки, требуется отдельное решение менеджера. Категории используются для отбора и явно заданных в интерфейсе периодов закупки; коммерческая расшифровка кодов не выдумывается. Без отдельного правила действует общий период. Смена правила снимает прежнее утверждение.

Историческая проверка прогноза

В раскрываемом блоке «Проверка прогноза на прошлых месяцах» выберите товар и нажмите «Проверить прогноз». Запуск только по кнопке, повторная отрисовка не пересчитывает отчёт. Показываются прогноз и наблюдаемые продажи за три завершённых месяца, MAE в единицах товара и WAPE; рядом — простое сравнение с дневным темпом предыдущего месяца. Нулевая сумма продаж делает WAPE неопределённой, а не равной нулю.

Полный read-only прогон по всем позициям:

.\.venv\Scripts\python.exe -m replenishment.backtest --demo --as-of 2026-09-22 --months 3
.\.venv\Scripts\python.exe -m replenishment.backtest --source "ПУТЬ_К_IEK" --source "ПУТЬ_К_SYSTEME" --as-of 2026-09-22 --months 3

Для каждого месяца доступны только предшествующие продажи и операции. Текущие остатки, поставки, рост и сезонные коэффициенты из файлов не используются как исторические факты. Сезонность оценивается по 24 последовательным предыдущим месяцам; при нехватке истории явно используется нейтральный коэффициент 1. Пропуски, отрицательные месяцы и ошибки отражаются в охвате, не превращаются в нули. Метрики считаются отдельно по каждой позиции; штуки и метры не складываются в общую ошибку.

Это оценка продаж, включая непредсказуемые разовые покупки, а не доказательство точности регулярного спроса, компенсации stockout или экономии. Даты появления и исправления исходных файлов неизвестны: полного архива на прошлые даты у нас нет. Проверка использует расчётную часть движка с нейтральным запасом только для получения прогноза; она не создаёт и не утверждает исторические заказы.

Зафиксированная оценка реальных продаж июня–августа 2026: 865 товаров, 2284 проверенных товаро-месяца и 9443 пропуска с причинами. Медиана per-SKU WAPE — 62,57%, у простого сравнения — 64,26%; MAE лучше у 465 товаров и хуже у 400. Ошибка остаётся высокой. Эти показатели не означают качество скрытого спроса при stockout или гарантированную экономию. Для воспроизведения нужен тот же набор файлов.

Ограничения текущей версии

  • В реальных детализациях нет клиентского ID. Анализ одного клиента проверен на подписанных синтетических тестах; на реальных файлах доступен уровень товара/дня с источниками-накладными, не идентификация клиента.
  • Нулевой начальный/месячный остаток не задаёт длительность stockout. Автоматической численной компенсации по такому признаку нет. Ввести подтверждённые дни можно в «Уточнениях менеджера». Это ограничение реального Must have №3, не полный PASS.
  • Для IEK не найден актуальный свободный остаток. Исторический срез не подменяет его: нужен подтверждённый ввод на дату расчёта. При этом все его источники читаются.
  • Данные склада и общие остатки имеют разную детализацию. MVP рассчитывает общий переданный контур с фильтром категории, не придумывая распределение по складам.
  • Значения «бухты/метры», дубликаты кодов, нечисловые значения, отсутствующие даты и неизвестные единицы требуют уточнения; конкретные позиции блокируются.
  • Excel читается по сохранённым значениям формул. Сам Excel не пересчитывается; при отсутствии сохранённого результата поле остаётся неизвестным.
  • CSV — проверяемый табличный экспорт. Импорт в конкретную конфигурацию 1С не проверен.
  • Нет авторизации сотрудников, постоянного журнала утверждений и многопользовательской БД. Состояние текущего проекта заказа хранится в Streamlit-сессии.
  • AI в текущем интерфейсе работает только с учебными данными. Свободный текст модели может ошибаться; отсутствие ключа/API отключает пояснение, но не локальный расчёт.
  • Добавлена историческая оценка ошибки прогноза наблюдаемых продаж; её результаты и охват не равны точности заказа или доказанной экономии. Экономический эффект не измерен. Тесты проверяют свойства алгоритма, а не обещают снижение затрат.

Доступ к приложению

Публичная deployed-версия в репозитории не указана. Проверяемый способ запуска — локальный Streamlit по инструкции выше. http://localhost:8501 — адрес на вашем компьютере, а не публичная ссылка. Производственное развёртывание не заявляется.

Репозиторий: BAITC-Hacks/hack-b9ec458c-27.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
20
Авторы
2
Файлы
39
Ветки
6

Авторы коммитов

Temirlan 16Auen 4

История коммитов

  • 2026-09-23 17:56Complete hackathon scenarios, validation, and jury READMETemirlan
  • 2026-09-23 16:56Record integrated UI and live agent verificationTemirlan
  • 2026-09-23 16:52Merge final UI review with data validationTemirlan
  • 2026-09-23 16:35Show complete calculation overview at top of demo UIAuen
  • 2026-09-23 16:31Verify replenishment inputs and group supplier CSV outputTemirlan
  • 2026-09-23 16:23Document final task split and verified partner data runTemirlan
  • 2026-09-23 15:55Report safe API status on agent failureTemirlan
  • 2026-09-23 15:41Allow enhanced explanations to use stronger modelTemirlan
Все коммиты (20)
  • 2026-09-23 15:39Route simple explanations and order drafts to task-sized modelsTemirlan
  • 2026-09-23 15:32Clarify agent approval status in StreamlitTemirlan
  • 2026-09-23 15:04Fix integration docs and hide built-in draft CSV downloadsTemirlan
  • 2026-09-23 14:53Connect agent backend to Streamlit with separate approvalAuen
  • 2026-09-23 14:48Merge remote-tracking branch 'origin/agent-integration' into codex/interface-demoAuen
  • 2026-09-23 14:35Add bounded replenishment agent backend and integration contractTemirlan
  • 2026-09-23 14:29Improve replenishment demo interfaceAuen
  • 2026-09-23 14:18Clarify agent roadmap and developer ownershipTemirlan
  • 2026-09-23 14:10Add two-developer handoff and work planTemirlan
  • 2026-09-23 14:06Remove team workflow section from READMETemirlan
  • 2026-09-23 14:04Merge remote-tracking branch 'origin/main'Temirlan
  • 2026-09-23 14:04Implement explainable replenishment MVPTemirlan
Структура репозитория (39 файлов)
.agents/skills/logistics-hackathon-mvp/SKILL.md
.agents/skills/logistics-hackathon-mvp/agents/openai.yaml
.agents/skills/logistics-hackathon-mvp/references/case-analysis.md
.agents/skills/logistics-hackathon-mvp/references/implementation.md
.agents/skills/logistics-hackathon-mvp/references/logistics-patterns.md
.env.example
.gitignore
.streamlit/config.toml
README.md
app.py
docs/AGENT_CONTRACT.md
docs/ARCHITECTURE.md
docs/CONTRACT.md
docs/DEMO.md
docs/DEV_A_TASK.md
docs/DEV_B_TASK.md
docs/HANDOFF_DEV_B_CODEX.md
docs/STATUS.md
replenishment/__init__.py
replenishment/__main__.py
replenishment/agent.py
replenishment/agent_client.py
replenishment/backtest.py
replenishment/demo.py
replenishment/engine.py
replenishment/importer.py
replenishment/models.py
replenishment/review.py
replenishment/scenarios.py
requirements-agent.txt
requirements.txt
tests/test_agent.py
tests/test_agent_client.py
tests/test_app.py
tests/test_backtest.py
tests/test_engine.py
tests/test_importer.py
tests/test_review.py
tests/test_scenarios.py
Ветки (6)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.