This example is from the textbook
Supply Chain Management: Strategy, Planning, and Operation, (Chopra and Meindl)
Find the Google Colab notebook for this example here.
Estimating Economic Order Quantity (EOQ)
System Description
As Best Buy sells its current inventory of HP computers, the purchasing manager places a replenishment order for a new lot of Q computers. Including the cost of transportation, Best Buy incurs a fixed cost of $S per order. The purchasing manager must decide on the number of computers to order from HP in a lot. For this decision, we assume the following inputs:
- D Annual demand of the product
- S Fixed cost incurred per order
- C Cost per unit
- h Holding cost per year as a fraction of product cost
Assume that HP does not offer any discounts, and each unit costs $C no matter how large an order is. The holding cost is thus given by H = hC. The model is developed using the following basic assumptions:
- Demand is steady at D units per unit time.
- No shortages are allowed, that is, all demand must be supplied from stock.
- Replenishment lead time is fixed (initially assumed to be zero).
The purchasing manager makes the lot-sizing decision to minimize the total cost the store incurs. He or she must consider three costs when deciding on the lot size:
- Annual material cost
- Annual ordering cost
- Annual holding cost
Because purchase price is independent of lot size, we have
- Annual material cost = \(CD\)
The number of orders must suffice to meet the annual demand D. Given a lot size of Q, we thus have
- Number of orders per year = \(\frac{D}{Q}\)
Because an order cost of S is incurred for each order placed, we infer that
- Annual ordering cost = \((\frac{D}{Q}){S}\)
Given a lot size of Q, we have an average inventory of Q/2. The annual holding cost is thus the cost of holding Q/2 units in inventory for one year and is given as
- Annual holding cost = \((\frac{Q}{2})H = (\frac{Q}{2})hC\)
The total annual cost, TC, is the sum of all three costs and is given as
- Total annual cost, \(TC = CD + (\frac{D}{Q})S + (\frac{Q}{2})hC\)

Image source: [Textbook] Supply Chain Management: Strategy, Planning, and Operation, (Chopra and Meindl)
Above figure shows the variation in different costs as the lot size is changed. Observe that the annual holding cost increases with an increase in lot size. In contrast, the annual ordering cost declines with an increase in lot size. The material cost is independent of lot size because we have assumed the price to be fixed. The total annual cost thus first declines and then increases with an increase in lot size.

