Интерактивный обучающий эмулятор программатик-аукциона по спецификации OpenRTB v3.0 — с обеими сторонами (биржа и биддеры), реальным HTTP-обменом и анимированным дашбордом, который пошагово объясняет, как устроены аукционы первой и второй цены.
Это не просто парсер схемы, а живой стенд: биржа (SSP) генерирует bid request'ы, рассылает их биддерам (DSP) по настоящему HTTP, проводит аукцион, рассылает уведомления о событиях и показывает весь поток в браузере. Аукцион можно проходить по шагам, читая разбор: кто победил, сколько платит и почему — отдельно для первой и для второй цены.
- Две реальные стороны общаются по HTTP POST — это не симуляция в одном цикле.
- Аукционы first-price и second-price-plus с bid floor, блок-листом сит и
min-to-win. - События по спеке: pending (
purl), billing (burl), loss (lurl) — рассылаются настоящими HTTP-запросами. - Подстановка макросов:
${OPENRTB_PRICE},${OPENRTB_MBR},${OPENRTB_MIN_TO_WIN},${OPENRTB_LOSS}и др., с кодировками:B64/:URL. - 🎓 Обучающий дашборд: анимация потока, замедление, пошаговый режим, текстовая озвучка каждого этапа и панель «разбор аукциона» с расчётом цены по обеим моделям на одних и тех же ставках.
- Ноль зависимостей — только стандартная библиотека Go.
POST / (Openrtb.Request) ┌──────────┐
┌──────────┐ ───────────────────────────────────▶ │ bidder A │ :9101
│ exchange │ ◀─────────────────────────────────── │ (seat-A) │
│ :9100 │ Openrtb.Response / 204 └──────────┘
│ │ ┌──────────┐
│ dashboard│ ───────────────────────────────────▶ │ bidder B │ :9102
│ + SSE │ ◀──────────────────────────────────── │ (seat-B) │
└────┬─────┘ GET /win /billing /loss (notices) └──────────┘
│
└── http://localhost:9100 (браузерный дашборд, поток событий по SSE)
- exchange (сторона продавца, SSP) — мнит запросы, рассылает биддерам, клирит аукцион, шлёт уведомления, отдаёт дашборд.
- bidder (сторона покупателя, DSP) — принимает запрос, решает делать ли ставку, отвечает и принимает уведомления win/billing/loss.
Нужен только Go 1.26+.
# один процесс поднимает 2 биддера + биржу, аукцион каждые 2 секунды
make demo
# открой http://localhost:9100Или вручную, в трёх терминалах:
make run-bidder-a # :9101, seat-A
make run-bidder-b # :9102, seat-B
make run-exchange # :9100 + дашбордНа дашборде жми «Запустить аукцион». Включи «по шагам» и скорость «медленно», чтобы пройти аукцион этап за этапом.
curl -s -X POST localhost:9100/api/auction | python3 -m json.tool # один аукцион
curl -s localhost:9100/api/recent | python3 -m json.tool # последние 50Дашборд разбивает каждый аукцион на 5 наглядных шагов — запрос → ставки → победитель → цена → события — и в панели «Разбор аукциона» показывает на одних и тех же ставках:
Шаг 1 — ставки по убыванию:
★ seat-B $4.16 ← победитель (max)
seat-A $3.24
⎯ floor $0.75
Шаг 3 — сколько платит победитель?
┌ Первая цена ──────┐ ┌ Вторая цена ★эта биржа ┐
│ платит свою ставку│ │ max(2-я ставка, floor) │
│ $4.16 │ │ $3.24 │
│ никакой экономии │ │ ставил $4.16, −$0.92 │
└───────────────────┘ └─────────────────────────┘
- Первая цена — победитель платит свою ставку (MBR = 1.000). Выгодно занижать (bid shading).
- Вторая цена (Vickrey) — побеждает наибольшая ставка, но платит цену второго места (или floor). Занижать бессмысленно → честная максимальная ставка становится доминирующей стратегией.
💡 Важно: OpenRTB задаёт лишь «словарь» (
at,${OPENRTB_PRICE}) — конкретную формулу клиринга определяет биржа. «Second Price Plus» классически = цена второго места плюс крошечный шаг; этот эмулятор для наглядности берёт ровно цену второго места (min-to-win).
| Путь | Назначение |
|---|---|
pkg/openrtb/ |
Типы v3.0, enum-коды (nbr / loss / auction type), движок подстановки макросов |
internal/auction/ |
Логика клиринга: first/second price, выбор победителя, min-to-win |
cmd/exchange/ |
Биржа (SSP) + дашборд (SSE) + встроенная статика |
cmd/bidder/ |
Биддер (DSP) |
exchange (./bin/exchange):
| Флаг | По умолчанию | Описание |
|---|---|---|
-addr |
:9100 |
адрес биржи + дашборда |
-bidders |
http://localhost:9101,http://localhost:9102 |
список биддеров через запятую |
-at |
2 |
тип аукциона: 1 first-price, 2 second-price-plus (только эти, или 500+) |
-tmax |
200 |
таймаут ответа биддера, мс |
-block-seats |
`` | сита для блокировки (block-list) |
-interval |
0 |
авто-генерация аукциона каждые N (напр. 2s); 0 = вручную |
bidder (./bin/bidder):
| Флаг | По умолчанию | Описание |
|---|---|---|
-addr |
:9101 |
адрес прослушивания |
-seat |
seat-A |
id buyer seat |
-bid-prob |
0.8 |
вероятность сделать ставку [0..1] |
-min-price / -max-price |
0.5 / 5.0 |
диапазон CPM ставки |
-adomain |
advertiser.example |
домен рекламодателя в креативе |
Ставки детерминированы по хешу id запроса — один и тот же сценарий воспроизводится без глобального RNG.
В рамках выбранного объёма (аукцион + события, без криптографии и multi-hop) реализовано в соответствии с OpenRTB v3.0 FINAL:
| Покрыто ✅ | Намеренно опущено ⚪ |
|---|---|
Конверт Openrtb, Request/Item/Source, Response/SeatBid/Bid |
ads.cert подписи (ds/dsmap/cert) — есть поля-заглушки |
at 1/2/500+, Bid.price (CPM) |
полный supply chain (schain) |
Макросы PRICE/MBR/MIN_TO_WIN/LOSS + кодировки |
полный AdCOM (реализовано минимальное подмножество) |
События purl/burl/lurl, no-bid 204, x-openrtb-version |
Формула клиринга второй цены — это политика биржи, а не буква спеки; в UI это явно проговаривается.
- Переключатель первая ⇄ вторая цена прямо в браузере.
- PMP-сделки (
deal/privateauction) иDeal.at = 3(fixed price). - Несколько
itemв одном запросе,packagebid. - Multi-hop supply chain и ads.cert подписи.
MIT — используй свободно в обучающих и исследовательских целях.
