וואלה32 רקטות מוכנות לשיגור: צה"ל איתר בדרום לבנון - טרם הפסקת האשDaily MaverickWHAT’S COOKING: A trio of venison recipes from the heart of the KarooPunch2027: APC govs distance themselves from Wike-led rainbow coalition, deny allianceESPN59 points for the Bears? 41 for the Ravens? Let's size up four NFL offenses that erupted in Week 1Bollywood HungamaEXCLUSIVE: Himesh Reshammiya reunites with Vikram Bhatt after 13 years for 1920: Cold Winter; horror flick to be shot in MussoorieRTP DesportoI Liga. Braga Vence Estoril por 1-0 com Golo Decisivo de Jonas WindThe Jerusalem PostRussian frigate fires flares at NATO member Denmark's military helicopter in international watersInquirer Entertainment‘Forgotten Island’ introduces underrepresented Filipino culture to the worldUOLGoverno acredita que decisão firme do STF sobre Moraes reduz margem para intervenção dos EUANMEWatch Charli XCX bring out Kim Petras for ‘Unlock It’ in BrooklynIl Fatto QuotidianoIntossicazione dopo la festa dei soci di un istituto bancario: avviate le verifiche sul cateringNotJustOkFull list of winners at the 2026 AFRIMMA Awards
The Daily Newsstand · Free, Always
Tuesday, September 15, 2026

Стресс-тест, который отвечает на вопрос бизнеса «а что, если»

Translate

Ровно 18 лет назад, 15 сентября 2008 года, обанкротился Lehman Brothers — крупнейшее банкротство в истории США. Банк не использовал стресс-тесты для коммерческой недвижимости, поэтому ответа на вопрос «а что, если офисы и торговые центры обесценятся» у него не было.

Сегодня стресс-тест доступен любой компании, а не только банку с отделом риска. «А что, если доставка вырастет на 3 дня», «конкурент снизит цену на 15%», «ставка по ипотеке поднимется на 3 пункта» — на каждый вопрос можно ответить числом, а не словами.

Далее — шаги, как посчитать на своих данных. Код движка и инструкция в опенсорсе.

Привет, Хабр!

Стресс-тест отвечает на вопросы «а что, если» цифрами. В первой статье мой риск-движок MAMIR прогнал ипотечный кризис 2008 года на 26.5 млн реальных записей — на его стресс-тестах и покажу, как это работает.

Для примера возьму сценарий «ставка вырастет на 3 пункта» — скажем, с 7% до 10%. Прибавить эти 3 пункта можно двумя разными механиками, и ответы получатся разные.

Данные из примера

Freddie Mac Single-Family Loan-Level — открытая помесячная история ипотечных займов: просрочки, дефолты, продажи залога.

Данные официальные и доступны любому. На странице датасета регистрируешься и качаешь sample-файлы, по паре на каждый год выдачи: выдача и помесячное обслуживание. Структура полей описана в официальном User Guide.

Сдвиг — прибавить три к среднему за год

Модель не читает всю историю займа. Она видит фичи — числа, посчитанные из истории. Среднюю ставку за год, сколько раз человек просрочил платеж. Сдвиг правит эти фичи напрямую.

Надо проверить рост ставки на три пункта — беру среднюю за год, прибавляю три, смотрю ответ. Сами данные не трогаю. Так делают, потому что дешево. Пара строк кода, ответ сразу.

// «ставка выросла на 3 пункта»
[{ feature: 'loan_rate_mean_365d', op: 'add', value: 3 }]

Правишь среднее — переписываешь прошлое

Модель видит не ставку по займу, а среднюю за последний год. Сейчас 7%. Чтобы спросить про рост до 10%, прибавляю 3 пункта. Но средняя за год будет 10%, только если ставка была такой все двенадцать месяцев.

Хотел спросить, что будет после повышения, а вместо этого сказал модели, что повышение случилось год назад и заемщик уже год платит по новой ставке.

Одно поправил, остальные фичи сломались

Из остатка долга у меня выходят три числа — среднее за год, минимальное за год и среднее по штату. Поправил среднее, а минимальное и штатное остались от старых данных. Три числа больше не сходятся между собой, и модель получает заемщика, которого не бывает.

Тот же капкан в карточном антифроде виден вообще без модели. Сдвигаю счетчик транзакций за сутки в 20 раз вверх, средний чек впятеро вниз, сумму за сутки оставляю прежней. При таком количестве транзакций и таком чеке сумма выросла бы вчетверо, а в сценарии записано, что она прежняя.

Получается, тестировал несуществующий мир. Сдвиги выбросил и стал искать другую механику.

Шок — пересчитать все заново

Стресс-тест на шоках меняет сами данные, а все числа для модели пересчитываются заново. Ставка выросла на три пункта — значит, меняю ставку в каждой записи по займу. Дальше тот же код, что готовил данные для обучения, заново считает фичи, которые из этого поля выходят. Руками эти числа не трогаю, они выходят сами и сходятся между собой.

// «ставка выросла на 3 пункта»
[{ field: 'CurrentInterestRate', op: 'add', value: 3 }]

