Расписание выкупов с jitter: как мы распределяем заказы, чтобы не было «всплеска как у бота»
Ровный график выкупов — это пульс мертвеца на кардиомониторе. Ровная линия, один и тот же интервал, ноль жизни. Антифрод считывает её за секунду.
Поэтому Toptaker не ставит выкупы пачкой и не размазывает их идеально ровно — оба варианта палятся. Вместо этого incremental scheduler на max-heap (двоичная куча, где наверху всегда самый большой элемент) ищет самый широкий пробел в уже занятом графике, ставит туда следующий заказ и добавляет jitter — случайный сдвиг по времени. Получается распределение, в котором нет ни «тика метронома», ни свалки заказов в один час.
Дальше — как это устроено внутри и почему два «очевидных» способа расписать выкупы (ровно и кучей) выдают тебя с головой.
Почему ровный график палится
Кажется логично: 30 выкупов на 30 дней — значит по одному в день, в одно и то же время. Просто, предсказуемо, удобно считать.
Это и есть проблема. Естественный спрос так не выглядит. Реальные покупатели заказывают рвано: всплеск в выходные, провал в среду, ночной заказ, утренний.
А когда у карточки 20 дней подряд ровно один заказ в 14:00 — это не покупатели. Это скрипт.
Антифрод WB по нашим оценкам ловит около 98% накрутки и смотрит на 200+ параметров. Регулярность интервала — самый дешёвый для них сигнал: посчитать дисперсию времени между заказами умеет даже примитивный запрос. Слишком низкая дисперсия = бот.
Цена ошибки высокая. При поимке снимают СПП (скидку постоянного покупателя) на 30 дней — и по всему ассортименту, а не только по «спалённой» карточке.
Почему кучный график палится ещё хуже
Второй типовой способ — «давай открутим 30 выкупов за два дня, чтобы быстрее поднять карточку».
Всплеск заказов на ровном месте — без рекламы, без трафика, без сезона — это аномалия, которую видно невооружённым глазом. У товара неделю не было продаж, и вдруг 15 заказов за вечер. Откуда?
Резкий градиент спроса — такой же красный флаг, как и идеальная ровность. Антифроду не нужны 200 параметров, чтобы это заметить; хватает производной по количеству заказов во времени.
Что делает incremental scheduler
Мы расписываем выкупы инкрементально, по одному, а не раскидываем всю пачку сразу формулой «период / количество».
Механика:
- Берём окно (например, 14 дней) и уже занятые точки графика — это могут быть прошлые выкупы, дни без активности, ограничения по дневному окну пользователя.
- Строим max-heap из пробелов (gap) между соседними точками. Наверху кучи — самый большой свободный промежуток.
- Достаём верхушку, ставим новый выкуп в середину этого пробела. Пробел разбивается на два меньших — оба возвращаются в кучу.
- Повторяем, пока не разложим все заказы.
Сложность — O(n log n): каждая вставка это extract-max и два push, каждый log n. Для 30–50 выкупов это микросекунды.
Но важно не быстродействие. Важно, что заказы садятся туда, где график реже всего — и распределение само собой выходит близким к равномерному по плотности, но без жёсткой решётки.
Зачем нужен jitter поверх max-heap
Сам по себе max-heap детерминирован: одинаковый вход — одинаковые точки. Два клиента с похожим объёмом получили бы один и тот же «скелет» расписания.
А скелет — это паттерн. Паттерн — ровно то, что антифрод и ищет.
Поэтому каждую посчитанную точку мы сдвигаем на случайную величину — jitter (дрожание). Сдвиг идёт и по времени внутри дня, и по самому дню в пределах допустимого окна. Параметры дрожания берутся из дневного окна пользователя (когда он реально готов, чтобы заказы шли в его рабочее время), так что выкуп не вылезет в 03:00 — отдельная история, но смысл тот же: время заказа должно быть правдоподобным.
Итог: плотность распределения задаёт max-heap (равномерно, без куч), а микрорисунок задаёт jitter (нерегулярно, без решётки). Дисперсия интервалов получается такой, как у живого спроса — ненулевой, но и не хаотичной.
Чем это отличается от «расписать в Excel»
Большинство сервисов и тем более ручных схем делают одно из двух: делят период на количество (ровно) или гонят пачкой (кучно). И то, и другое — линейная функция, которую антифрод раскладывает в одну строчку.
Разница на уровне подхода:
- Ровный делитель:
interval = период / n. Нулевая дисперсия по времени суток. Палится. - Пачка: всё за пару дней. Резкий градиент. Палится.
- Toptaker: max-heap по пробелам + jitter. Плотность ровная, микрорисунок случайный. Похоже на спрос.
Это та же логика, по которой мы не шлём запросы голым Node fetch (его TLS-fingerprint — отпечаток TLS-рукопожатия, по которому сервер отличает браузер от скрипта — виден сразу), а используем пресет под реальный мобильный клиент. Бессмысленно вылизывать сетевой слой, если расписание заказов кричит «бот». Антифрод смотрит на всю картину сразу. Подробнее про подход — в чём Toptaker отличается.
Сколько выкупов вообще ставить
Расписание решает «когда», но не «сколько». Объём считается от ниши, конкурентов и текущей позиции карточки — слишком мало не сдвинет выдачу, слишком много даст тот самый подозрительный градиент, который не спасёт никакой jitter. Как прикинуть число под свою карточку — разобрали отдельно: сколько выкупов нужно.
Скажу честно, как продавец с пятью годами на WB: «100% безопасно» в самовыкупах не бывает, это серая зона. Грамотное расписание снижает риск примерно до 95%, а не до нуля. Кто обещает ноль — врёт или не понимает, как это работает.
Но между «спалиться на ровном тике за неделю» и «выглядеть как живой спрос» разница — именно в таких деталях.
FAQ
Что такое incremental scheduler в Toptaker? Алгоритм, который добавляет выкупы в график по одному, каждый раз в самый широкий свободный пробел. Реализован на max-heap (куче пробелов), сложность O(n log n).
Зачем нужен jitter в расписании самовыкупов? Чтобы убрать регулярность. Max-heap даёт ровную плотность, но детерминированные точки — это паттерн. Случайный сдвиг (jitter) по времени и дню ломает решётку, и интервалы между заказами выглядят как у живого спроса.
Почему нельзя просто заказывать по одному в день в одно время? Нулевая дисперсия интервалов — дешёвый сигнал для антифрода. Реальные покупатели так не заказывают. Ровный график WB ловит как накрутку.
Что будет, если антифрод WB поймает накрутку? Снимают СПП (скидку постоянного покупателя) на 30 дней — причём по всему ассортименту продавца, а не только по одной карточке. По нашим оценкам антифрод отлавливает около 98% накрутки по 200+ параметрам.
Гарантирует ли расписание безопасность? Нет. Самовыкупы — серая зона, гарантий не бывает. Грамотное распределение снижает риск примерно до 95%, но не до нуля.
Расписание — это не «когда тебе удобно», а «когда поверит антифрод». Живой спрос дышит. Метроном — нет, и его слышно за версту.
Хотите так же — но без ручной возни?
Toptaker делает выкупы и отзывы автоматически: SRID, чеки и скриншоты по каждому действию. 5 выкупов бесплатно при регистрации.