Заказчик искал разницу цен между биржами и P2P-площадками руками: открытые вкладки, калькулятор, прикидки на глаз. Проблема не в том, чтобы найти разницу, а в том, что почти вся она бумажная — после комиссий биржи, сетевого сбора за перевод, сбора P2P и проскальзывания по стакану прибыль исчезает. Плюс объявления мелкие: цена красивая, но на нужный объём её не хватает.
Нужен был сервис, который считает прибыль честно и беспокоит сообщением только тогда, когда сделку действительно можно исполнить.
Написал асинхронный сканер на Python. Площадки опрашиваются параллельно, каждая через свой адаптер, поэтому добавление новой биржи — это один файл, а не переделка логики.
Прибыль считается по-настоящему: комиссии покупки и продажи, сетевой сбор за перевод монеты, сбор P2P, издержки способа оплаты и проскальзывание по реальной глубине стакана. Если под нужный объём глубины не хватает — окно отбрасывается. Для P2P проверяются лимиты объявлений, процент исполнения мерчанта, число завершённых сделок и статус «онлайн», а слишком выгодные предложения отсеиваются как выбросы данных: на практике это мусорные объявления.
Сообщение приходит, только если окно одновременно прошло порог по чистому спреду, по абсолютной прибыли и по объёму, и подтвердилось несколькими опросами подряд. Повторы гасятся кулдауном и дедупликацией в базе. В самом сообщении — обе стороны сделки, надёжность мерчантов, банки, лимиты, прибыль и оптимальный объём; кнопками можно сразу открыть нужную площадку.
Отдельно сделал устойчивость: ограничение частоты запросов по каждому хосту, повторы с нарастающей паузой, таймауты, сообщение «площадка недоступна» и сигнал «я жив». Расчёты закрыты 42 автотестами.
Важно: сервис только читает данные. Ордера не выставляются, средства не выводятся, ключи используются исключительно на чтение.
Ручной поиск заменён на одно сообщение в Telegram с готовым расчётом. Бумажные окна, которые раньше выглядели выгодными, отсекаются до отправки — в логе видно, по какой именно причине каждое из них не прошло. Сбой или блокировка одной площадки не останавливает работу остальных.
Код открыт, запуск одной командой, настройки — в одном файле с примером.