Разница со сдвигом — одно слово в конфиге, feature стало field. Правится не вход модели, а само поле в данных.

Цена

Сдвиг отвечал мгновенно, шоку надо пройти по 5.3 млн событий, ответ занимает около трех минут на M3 Max.

Ограничение — не все можно шокировать

Шокировать можно не любое поле. Ставку — да, ее задает банк или рынок, она приходит извне. А просрочку — нет. Платит человек или перестал — это и надо узнать. Скажу в сценарии «пусть у всех будет по три просрочки» — модель покажет большие потери. Только это не прогноз. Я вписал ответ в вопрос и получил его же обратно.

Сценарий «ставка выросла на 3 пункта»

Вопрос со ставкой записывается в движке так — это реальная декларация из plugins/credit-risk, шок из примера выше, только с адресом и именем.

{
	id: 'high_ltv_rate_shock',
	title: 'Rate rise for the high-LTV-at-origination cohort',
	select: [{ field: 'OriginalLTV', op: 'gte', value: 90 }],
	shock: [{ field: 'CurrentInterestRate', op: 'add', value: 3 }],
}

select выбирает, кого касается вопрос. Здесь это займы с LTV при выдаче от 90 — первый взнос меньше десятой части цены жилья, и рост ставки первым делом бьет по такому плечу. Пустой select задал бы тот же вопрос всему портфелю. shock двигает наблюдаемое поле события, операций две — add и mul. Кода под сценарий не пишут, движок про ипотеку ничего не знает.

Ставка в этих данных фиксированная, у выданного займа она от рынка не растет. Так что сценарий условный — вроде «всем пересчитали ставку на три пункта вверх». Механике все равно, какое поле двигать.

Прогон на реальных данных

Данные — Freddie Mac Single-Family Loan-Level Dataset, те же 26.5 млн записей, что в первой статье. Скачиваются бесплатно под собственный аккаунт, структура полей описана в официальном User Guide. Лицензия запрещает перераспространение, поэтому в репозитории их нет. Нужны пары файлов когорт 1999–2007 в data/freddie-mac/sample_orig_*.txt с выдачей и sample_svcg_*.txt с помесячным обслуживанием.

./scripts/up.sh                # postgres в докере
./scripts/ingest.sh            # загрузка 26.5 млн событий, ~5 минут
npm run windows -w @mamir/backend -- --plugin credit_risk --what labels
npm run windows -w @mamir/backend -- --plugin credit_risk --what features
npm run dev -w @mamir/scoring &        # python-сайдкар с моделью
npm run backtest -w @mamir/backend -- --plugin credit_risk --from 2005-01-01 --steps 6
npm run dev -w @mamir/backend &        # ядро на :3001

curl -X POST localhost:3001/scenarios/high_ltv_rate_shock/run \
  -H 'content-type: application/json' \
  -d '{"plugin":"credit_risk","at":"2009-01-01T00:00:00.000Z","lookback":"400d"}'

at — момент, на который собирается портфель. lookback — сколько истории входит в позицию. Вся цепочка до первого сценария занимает около часа на M3 Max, самые дорогие шаги — расчет фич (638 секунд на 8 × 26.5 млн значений) и обучение с бэктестом (770 секунд).

Итог в деньгах

Кроме прибавки потерь в ответе два служебных блока, coverage и extrapolation. Прогон выше на портфеле 2009 года — 207 867 займов на 29.83 млрд долларов — дает такую картину.

  • deltaEL: ожидаемые потери выросли со 161.40 до 176.85 млн долларов — плюс 15.45 млн, рост на 9.6%.

  • coverage: пройдено 5 303 019 событий, отобрано и перезаписано 528 614. Шок дошел до данных. Ноль в перезаписанных при непустом отборе означал бы, что нужного поля в данных нет и нулевой эффект сценария ничего не доказывает — такой прогон движок помечает untouched вместо completed.

  • extrapolation: после шока средняя ставка за год у 7.9% займов уходит за 99-й перцентиль обучающей выборки, до шока таких было 0.077%. Обучающих примеров за этой границей — один из ста, ответ модели там ближе к догадке, чем к оценке.

Если ставка для займов с маленьким первым взносом вырастет на три пункта, к ожидаемым потерям портфеля добавится 15.45 млн долларов. Рядом видно, сколько записей шок реально изменил и где модель вышла за границу обучения.

Сам сценарий не проверишь — его будущее не наступает. Проверяется модель. Исторический прогон сравнивает предсказанные потери с реальными, на кризисе 2009 года разрыв был ×3.39, про это первая статья. Стресс-тест не точнее модели, которую использует.

Свой вопрос

Чтобы прогнать свое «а что, если», нужно положить данные в движок и объявить сценарий из двух частей — select с условием, кто попадает под вопрос, и shock с полем и величиной. Вопрос «доставка вырастет на 3 дня» из начала статьи записался бы как shock: [{ field: 'delivery_days', op: 'add', value: 3 }]. Путь от пустой базы расписан в гайде репозитория mamir, синтетический домен можно поднять за 15 минут, ипотека Freddie Mac — около часа.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.