A18 · An end-to-end ledger from ad request to settlement
Prerequisites: foundations 31–34; A17.
Evidence: explicitly constructed mechanism experiments, not real ad logs. This chapter does not claim industrial-system reproduction or online gains.
Learning order: predict → change one variable → run → explain.
English companion. All instructional Markdown is translated. Experiment code, Chinese language examples, execution counts, and saved outputs remain as in the source edition; historical output text may therefore be Chinese. The initial setup cell anchors the working directory and Python import path for this companion's deeper folder; it does not change the experiment. Saved outputs are historical evidence, not a new run. Run from the top after preparing the required data and models.
# English companions live one directory deeper; keep the original experiment code unchanged.
from pathlib import Path as _TranslationPath
import os as _translation_os
import sys as _translation_sys
_translation_root = next((p for p in [_TranslationPath.cwd(), *_TranslationPath.cwd().parents]
if (p / "reclab").is_dir()), None)
if _translation_root is None:
raise RuntimeError("Open this notebook from inside the Search Recommendation Ads Lab checkout.")
_translation_os.chdir(_translation_root)
if str(_translation_root) not in _translation_sys.path:
_translation_sys.path.insert(0, str(_translation_root))
Problem and input/output contract
Connect product entry → keyword trigger → eligibility → quality ranking → payment threshold → event → ledger. This integrated example uses CPC and constructed clicks; publisher revenue equals advertiser payment, with no fee. A bid is a ceiling, not payment. If budget is insufficient, the teaching example does not display. Production needs affordability checks or reservation before serving. Real Criteo CTR evidence stays strictly separate from constructed quality/events; no real revenue is reported.
Before running, predict which result the changed variable will affect and which invariants must hold.
from pathlib import Path
import sys
root=Path.cwd()
if not (root/'reclab').exists(): root=root.parent
if str(root) not in sys.path: sys.path.insert(0,str(root))
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from reclab import ads_curriculum as acRun the one-variable comparison
Inputs are small constructed examples visible in source. Output units and constraints are defined above. Run assertions to verify mathematics and accounting.
served=ac.ledger(budget=2.);blocked=ac.ledger(budget=1.);empty=ac.ledger(query='未知',budget=2.)
print('成交',served);print('预算不足',blocked);print('无候选',empty)
assert served['spend']==served['publisher_income']>0
assert blocked['spend']==0 and empty['spend']==0
assert len({x['request'] for x in served['ledger']})==len(served['ledger'])
dedup=ac.deduplicate_charges([('click-1',.5),('click-1',.5),('click-2',.8)],1.)
print('重复事件及预算拒绝',dedup)
assert dedup['spend']==.5 and len(dedup['entries'])==1
print('原正式预测与模拟市场保持独立:参阅19–24与原API')Saved notebook output · not executed on this page
成交 {'candidates': ['a', 'b'], 'ledger': [{'request': 'constructed-1', 'ad': 'a', 'event': 'click', 'payment': 1.5625, 'receipt': 1.5625}], 'spend': 1.5625, 'publisher_income': 1.5625, 'probability_source': 'constructed quality, NOT Criteo production CTR', 'served': True}
预算不足 {'candidates': ['a', 'b'], 'ledger': [], 'spend': 0.0, 'publisher_income': 0.0, 'probability_source': 'constructed quality, NOT Criteo production CTR', 'served': False}
无候选 {'candidates': [], 'ledger': [], 'spend': 0.0, 'publisher_income': 0.0}
重复事件及预算拒绝 {'spend': 0.5, 'entries': [{'event': 'click-1', 'advertiser_debit': 0.5, 'publisher_credit': 0.5}], 'unique_events': 2}
原正式预测与模拟市场保持独立:参阅19–24与原API
Interpretation and limits
Success, insufficient budget, and empty candidates all need explanations and must not create false charges. This example has one request, no concurrency, retry infrastructure, refunds, or log platform. It includes single-process event-ID idempotency. Next steps require atomic concurrent budgets and persistent idempotency, not repeatedly adding the same notice.
Inspect source, then try an exercise
Change duplicate-event order and verify charging still occurs once. Design a refund event and check net advertiser payment=net publisher receipts.
import inspect
print(inspect.getsource(ac.ledger))Saved notebook output · not executed on this page
def ledger(query='跑鞋',region='上海',budget=1.):
pool=candidates(query,region); rows=[]; spent=0.
if not pool: return dict(candidates=[],ledger=[],spend=0.,publisher_income=0.)
winner=pool[0]; next_score=pool[1]['bid']*pool[1]['quality'] if len(pool)>1 else 0.
cpc=next_score/winner['quality']
# One explicitly constructed click; affordable eligibility is checked again at charging.
click=True;payment=cpc if click and cpc<=budget else 0.
if payment: spent+=payment; rows.append(dict(request='constructed-1',ad=winner['id'],event='click',payment=payment,receipt=payment))
assert spent<=budget and abs(sum(r['payment'] for r in rows)-sum(r['receipt'] for r in rows))<1e-12
return dict(candidates=[a['id'] for a in pool],ledger=rows,spend=spent,publisher_income=spent,
probability_source='constructed quality, NOT Criteo production CTR',served=bool(rows))
Sources and next step
An original Lab integration connecting products, candidates, decisions, and accounting. This is an original Lab exercise, not a copy of the complete lecture text.
Chinese GitHub chapter · Authors’ RTB slides. The Chinese deck is not a complete modern advertising-engineering course. Historical descriptions of platforms are not presented as current market facts.
After the exercise, return to the ads learning path and continue to the next semantic unit.