From the perspective of the manager at Best Buy, the optimal lot size is one that minimizes the total cost to Best Buy. It is obtained by taking the first derivative of the total cost with respect to Q and setting it equal to 0. The optimum lot size is referred to as the economic order quantity (EOQ). It is denoted by Q* and is given by the following equation:
Optimal lot size, \(Q* = \sqrt{\frac{2DS}{hC}}\)
Numerical Example
Demand for the Deskpro computer at Best Buy is 1,000 units per month. Best Buy incurs a fixed order placement, transportation, and receiving cost of $4,000 each time an order is placed. Each computer costs Best Buy $500 and the retailer has a holding cost of 20 percent. Evaluate the number of computers that the store manager should order in each replenishment lot.
Analysis: In this case, the store manager has the following inputs:
- Annual demand, \(D = 1,000 * 12 = 12,000\) units
- Order cost per lot, \(S = 4,000\)
- Unit cost per computer, \(C = 500\)
- Holding cost per year as a fraction of unit cost, \(h = 0.2\)
Using the EOQ formula, the optimal lot size is
Optimal order size = Q* = \(\sqrt{\frac{2 * 12,000 * 4,000}{0.2 * 500}} = 980\)
To minimize the total cost at Best Buy, the store manager orders a lot size of 980 computers for each replenishment order. The cycle inventory is the average resulting inventory and is given by
Cycle inventory = \(\frac{Q*}{2} = 490\)
For a lot size of Q* = 980, the store manager evaluates
Number of orders per year = \(\frac{D} {Q*} = \frac{12,000} {980} = 12.24\)
Annual ordering and holding cost = \(\frac{D} {Q*} S + (\frac{Q*} {2}) hC = 97,980\)
Average flow time = \(\frac{Q*} {2D} = \frac{490} {12,000} = 0.041\) year \(= 0.49\) month
Each computer thus spends 0.49 month, on average, at Best Buy before it is sold because it was purchased in a batch of 980.
Implementation
import simpy
import numpy as np
import matplotlib.pyplot as plt
import SupplyNetPy.Components as scm
"""
Demand for the Deskpro computer at Best Buy is 1,000 units per month. Best Buy incurs a fixed order placement,
transportation, and receiving cost of $4,000 each time an order is placed. Each computer costs Best Buy $500
and the retailer has a holding cost of 20 percent. Evaluate the number of computers that the store manager
should order in each replenishment lot.
Analysis:
In this case, the store manager has the following inputs:
- Annual demand, D = 1,000 * 12 = 12,000 units (approx 34 units per day)
- Order cost per lot, S = 4,000
- Unit cost per computer, C = 500
- Holding cost per year as a fraction of unit cost, h = 0.2 (500*0.2 = 100 per year => 100/365 = 0.273 per day)
Assumptions:
- Demand is constant and deterministic
- Lead time is zero
Optimum Economic Order Quantity (EOQ) is determined to minimize the total cost.
Total cost = Annual material cost + Annual ordering cost + Annual holding cost
This is same as -> Total cost = total transportation cost + inventory cost (we'll ignore material cost since it is constant)
"""
D = 12000 # annual demand
d = 34 # daily demand
order_cost = 4000 # order cost
unit_cost = 500 # unit cost
holding_cost = 0.273 # holding cost per day
lead_time = 0 # lead time
simlen = 3650 # simulation length in days
total_cost_arr = []
unsat_arr = []
print(f"lot size \t Inv holding cost \t Order cost \t Average cost(per day) \t Unmet demand")
for lot_size in range(800,1600,10):
order_interval = 365*lot_size/D
env = simpy.Environment()
hp_supplier = scm.Supplier(env=env, ID="S1", name="HPComputers", node_type="infinite_supplier")
bestbuy = scm.InventoryNode(env=env, ID="D1", name="Best Buy", node_type="distributor",
capacity=lot_size, initial_level=lot_size, inventory_holding_cost=holding_cost,
replenishment_policy=scm.PeriodicReplenishment, product_buy_price=450,
policy_param={'T':order_interval,'Q':lot_size}, product_sell_price=unit_cost)
link1 = scm.Link(env=env,ID="l1", source=hp_supplier, sink=bestbuy, cost=order_cost, lead_time=lambda: lead_time)
demand1 = scm.Demand(env=env,ID="d1", name="demand_d1", order_arrival_model=lambda: 1,
order_quantity_model=lambda: d, demand_node=bestbuy, consume_available=True)
scm.global_logger.disable_logging() # disable logging for all components
env.run(until=simlen)
bb_invlevels = np.array(bestbuy.inventory.instantaneous_levels)
hp_sup_transportation_cost = bestbuy.stats.transportation_cost
total_cost = bestbuy.stats.inventory_carry_cost + bestbuy.stats.transportation_cost
total_cost_arr.append([lot_size, total_cost/simlen])
unsat_demand = demand1.stats.demand_placed[1]-demand1.stats.fulfillment_received[1]
unsat_arr.append([lot_size,unsat_demand])
print(f"{lot_size} \t\t {bestbuy.stats.inventory_carry_cost:.2f}\t\t{bestbuy.stats.transportation_cost}\t\t{total_cost/simlen:.2f}\t\t{unsat_demand:.2f}")
total_cost_arr = np.array(total_cost_arr)
unsat_arr = np.array(unsat_arr)
EOQ = np.argmin(total_cost_arr[:,1])
plt.figure()
plt.plot(total_cost_arr[:,0], total_cost_arr[:,1],marker='.',linestyle='-')
plt.plot(total_cost_arr[EOQ,0], total_cost_arr[EOQ,1],marker='o',color='red',label=f'EOQ = {total_cost_arr[EOQ,0]:.2f} with cost = {total_cost_arr[EOQ,1]:.2f}')
plt.xlabel("lot size")
plt.ylabel("Average cost per day")
plt.title("Average cost vs lot size")
plt.legend()
plt.grid()
plt.show()
lot size Inv holding cost Order cost Average cost(per day) Unmet demand
800 386458.80 596000 269.17 4100.00
810 390557.96 592000 269.19 4118.00
820 395049.18 584000 268.23 4140.00
830 400188.24 576000 267.45 4104.00
840 405223.18 568000 266.64 4106.00
850 409730.10 564000 266.78 4114.00
860 414937.16 556000 266.01 4118.00
870 419476.82 548000 265.06 4094.00
880 424411.62 544000 265.32 4114.00
890 429494.01 536000 264.52 4092.00
900 436224.38 532000 265.27 4094.00
910 438638.31 524000 263.74 4074.00
920 442904.09 520000 263.81 4096.00
930 448040.50 516000 264.12 4130.00
940 453707.25 508000 263.48 4108.00
950 458159.42 504000 263.61 4094.00
960 462991.62 500000 263.83 4100.00
970 468226.74 492000 263.08 4110.00
980 472987.11 488000 263.28 4098.00
990 477960.52 484000 263.55 4106.00
1000 481626.60 480000 263.46 4100.00
1010 487159.07 472000 262.78 4104.00
1020 492760.50 468000 263.22 4080.00
1030 496374.95 464000 263.12 4110.00
1040 502052.28 460000 263.58 4092.00
1050 507372.65 456000 263.94 4094.00
1060 511096.54 452000 263.86 4116.00
1070 516617.65 448000 264.28 4124.00
1080 519820.94 444000 264.06 4118.00
1090 525820.83 440000 264.61 4098.00
1100 530125.28 436000 264.69 4098.00
1110 534894.02 432000 264.90 4118.00
1120 539837.84 428000 265.16 4124.00
1130 544889.08 424000 265.45 4116.00
1140 550465.87 420000 265.88 4094.00
1150 554073.29 416000 265.77 4092.00
1160 559606.68 412000 266.19 4110.00
1170 564940.50 408000 266.56 4080.00
1180 569711.55 404000 266.77 4104.00
1190 573919.60 400000 266.83 4080.00
1200 586076.40 396000 269.06 4100.00
1210 583497.57 396000 268.36 4106.00
1220 589075.99 392000 268.79 4098.00
1230 593807.38 388000 268.99 4110.00
1240 598836.42 384000 269.27 4074.00
1250 601944.80 380000 269.03 4100.00
1260 607432.10 380000 270.53 4094.00
1270 613174.10 376000 271.01 4108.00
1280 617805.01 372000 271.18 4074.00
1290 621160.11 372000 272.10 4130.00
1300 627485.86 368000 272.74 4092.00
1310 631953.94 364000 272.86 4074.00
1320 637026.39 360000 273.16 4076.00
1330 640737.93 360000 274.17 4094.00
1340 646993.21 356000 274.79 4092.00
1350 652581.25 352000 275.23 4076.00
1360 655767.11 352000 276.10 4114.00
1370 661892.46 348000 276.68 4094.00
1380 663762.51 344000 276.10 4060.00
1390 671198.93 344000 278.14 4118.00
1400 676112.71 340000 278.39 4080.00
1410 679131.28 340000 279.21 4114.00
1420 685778.46 336000 279.94 4106.00
1430 687048.38 332000 279.19 4084.00
1440 695202.14 332000 281.43 4104.00
1450 700610.60 328000 281.81 4078.00
1460 704462.53 328000 282.87 4108.00
1470 710215.40 324000 283.35 4078.00
1480 716061.53 324000 284.95 4118.00
1490 720095.10 320000 284.96 4084.00
1500 724323.60 316000 285.02 4100.00
1510 729269.91 316000 286.38 4096.00
1520 732658.29 312000 286.21 4078.00
1530 739202.82 312000 288.00 4080.00
1540 742057.54 308000 287.69 4058.00
1550 749044.53 308000 289.60 4104.00
1560 752204.00 304000 289.37 4078.00
1570 759076.52 304000 291.25 4100.00
1580 762089.05 300000 290.98 4070.00
1590 768415.08 300000 292.72 4102.00
Results

We conducted multiple simulations with varying lengths (1000, 2000, 3000, 4000, 5000, and 6000). Our findings indicated that when the simulation length is less than 4000, the Economic Order Quantity (EOQ) is approximately 1010. Additionally, we found that the results improve as the simulation length increases.