Revenue management for Python: single-leg seat protection (Littlewood, EMSR-a/b), overbooking, pricing, network bid prices and the standard performance metrics. Computed from standard methods and validated against published worked examples.
Project description
revmng
Revenue management for Python: the building blocks for selling fixed, perishable capacity well. Single-leg seat protection, overbooking, pricing, network bid prices and the standard performance metrics, computed from the textbook methods and validated against published worked examples.
The core has no third-party dependencies. Every result carries provenance
(library version, input hash, timestamp) and a JSON-safe to_dict().
pip install revmng
Quick start
import revmng
# Two-class seat protection (Littlewood's rule)
revmng.littlewood(fare_high=1000, fare_low=400, mean_high=50, sd_high=18)
# -> protect this many seats for the high fare; sell the low fare below it
# Multi-class nested booking limits (EMSR-b, the industry-standard heuristic)
a = revmng.emsr_b(
[(1000, 30, 12), (700, 40, 15), (400, 60, 20)], # (fare, demand mean, sd)
capacity=120,
)
a.booking_limits_int # nested whole-seat booking limits
print(a.summary())
# Overbooking: balance the cost of bumping against the cost of empty seats
o = revmng.overbooking_limit(100, no_show_rate=0.12,
denied_cost=400, spoilage_cost=180)
o.authorization_limit # how many reservations to accept
# Pricing: the newsvendor stocking quantity and the profit-maximising price
revmng.newsvendor(price=10, cost=4, demand_mean=100, demand_sd=30).optimal_quantity
revmng.optimal_price(revmng.LinearDemand(intercept=100, slope=2), unit_cost=10)
# Score booking limits against perfect-hindsight and no-control benchmarks
revmng.revenue_opportunity([1000, 800, 600, 200], [25, 30, 20, 50], capacity=100,
booking_limits=[100, 70, 45, 32]).rom
# Exact optimal protection levels (and the expected revenue EMSR leaves behind)
opt = revmng.optimal_protection_levels(
[(1000, 30, 12), (700, 40, 15), (400, 60, 20)], capacity=120)
opt.expected_revenue
# Should we take this group? (displacement analysis)
cost = revmng.group_displacement(group_size=30, capacity=100,
demand=[70, 95, 85], value_per_unit=70)
revmng.evaluate_group(group_rate=60, units=90, displacement_cost=cost,
variable_cost=50).accept
# Should we accept this multi-night stay? (length-of-stay bid-price control)
revmng.evaluate_stay({"Mon": 80, "Tue": 120, "Wed": 90},
["Mon", "Tue", "Wed"], total_rate=320).accept
Network bid prices need SciPy and the charts need matplotlib:
pip install "revmng[network]" # bid_prices via the deterministic LP
pip install "revmng[plot]" # booking-limit, overbooking and ROM charts
from revmng import Product
n = revmng.bid_prices(
[Product(fare=200, uses={"AB": 1}, demand=60),
Product(fare=300, uses={"AB": 1, "BC": 1}, demand=40)],
capacities={"AB": 100, "BC": 100},
)
n.bid_prices # marginal value of each resource
n.accept(fare=250, uses={"AB": 1, "BC": 1})
What it covers
| Area | Functions |
|---|---|
| Single-leg capacity control | littlewood, emsr_a, emsr_b |
| Exact optimal control | optimal_protection_levels, policy_revenue |
| Overbooking | overbooking_limit (service level and cost based) |
| Pricing | newsvendor, optimal_price (LinearDemand, ConstantElasticityDemand) |
| Group evaluation | evaluate_group, group_displacement |
| Length-of-stay | evaluate_stay |
| Performance metrics | revpar, adr, occupancy, yield_, load_factor, rasm, casm, spill, spoilage |
| Revenue opportunity | revenue_opportunity, nested_revenue |
| Network (needs SciPy) | bid_prices, Product |
| Charts (needs matplotlib) | booking_limit_chart, overbooking_cost_curve, revenue_opportunity_chart |
optimal_protection_levels computes the exact optimal nested protection levels
by dynamic programming (the policy the EMSR heuristics approximate) and reports
the optimal expected revenue; policy_revenue scores any policy against it.
Group and length-of-stay decisions share one idea: accept a request when its
contribution covers the opportunity cost of the capacity it displaces (a
marginal seat value or a sum of nightly bid prices).
Demand for the capacity-control methods is assumed normal and independent, with the classic low-before-high booking assumption. EMSR-a and EMSR-b are heuristics; for two classes both reduce to Littlewood's optimal rule.
What is out of scope
revmng computes decisions from the demand you supply. It does not forecast demand, estimate willingness-to-pay, or unconstrain censored bookings, and it does not connect to any reservation, property-management or distribution system. Those belong upstream; keeping them out is what lets every result here be reproduced and audited.
Validation
The methods are checked against published and hand-derived worked examples (see
tests/validation_cases.json):
| Method | Source | Result |
|---|---|---|
| Littlewood booking limits | Phillips, Pricing and Revenue Optimization (2005), Ex. 9.2 | 25 / 50 / 76 reproduced |
| Revenue opportunity metric | Phillips (2005), Ex. 9.7 | perfect 66000, no-control 46000, realized 59200, ROM 66% |
| EMSR-b (two classes) | Belobaba (1989) | equals Littlewood's optimal rule |
| EMSR-b (three classes) | Belobaba (1989) formula, arithmetic shown | protection 23.71 / 70.83, limits 97 / 50 |
| Optimal control (DP) | Talluri and van Ryzin (2004) | matches Littlewood for two classes; expected revenue at least EMSR-b's |
| Group displacement | standard displacement analysis, arithmetic shown | 40 displaced room-nights, cost 2800, break-even rate 81.11 |
| Length-of-stay bid price | Talluri and van Ryzin (2004), arithmetic shown | 290 hurdle, accept at rate 320 |
| Newsvendor quantity | critical-fractile rule | reproduced |
| Overbooking (service level) | deterministic no-show formula | reproduced |
Definitions and methods
- K. Littlewood, "Forecasting and control of passenger bookings" (1972).
- P. Belobaba, "Application of a probabilistic decision model to airline seat inventory control," Operations Research (1989). EMSR-a and EMSR-b.
- K. Talluri and G. van Ryzin, The Theory and Practice of Revenue Management (2004).
- R. Phillips, Pricing and Revenue Optimization (2005).
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file revmng-0.1.0.tar.gz.
File metadata
- Download URL: revmng-0.1.0.tar.gz
- Upload date:
- Size: 31.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c4ca0d72a9885b402b7beb307a2c890daf13c51f79a9868501c1c50c8c7efbc
|
|
| MD5 |
6b955e0fafc18cd1a006d1a4daedc9ef
|
|
| BLAKE2b-256 |
ba74ba2233c9327063de6bdb318789334711750888f26e7b70e1ff1a2c870c67
|
Provenance
The following attestation bundles were made for revmng-0.1.0.tar.gz:
Publisher:
release.yml on arikanatakan/revmng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
revmng-0.1.0.tar.gz -
Subject digest:
8c4ca0d72a9885b402b7beb307a2c890daf13c51f79a9868501c1c50c8c7efbc - Sigstore transparency entry: 1839125378
- Sigstore integration time:
-
Permalink:
arikanatakan/revmng@c6755c31cea6a90f4951e2ab212ba7813c9d3c03 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arikanatakan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c6755c31cea6a90f4951e2ab212ba7813c9d3c03 -
Trigger Event:
release
-
Statement type:
File details
Details for the file revmng-0.1.0-py3-none-any.whl.
File metadata
- Download URL: revmng-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2609cf1e0b7b3516f45e43be8552f1a202a2e328850977c579bf9e378b86a66b
|
|
| MD5 |
33d1b2e48d2654897f4da96e2ec4998e
|
|
| BLAKE2b-256 |
71a0b829729f5c9e0351765b3f93769e817a17a93a728ae3e44d127bfa3aa143
|
Provenance
The following attestation bundles were made for revmng-0.1.0-py3-none-any.whl:
Publisher:
release.yml on arikanatakan/revmng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
revmng-0.1.0-py3-none-any.whl -
Subject digest:
2609cf1e0b7b3516f45e43be8552f1a202a2e328850977c579bf9e378b86a66b - Sigstore transparency entry: 1839125394
- Sigstore integration time:
-
Permalink:
arikanatakan/revmng@c6755c31cea6a90f4951e2ab212ba7813c9d3c03 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arikanatakan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c6755c31cea6a90f4951e2ab212ba7813c9d3c03 -
Trigger Event:
release
-
Statement type: