Logo
Overview

Bidding Optimization Practice

September 30, 2025
4 min read

Q1: Bid Optimization in First-Price Auction for Advertising using Optimization Approach

A company is running an online advertising campaign, bidding on ad placements in a first-price auction. The goal is to determine the optimal bid that maximizes profit while ensuring that total advertising expenditure stays within a specified budget, using the approach discussed in the last lecture.

max(RPCcogsCPC)Impressionsσ(p(x)f(x,b))s.t. CPC×Impressionsσ(p(x)f(x,b))Budgetminimum bidbmaximum bid\text{max} (\text{RPC} - \text{cogs} - \text{CPC})\text{Impressions}\sigma(p(x)f(x, b)) \\ \text{s.t. } \text{CPC} \times \text{Impressions}\sigma(p(x)f(x, b)) \leq \text{Budget} \\ \text{minimum bid} \leq b \leq \text{maximum bid}

Assume there are only two placements: a good place (1) and a bad place (2), and:

  • Revenue per Click (RPC): Each click on the advertisement generates $5 in revenue.
  • Cost of Goods Sold (COGS): The cost associated with each click is $1.
  • Impressions: The ad is ex
  • pected to be displayed 1,000 times.
  • Click-Through Rate (CTR): CTR | 𝑋 = 𝑥 ∼ Binomial(𝑝(𝑥))
    • p(1) = 0.4 for a good place
    • p(2) = 0.6 for a bad place
  • Function f(x; b) :
    • For a good place: f(x;b)=beta.mean(10,maxbid)×bf(x; b) = beta.mean(10, max bid) × b
    • For a bad place: f(x;b)=beta.mean(3,minbid)×bf(x; b) = beta.mean(3, min bid) × b
  • Budget: The total budget for the advertising campaign is $200,000.
  • Bid Bounds: The bid b must be between 0.01and0.01 and 4.00.
  1. Write the question in Pyomo.
  2. Find the optimal bid.
  3. Plot the objective function.
import pyomo.environ as pyo
import numpy as np
from scipy.stats import beta
# parameters
rpc = 5
cogs = 1
impressions = 1000
budget = 200000
min_bid = 0.01
max_bid = 4.0
# CTR distribution parameters
p = {1: 0.4, 2: 0.6}
beta_params = {1: (10, max_bid), 2: (3, min_bid)}
budget = 200000
model = pyo.ConcreteModel()
model.b = pyo.Var(bounds=(min_bid, max_bid), within=pyo.NonNegativeReals)
def f(x, b):
a, b_param = beta_params[x]
return beta.mean(a, b_param) * b
model.objective = pyo.Objective(expr=(
rpc - cogs - model.b) * impressions * sum(p[x] * f(x, model.b) for x in p), sense=pyo.maximize)
model.budget_constraint = pyo.Constraint(
expr=model.b * impressions * sum(p[x] * f(x, model.b) for x in p) <= budget)
solver = pyo.SolverFactory('ipopt')
results = solver.solve(model, tee=True)
optimal_bid = pyo.value(model.b.value)
print(f"Optimal Bid: ${optimal_bid}")

Output:

Optimal Bid: $2.0000000000009908
import matplotlib.pyplot as plt
def objective_func(b):
cpc = b
profit = (rpc - cogs - cpc) * impressions * (p[1]*f(1, b) + p[2]*f(2, b))
return profit
bids = np.linspace(min_bid, max_bid, 100)
obj_vals = [objective_func(b) for b in bids]
plt.plot(bids, obj_vals, label="Objective Function")
plt.axvline(optimal_bid, color='r', linestyle='--', label="Optimal Bid")
plt.xlabel("Bid ($)")
plt.ylabel("Objective Function Value")

Objective Function Plot

Q2. Bid Optimization in First-Price Auction for Advertising using Multi objective Approach

Assume the same parameters with the following modifications:

E[CTR]=bidmix_bidE[CTR] = \frac{bid}{mix\_bid} E[Impressions]=Impressions^×bidmix_bid×bidE[Impressions] = \hat{Impressions} \times \frac{bid}{mix\_bid} \times bid E[Clicks]=E[Impressions]×E[CTR]E[Clicks] = E[Impressions] \times E[CTR] P(bid)=(RPCcogsCPC)×E[Clicks]P(bid) = (RPC - cogs - CPC) \times E[Clicks]

We are now considering the problem:

maxbα1P(b)+α2E[CTR]+α3E[Impressions]+α4E[Clicks]subject toE[C(b)]Budgetbidminbbidmaxwhere α1+α2+α3+α4=1\begin{align*} \max_{b} \quad & \alpha_1 P(b) + \alpha_2 E[CTR] + \alpha_3 E[Impressions] + \alpha_4 E[Clicks] \\ \text{subject to} \quad & E[C(b)] \le Budget \\ & bid_{min} \le b \le bid_{max} \end{align*} \\ \text{where } \alpha_1 + \alpha_2 + \alpha_3 + \alpha_4 = 1

where:

  • Profit: α1=0.4\alpha_1 = 0.4
  • Expected CTR: α2=0.2\alpha_2 = 0.2
  • Expected Impressions: α3=0.2\alpha_3 = 0.2
  • Expected Clicks: α4=0.2\alpha_4 = 0.2
import numpy as np
import matplotlib.pyplot as plt
import pyomo.environ as pyo
# parameters
rpc = 5
cogs = 1
impressions = 1000
budget = 200000
min_bid = 0.01
max_bid = 4.0
p = {1: 0.4, 2: 0.6}
# weights
alpha1, alpha2, alpha3, alpha4 = 0.4, 0.2, 0.2, 0.2
# helper functions
def f_x_b_good(b):
return beta.mean(10, max_bid) * b
def f_x_b_bad(b):
return beta.mean(3, min_bid) * b
def objective_func(b):
E_ctr_good = b / f_x_b_good(b)
E_ctr_bad = b / f_x_b_bad(b)
E_impression_good = impressions * (b / f_x_b_good(b)) * b
E_impression_bad = impressions * (b / f_x_b_bad(b)) * b
E_clicks_good = E_impression_good * E_ctr_good
E_clicks_bad = E_impression_bad * E_ctr_bad
cpc = b
p_bid_good = (rpc - cogs - cpc) * E_impression_good
p_bid_bad = (rpc - cogs - cpc) * E_impression_bad
return (alpha1 * (p_bid_good * p[1] + p_bid_bad * p[2]) +
alpha2 * (E_ctr_good * p[1] + E_ctr_bad * p[2]) +
alpha3 * (E_impression_good * p[1] + E_impression_bad * p[2]) +
alpha4 * (E_clicks_good * p[1] + E_clicks_bad * p[2]))
# Compute objective across bids
bids = np.linspace(min_bid, max_bid, 200)
obj_vals = [objective_func(b) for b in bids]
# Solve with Pyomo
model = pyo.ConcreteModel()
model.b = pyo.Var(bounds=(min_bid, max_bid), within=pyo.NonNegativeReals)
E_ctr_good = model.b / f_x_b_good(model.b)
E_ctr_bad = model.b / f_x_b_bad(model.b)
E_impression_good = impressions * (model.b / f_x_b_good(model.b)) * model.b
E_impression_bad = impressions * (model.b / f_x_b_bad(model.b)) * model.b
E_clicks_good = E_impression_good * E_ctr_good
E_clicks_bad = E_impression_bad * E_ctr_bad
cpc = model.b
p_bid_good = (rpc - cogs - cpc) * E_clicks_good
p_bid_bad = (rpc - cogs - cpc) * E_clicks_bad
model.obj = pyo.Objective(expr=alpha1 * (p_bid_good * p[1] + p_bid_bad * p[2]) +
alpha2 * (E_ctr_good * p[1] + E_ctr_bad * p[2]) +
alpha3 * (E_impression_good * p[1] + E_impression_bad * p[2]) +
alpha4 * (E_clicks_good *
p[1] + E_clicks_bad * p[2]),
sense=pyo.maximize)
model.budget_constraint = pyo.Constraint(
expr=model.b * (E_clicks_good + E_clicks_bad) <= budget)
solver = pyo.SolverFactory('ipopt')
solver.solve(model)
optimal_bid = pyo.value(model.b)
print(f"Optimal Bid from Pyomo: ${optimal_bid}")

Output:

Optimal Bid from Pyomo: $2.459292942866574
# plot
plt.figure(figsize=(8,5))
plt.plot(bids, obj_vals, label="Objective Function")
plt.axvline(optimal_bid, color='r', linestyle='--', label=f"Optimal Bid = {optimal_bid:.2f}")
plt.xlabel("Bid ($)")
plt.ylabel("Objective Function Value")
plt.title("Objective vs Bid (Your Formulation)")
plt.legend()
plt.show()

Objective Function Plot