Skip to content

mackelday/bidscape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bidscape banner

bidscape

Simulation and optimization toolkit for publisher-side ad serving.
Model auctions. Optimize yield. Simulate before you ship.

Installation · Quickstart · Features · API Reference


Why bidscape?

Ad serving systems make millions of allocation decisions per day — each one a revenue-impacting tradeoff between fill rate, floor price, pacing, and campaign priority. Yet most teams build these systems by trial and error in production, with no way to simulate the revenue impact of a configuration change before it goes live.

bidscape gives you a simulation environment for your ad server. Test floor price strategies, compare auction types, validate pacing algorithms, and forecast inventory — all without touching production traffic.

Without bidscape With bidscape
Guess floor prices, lose revenue or fill rate yield_opt.optimize_floor_price(bids) — data-driven optimal floor
Ship pacing changes blind, overshoot budgets pacing.pid_pacing(...) — simulate pacing over the full flight
No way to compare allocation strategies simulate.compare_strategies(...) — side-by-side revenue comparison
Estimate inventory on spreadsheets forecast.ets_forecast(history, horizon=7) — statistical forecasting
Debug auction logic in production auction.first_price_auction(bids, floor) — unit-testable auction mechanics
Manual yield management allocation.dynamic_allocation(...) — real-time direct vs programmatic decisions

Who is this for?

  • Ad platform engineers — prototype and validate serving logic before production deployment
  • Yield management teams — optimize floor prices, allocation splits, and pacing parameters with simulation data
  • Ad tech startups — build on battle-tested auction and pacing primitives instead of from scratch
  • CTV/streaming ad teams — model inventory scenarios specific to content-driven ad delivery
  • Students and researchers — learn publisher-side ad tech through clean, readable implementations

Installation

pip install bidscape

Requires Python 3.10+. Dependencies: NumPy, SciPy, Pandas, Plotly.

Quickstart

import bidscape

# Simulate 10,000 ad requests with first-price auction
sim = bidscape.simulate.run_simulation(
    bidscape.SimConfig(
        n_requests=10_000,
        floor_price=5.0,
        auction_type="first_price",
        n_bidders=5,
        bid_mean=8.0,
        bid_std=3.0,
        seed=42,
    )
)
print(sim.summary())
# Simulation Results:
#   Fill rate: 100.0%
#   Total revenue: $117.30
#   eCPM: $11.73

# Optimize floor price from observed bids
floor_opt = bidscape.yield_opt.optimize_floor_price(sim.clearing_prices)
print(floor_opt.summary())
# Floor Optimization:
#   Optimal floor: $7.80
#   Expected fill rate: 95.0%

# Compare strategies
results = bidscape.simulate.compare_strategies(
    bidscape.SimConfig(n_requests=5000, seed=42),
    {
        "conservative": {"floor_price": 3.0},
        "aggressive": {"floor_price": 10.0},
        "optimized": {"floor_price": floor_opt.optimal_floor},
    },
    n_runs=5,
)
for name, m in results.items():
    print(f"{name}: revenue=${m['revenue_mean']:.2f}, fill={m['fill_rate_mean']:.1%}")

Features

Auction Mechanics

First-price, second-price, and header bidding auctions with configurable floor prices.

from bidscape import Bid

bids = [Bid("dsp_a", 10.0), Bid("dsp_b", 8.5), Bid("dsp_c", 12.0)]

# First-price: winner pays their bid
result = bidscape.auction.first_price_auction(bids, floor_price=5.0)

# Second-price: winner pays second-highest bid
result = bidscape.auction.second_price_auction(bids, floor_price=5.0)

# Header bidding: unified auction across multiple exchanges
result = bidscape.auction.header_bidding_auction({
    "exchange_a": [Bid("buyer1", 10.0)],
    "exchange_b": [Bid("buyer2", 12.0)],
})

Campaign Pacing

Three pacing algorithms used in production ad servers, from simple to sophisticated.

# Proportional pacing — straightforward ratio-based
state = bidscape.pacing.proportional_pacing(
    budget_total=10_000, budget_spent=4_000,
    impressions_delivered=20_000, impressions_target=50_000,
    elapsed_fraction=0.5,
)

# PID pacing — smooth delivery with error correction
state, integral, error = bidscape.pacing.pid_pacing(
    budget_total=10_000, budget_spent=4_000,
    impressions_delivered=20_000, impressions_target=50_000,
    elapsed_fraction=0.5,
    error_integral=prev_integral, prev_error=prev_error,
)

# Multiplicative pacing — production-grade exponential adjustment
state = bidscape.pacing.multiplicative_pacing(
    budget_total=10_000, budget_spent=4_000,
    impressions_delivered=20_000, impressions_target=50_000,
    elapsed_fraction=0.5, prev_throttle=0.8,
)

