Новый алгоритм
выплат transit
Презентация для понимания: что и зачем меняем
15 слайдов · 5 минут чтения · стрелки ← →
1. Контекст
Что такое transit-выплаты
Простыми словами:
Игрок А хочет вывести деньги — мерчант должен ему заплатить.
Игрок Б в это же время вносит депозит — мерчант должен от него получить.
Наш алгоритм сводит их напрямую: Б платит А по реквизитам, мерчант просто фиксирует что обе операции прошли.
Это альтернатива «трейдерам». Дешевле и быстрее — если получается свести.
Сейчас работает только для виджет-мерчантов (Orbit, MoXB, MRGB) → метод UPI в Индии.
2. Проблема
Сейчас выплата может ждать 12 часов
В большинстве случаев (90% выплат) — закрываются в течение этого времени.
Это недопустимо: мерчанты жалуются, теряем трафик, особенно крупный.
Что страдает
- Половина выплат закрывается быстро (за час)
- Но 40% — застревают на часы
- Хуже всего вечером (с 18 до 23)
- Самый страдающий мерчант — KPMI (55% объёма)
Почему так
- Алгоритм матчинга — это «7 правил подряд», накопленных за годы
- Эти правила противоречат друг другу
- Старые выплаты получают приоритет — но они старые ровно потому что их не получается закрыть
- Зависшие выплаты блокируются и ждут разблокировки 3+ минут
3. Цель
Куда хотим прийти
✓
Важные мерчанты (KPMI)
≤ 60 мин
9 из 10 выплат за час
✓
Остальные мерчанты
≤ 180 мин
9 из 10 выплат за 3 часа
✓
Потери от ошибок
≤ 2%
было 2.5%, хотим 1.5–2%
Если этого добиться — мерчанты дают больше трафика, мы зарабатываем больше.
4. Как работает сейчас
Старый алгоритм: 7 правил подряд
Когда приходит платёж от игрока, программа выбирает кому из ожидающих выплат его отдать. Выбор делается по цепочке 7 правил:
- Старые выплаты вперёд — самая старая получает первой
- Точное совпадение сумм
- Минимальный «ущерб круглости» остатка
- Максимально круглый остаток
- Минимальный остаток
- Минимальная переплата
- Случайный выбор если всё равно
Это не «формула выбора», это история фиксов — каждое правило добавляли когда что-то ломалось.
Правила конфликтуют между собой. Старая выплата с большим остатком всегда побеждает свежую с идеальным размером — и зависает дальше.
5. Новая архитектура
Решение: 5 независимых улучшений
Каждое улучшение — отдельный «слой» с своей задачей. Вместе они дают целевые показатели.
1
Кого матчить
Правильно сузить кандидатов, асимметричный допуск, кратность сумм
2
Скоринг игроков
4 группы по истории: TRUSTED / STANDARD / COLD / RISKY
3
Кому отдавать
Одна формула «оценки» вместо 7 правил подряд
4
Зависшие
Мгновенная разблокировка, умные таймауты
5
Переплаты
Книга переплат вместо тихих потерь
Дальше — слайды с каждым слоем подробно.
Слой 1 из 5
Кого вообще можно матчить
Правильно настроенный фильтр кандидатов
Три ключевых изменения:
🎯 Асимметричный допуск
Бизнес-правило: игрок может прислать чуть больше чем надо (мы съедим переплату), но никогда меньше — мерчант должен получить полную сумму.
Сейчас в коде разрешено в обе стороны → это бизнесово неправильно и расширяет окно вдвое.
⚙️ Отдельные настройки для каждого мерчанта
Сейчас один общий выключатель «можно ли частично закрывать» для всех. Делаем отдельно:
- KPMI / MDS / MKC / MPUP — частичное матчинг запрещено (они так договорились)
- Orbit / MRJB — частичный матчинг разрешён
🔢 Round-500: попросить KPMI выдавать суммы кратные 500
Сейчас KPMI выдаёт выплаты типа 1013, 1009 рупий — таких сумм почти не бывает у плательщиков. Если попросить мерчанта выдавать 1000, 1500, 2000… — точное совпадение взлетит с 84% до 100%.
Требует переговоров с мерчантом — это самое большое улучшение для KPMI.
Слой 2 из 5
Скоринг отправителей
Делим всех игроков на 4 группы по их прошлой истории — и обрабатываем каждую группу по-своему.
🟢
TRUSTED
86%
≥5 прошлых платежей, ≥90% успешных, без жалоб
Держим дольше — почти всегда платит
🔵
STANDARD
59%
средняя история
Стандартная обработка
⚪
COLD
47%
новый, <5 платежей
Стандартная обработка
🔴
RISKY
6%
≥5 платежей, ≤10% успешных
Сразу к трейдерам — не блокируем
Большое число — это сколько процентов их платежей реально завершаются успехом.
RISKY чаще «играют» — копируют реквизиты, ничего не платят, потом пишут апелляцию. Их выгоднее сразу отдавать трейдерам, чем занимать ими выплаты.
TRUSTED — наоборот, на них можно положиться: блокировать выплату для них дольше — окупится.
Слой 3 из 5
Кому отдать платёж — одна формула вместо 7 правил
Каждый кандидат-выплата получает «оценку» (score). Выбираем того, у кого оценка выше.
оценка =
+ 1.2 × бонус важности мерчанта
− 0.5 × возраст выплаты # старые НЕ в приоритете
− 0.5 × переплата
− 1.0 × остаток после матча
− 1.2 × штраф за «узкое окно»
+ 1.3 × бонус хорошего игрока
− 100 × если выплата «проблемная»
Числа перед каждым слагаемым (1.2, 0.5, и т.д.) — «веса», их можно крутить и подбирать оптимально.
Главное отличие от старого: можно отлаживать. Видно почему алгоритм выбрал именно эту выплату — можно изменить один вес и понять как поведение меняется.
Слой 4 из 5
Зависшие выплаты — арифметика времени
Откуда берётся хвост из «12 часов» и сколько минут срезает каждое изменение.
Что показали данные за неделю
- 19 517 успешных UPI-выплат всего
- 239 выплат (1.2%) имели 5–9 неудачных попыток — это «проблемная популяция»
- Среднее число переназначений менеджера: 3.07; у 14% — 6+ переназначений
- У выплат с 6+ переназначениями: p90 = 869 минут. У выплат с 1 переназначением: p90 = 477 мин (×1.8 разница)
- Вечером (18-23ч) capacity менеджеров в 4× ниже → p90 = 699 мин vs днём 112 мин (×6 разница!)
Откуда минуты в хвосте
| Источник простоя | Минут / случай | Кого затрагивает |
| 3-минутный цикл acqUnlocker | 3-10 мин | каждая выплата с failures >0 |
| 1 переназначение менеджера в вечерний пик | 100-200 мин | 30% выплат |
| 6+ переназначений (циркуляция) | +390 мин (869 vs 477) | 14% выплат |
| Forever-блок после 5 ошибок | часы до ручной разблокировки | 1.2% (239 выплат / нед) |
Что меняем и сколько срезает
1. Мгновенная разблокировка
Убирает 3-мин цикл. Если у выплаты 5 циклов блок-разблок за хвостовое время — это 15+ минут простоя удалено.
2. Растущие паузы (1ч / 2ч / 4ч)
Эти 239 «проблемных» выплат перестают циркулировать в pool 5+ раз. Это освобождает менеджеров для обычных выплат.
3. Skip-problematic после 4ч
1.2% «безнадёжных» отправляются трейдерам, а не висят. Их вклад в p99 (самые долгие 1%) — почти весь.
4. Per-merchant capacity awareness
Вместо борьбы за peak hours — алгоритм распределяет выплаты с учётом нагрузки. Эффект на evening p90: 699 → ~150 мин.
Совокупный эффект в sim: от preset C (без recovery) к preset G (полное): p90 хвоста 194 → 98 мин (−50%), p99 1103 → 1121 почти одинаково, но Tier-A p90: 163 → 36 мин (−78%).
Слой 5 из 5
Переплаты — арифметика снижения потерь
Конкретно откуда берётся падение Loss с 2.09% до 0.44%.
Что считается «потерями» в наших цифрах
- Возвраты игрокам по апелляциям (мы reject'нули payin → игрок реально заплатил → возвращаем)
- Двойные выплаты мерчанту (мы апрувнули фейк-квитанцию → мерчант не получил → платим ещё раз)
- Переплаты в Expense(SYSTEM_ERRORS) — игрок прислал больше, разницу списываем
Откуда переплаты возникают (3 случая)
| Сценарий | Сколько | Доля |
| Игрок округлил вверх (1000 → 1100) | 100-200 ₹ / случай | ~70% |
| Игрок перевёл на старую цену, мерчант изменил сумму | 500-2000 ₹ | ~20% |
| Намеренная переплата «для надёжности» | 50-300 ₹ | ~10% |
Старое vs новое поведение
Старое
Шаг 1: игрок перевёл 1100₹, надо 1000₹
Шаг 2: 100₹ записываются в Expense(SYSTEM_ERRORS) как «системная ошибка»
Шаг 3: деньги списаны с баланса, никто не пытается вернуть игроку
Результат: ~2% объёма transit-payment'ов исчезает в потерях
Новое
Шаг 1: игрок перевёл 1100₹, надо 1000₹
Шаг 2: 100₹ записываются в customerOverpayLedger со ссылкой на этот платёж и счёт игрока
Шаг 3: раз в сутки batch-job: возвращаем игрокам всё что в ledger
Результат: переплаты возвращаются → исчезают из «потерь»
Арифметика дельты Loss% 2.09 → 0.44
- Preset E (без ledger): Loss 2.09% = 1.65% переплаты + 0.27% возвраты + 0.17% двойные
- Preset G (с ledger): переплаты теперь возвращаемые → исключаются из формулы потерь
- Остаётся: 0.27% возвраты + 0.17% двойные ≈ 0.44%
Это не магия: деньги те же, но теперь они идут не в «потери», а в «пассив с обязательством вернуть». Возвращаем — балансовая запись очищается.
6. Что получаем
Результаты в симуляции
Прогнали ~25 итераций симуляции на реальных данных за неделю. Финал — preset OPTIMAL.
✓
Tier-A (KPMI)
36 мин
было 8.2 часа → −97%
✓
Tier-B (Orbit)
143 мин
было 11.9 часа → −80%
✓
Потери
0.44%
было 2.5% → в 5.7× меньше
Важно: симуляция чуть пессимистичнее реальности (baseline 18 часов в симе vs 12 в проде). Реальные результаты могут быть лучше прогноза.
7. Сравнение
Что выкидываем · что приходит на смену
| Старое | → | Новое |
| Сортировка по 7 правилам | → | Одна формула оценки |
| Старые выплаты в приоритете | → | Возраст — мягкий бонус |
| Сохранять круглость остатка | → | Штраф за создание узкого окна |
| 5 ошибок = блок навсегда | → | Растущие паузы: 1ч / 2ч / 4ч… |
| Допуск в обе стороны | → | Только переплата, недоплата запрещена |
| Разблокировка каждые 3 минуты | → | Мгновенная разблокировка |
| Один общий «можно ли частично» | → | Отдельно для каждого мерчанта |
| Переплаты в тихие потери | → | Книга переплат + refund |
| Все игроки обрабатываются одинаково | → | 4 группы по истории |
8. Реализация
План внедрения — около месяца
Неделя 1
параллельно
Переговоры с KPMI про кратность сумм 500 рупий. Внешний трек — не зависит от кода.
Неделя 1-2
код
Базовые изменения в алгоритме:
• асимметричный допуск
• новая формула оценки вместо ORDER BY
• мгновенная разблокировка
• растущие паузы для ошибок
Неделя 2
новая БД-таблица
customerOverpayLedger + batch refund job (возврат переплат раз в сутки)
Неделя 2-3
скоринг
4-bucket скоринг отправителей на текущих данных (без ML-моделей пока)
Неделя 3
А/Б-тест
Постепенный rollout: 5% → 20% → 50% → 100% трафика, каждый шаг 24-48ч наблюдения
Неделя 4
доводка
Калибровка весов формулы на основе реальных данных. Метрики становятся target'ами.
9. Дальше копать
Куда углубиться
Дальнейшие улучшения
- Скоринг V2: когда соберём поведенческую телеметрию виджета — можно перейти на ML-модель (LR/GBM) на 30+ фичах
- Логирование (D): точки причин не-матча, события виджета, false-positive детектор
- Расширение payin: подключить host-to-host (50% трафика) через скоринг — потенциал удвоить capacity