>_bandit
changelog

Reward mode: revenue

How the bandit allocates traffic when Revenue mode is selected.


TL;DR

The main question: do people pay after this article?

Each visit gets a score:

  • there was a purchase → strong contribution (by order amount);
  • no purchase → a small funnel-depth contribution (so zero-sales articles are still comparable).

Per article we average those scores, then run the same Thompson Sampling as in depth mode.

Important: we deliberately do not rank so that “highest revenue-per-click gets ~100% of traffic”. That crushed exploration: one leader starved other articles that also had purchases. Scoring is soft, per visit — rivals keep getting tested.

If the product has no purchases yet, the mode behaves like weighted depth.


Details

Why not raw revenue / RPC ladders

An earlier mistaken approach normalized revenue-per-click so the leader scored ≈ 1.0. With hundreds of visits Thompson became overconfident → dashboard showed ~100% on one article.

The correct approach mirrors depth: a small contribution per visit; purchases raise the mean, but do not kill exploration.

Per-visit formula

Depth first (same as depth mode):

depth=w[max_stage]w[7]\mathrm{depth} = \frac{w[\max\_stage]}{w[7]}

Constants: (D = 0.05) (depth scale without a purchase), (E = 0.02) (tiny depth mix even on purchase — tie-break).
(\text{target}) — max purchase amount in the current window/segment.

reward={depthif the segment has no purchases yetmin ⁣(vtarget,1)(1E)+depthEif purchase_value >0depthDotherwise\text{reward} = \begin{cases} \mathrm{depth} & \text{if the segment has no purchases yet} \\[0.4em] \min\!\left(\dfrac{v}{\text{target}},\,1\right)(1-E) + \mathrm{depth}\cdot E & \text{if purchase\_value } > 0 \\[0.4em] \mathrm{depth}\cdot D & \text{otherwise} \end{cases}

Intuition:

  • order near the segment max → almost 1.0 for that visit;
  • visit without purchase → at most ~0.05 (even with deep funnel progress);
  • any purchase beats a deep non-paying visit.

Article score and traffic

mean_reward=AVG(reward)reward_sum=SUM(reward)α=1+reward_sumβ=1+journeysreward_sum\begin{aligned} \text{mean\_reward} &= \mathrm{AVG}(\text{reward}) \\ \text{reward\_sum} &= \mathrm{SUM}(\text{reward}) \\ \alpha &= 1 + \text{reward\_sum} \\ \beta &= 1 + \text{journeys} - \text{reward\_sum} \end{aligned}

Traffic shares again via Thompson / the selected algorithm. Below min_journeys — uniform.

The store must send purchase amounts. Without amounts the mode cannot tell a large order from a small one.


Example

Four active articles (simplified):

ArticleVisitsPurchasesRevenueWhat happens
A40010$96High mean, but not 100% traffic
B802$19Less data → more exploration, solid share
C2505$48Stable share near A/B
D1000$0Weak depth only → little traffic, not forever zero

Expected shares look spread (e.g. 15–35% among strong arms), not 99% / 0% / 0%.

Zero-purchase articles can still surface if they start converting — uncertainty keeps a door open.


When to use it

  • Tracking already sends purchase with amount
  • Goal is money, not only funnel depth
  • You have at least a few purchases across articles

If amounts are missing or purchases are tiny — start with weighted depth, then switch to revenue.

Switch in bandit settings. Metrics recompute immediately after save.