Inventory Allocation

Allocate impressions between direct-sold campaigns and programmatic demand.

# Priority-weighted allocation across direct and programmatic
result = bidscape.allocation.allocate_inventory(
    total_impressions=1_000_000,
    direct_campaigns={
        "brand_deal": {"impressions": 200_000, "cpm": 25.0, "priority": 1},
        "performance": {"impressions": 300_000, "cpm": 12.0, "priority": 2},
    },
    programmatic_ecpm=8.0,
)

# Real-time dynamic allocation decision for a single impression
winner, price = bidscape.allocation.dynamic_allocation(
    direct_floor=5.0,
    programmatic_bids=[8.0, 12.0, 6.0],
    direct_value=10.0,
)

Inventory Forecasting

Forecast future impressions to plan allocation, pricing, and campaign commitments.

# Holt's exponential smoothing (trend-aware)
forecast = bidscape.forecast.ets_forecast(daily_impressions, horizon=7)

# Seasonal naive (weekly patterns)
forecast = bidscape.forecast.seasonal_naive_forecast(daily_impressions, horizon=14)

# Moving average baseline
forecast = bidscape.forecast.moving_average_forecast(daily_impressions, horizon=7)

Yield Optimization

Data-driven floor pricing and bid landscape analysis.

# Find the revenue-maximizing floor price
result = bidscape.yield_opt.optimize_floor_price(historical_bids)
print(f"Optimal floor: ${result.optimal_floor:.2f}")
print(f"Expected fill rate: {result.expected_fill_rate:.0%}")

# Fit bid landscape (log-normal model)
landscape = bidscape.yield_opt.fit_bid_landscape(historical_bids)

# Win rate curve: P(win | bid_price)
curve = bidscape.yield_opt.win_rate_curve(historical_bids)

# Revenue at a specific floor price
rev, fill, avg_price = bidscape.yield_opt.revenue_at_floor(historical_bids, 5.0)

Monte Carlo Simulation

Full ad server simulation with configurable demand, supply, and auction parameters.

# Single simulation run
sim = bidscape.simulate.run_simulation(bidscape.SimConfig(
    n_requests=50_000,
    floor_price=5.0,
    auction_type="first_price",
    n_bidders=5,
    bid_mean=8.0,
    bid_std=3.0,
    direct_campaigns=[
        {"campaign_id": "brand", "impressions": 10_000, "cpm": 20.0},
    ],
    seed=42,
))

# Compare multiple strategies with statistical confidence
results = bidscape.simulate.compare_strategies(
    base_config, variations={"A": {...}, "B": {...}}, n_runs=10,
)

Interactive Visualizations

Plotly-based charts for every stage of the ad serving pipeline.

bidscape.visualize.plot_revenue_curve(floor_opt_result)     # Floor price vs revenue
bidscape.visualize.plot_bid_distribution(bids, floor=5.0)   # Bid histogram with floor
bidscape.visualize.plot_pacing(elapsed, spent, throttle)     # Pacing over time
bidscape.visualize.plot_forecast(forecast_result)            # Inventory forecast
bidscape.visualize.plot_win_rate_curve(curve)                # Win probability by bid
bidscape.visualize.plot_simulation_comparison(results)       # Strategy comparison bars

Design Principles

  • Simulate before you ship — test configuration changes offline before they impact revenue
  • Publisher-side focus — built for the sell side: floor pricing, yield, fill rate, allocation
  • Composable — use individual modules (auctions, pacing) standalone or combine into full simulations
  • Production-informed — pacing algorithms, auction types, and allocation strategies mirror real ad server architecture
  • Tested — 90 tests, 99% coverage, seeded randomness for reproducible simulations

API Reference

Module Functions
bidscape.auction first_price_auction, second_price_auction, header_bidding_auction
bidscape.pacing proportional_pacing, pid_pacing, multiplicative_pacing
bidscape.allocation allocate_inventory, dynamic_allocation, optimal_fill_allocation
bidscape.forecast ets_forecast, seasonal_naive_forecast, moving_average_forecast
bidscape.yield_opt optimize_floor_price, fit_bid_landscape, win_rate_curve, revenue_at_floor
bidscape.simulate run_simulation, compare_strategies
bidscape.metrics compute_metrics, fill_rate, ecpm, bid_to_win_ratio, revenue_lift
bidscape.visualize plot_revenue_curve, plot_bid_distribution, plot_pacing, plot_forecast, plot_win_rate_curve, plot_simulation_comparison

License

MIT

About

Simulation and optimization toolkit for publisher-side ad serving.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages