Multi-agent simulation of a Combinatorial Clock Auction. An auctioneer and a configurable set of bidder agents communicate through messages while the simulator executes the two auction phases:
- In the clock phase, bidders submit resource demands and prices increase for resources with excess demand.
- An eligibility-based activity rule limits later bundle changes and final bid values.
- In the final phase, bidders submit XOR package bids.
- Exact winner determination selects the feasible allocation with the highest reported value, followed by VCG payment calculation.
The repository includes JSON-based experiment orchestration, readable console traces, stored result JSON, and static result plots.
auction/domain/: bundles, bids, products, production plans, allocations, and shared resource typesauction/core/: scenario loading, simulator, message bus, trace formatting, and result-facing simulation recordsauction/agents/: auctioneer and bidder agents driven throughAgentBase.step()auction/protocols/: auction message dataclasses and the CCA phase state machineauction/mechanisms/: clock-price updates, activity rule, exact winner determination, and VCG paymentsorchestration/: experiment/profile loading, batch execution, and JSON result serializationanalysis/: static plots and text summaries generated from stored result JSONconfigs/scenarios/: resources, supply, bidders, budgets, and productsconfigs/run_profiles/: mechanism, seed, round limits, and price incrementconfigs/experiments/: scenario/profile/repetition combinationsdocs/: class and sequence diagramsresults/: generated and prepared experiment output
Simulatorowns the round clock and calls each agent once per simulator round.- Agents communicate only through the
MessageBusinterface. The local runner usesInMemoryMessageBus. CCAInstancetracks the clock and final-bid phases but does not deliver messages itself. Agents own message sending.- The mechanism modules operate on auction data and do not depend on the CLI or plotting layer.
ExperimentRunnerexecutes every scenario/profile/repetition combination from an experiment file.- Plotting consumes stored result JSON only; it does not rerun agents or depend on the message bus.
Use Python 3.12 or 3.13. Other versions are excluded by pyproject.toml.
Create a virtual environment and install the simulator in editable mode:
python3.13 -m venv .venv
source .venv/bin/activate
python -m pip install -e .The simulation itself has no third-party runtime dependency. Install the optional reporting dependency when generating plots:
python -m pip install -e ".[report]"The editable installation provides two console commands:
clock-auction Run an experiment configuration
clock-auction-plot Generate plots from a stored result JSON
All examples below use python3 main.py and python3 -m analysis.plot_results.
The installed commands are equivalent.
Run the small two-bidder example, print the auction trace without delays, and write a stable result path:
python3 main.py configs/experiments/example.json \
--trace \
--trace-delay 0 \
--output results/example.jsonThe command prints every clock evaluation, price change, eligibility reduction, final XOR bid, allocation, and payment. It finishes with:
Wrote experiment results to results/example.json
The same run through the installed entry point is:
clock-auction configs/experiments/example.json \
--trace --trace-delay 0 \
--output results/example.jsonRunning without an experiment path uses configs/experiments/example.json.
Running without --output creates a timestamped file at:
results/<experiment-id>/<DDMMYYYY-HH-MM>/result.json
configs/experiments/a3_experiments.json runs the five scenarios in assignment
order with the deterministic cca_default profile:
| Part | Scenario | Bidders / products | Purpose |
|---|---|---|---|
| (a) | simple_three_resource.json |
2 / 5 | Small correctness case with a hand-checkable allocation and positive VCG payment. |
| (b) | complex_overdemand.json |
4 / 8 | Nontrivial baseline with initial excess demand and bundle changes. |
| (c) | complex_early_exit.json |
4 / 8 | Same market as (b), but B2 loses eligibility early. |
| (d) | complex_supply_surplus.json |
2 / 4 | Bidders are removed from (b), producing supply surplus and first-round clearing. |
| (e) | complex_high_overdemand.json |
6 / 12 | Bidders are added to (b), increasing demand pressure and clock duration. |
Run all five scenarios and store one result document:
python3 main.py configs/experiments/a3_experiments.json \
--trace \
--trace-delay 0 \
--output results/a3_experiments/canonical/result.jsonPrepared output is available under
results/a3_experiments/canonical/, including the result JSON, a complete
console trace, detailed per-run plots, comparison plots, and report figures.
Add --trace to print a readable narration and include full simulator trace
frames in the result JSON:
python3 main.py configs/experiments/example.json --traceThe default trace delay is three seconds per printed simulator round. This is
useful for a paced recording. Use --trace-delay 0 for an immediate run, or
press Enter to continue early while a delayed trace is running.
Each configured run begins with its experiment, scenario, profile, repetition,
and bidder behavior. The footer reports whether it completed and why it stopped.
Possible termination reasons include market_cleared,
max_clock_rounds_reached, and max_simulator_rounds_reached.
Plotting requires the optional report dependency:
python -m pip install -e ".[report]"Generate plots and a text summary from any result document:
python3 -m analysis.plot_results \
results/example.json \
--output-dir results/example_plotsOr use the installed command:
clock-auction-plot results/example.json \
--output-dir results/example_plotsWhen --output-dir is omitted, the tool creates <result-name>_plots beside the
result file. For example, results/example.json produces
results/example_plots/.
Generated artifacts include:
<run>/market_dynamics.png: prices, aggregate demand and supply, excess demand, and bidder eligibility by clock round<run>/bidder_outcomes.png: realized values, payments, utility, and retained eligibilityexperiment_comparison.png: multi-run market-pressure or generic experiment comparisonbidder_condition_comparison.png: focused bidder comparison when matching conditions are availablesummary.txt: completion state, prices, welfare, revenue, utility, utilization, allocations, and payments
Incomplete runs remain visible in summary.txt but are excluded from economic
comparison plots.
Use --output for a predictable path:
python3 main.py configs/experiments/example.json \
--output results/example.jsonUse --results-root to change only the root of timestamped output:
python3 main.py configs/experiments/example.json \
--results-root build/resultsEach result document contains:
- experiment ID and creation time
- one record per scenario/profile/repetition combination
- run status, completion flag, and termination reason
- a snapshot of the loaded scenario and the effective run configuration
- normalized clock rounds with prices, demand, supply, excess demand, and eligibility
- activity reductions, final XOR bids, allocation, payments, and bidder outcomes
- message count and, when
--traceis enabled, detailed trace frames and messages
Parent directories are created automatically.
Configuration is split into three layers. Paths inside an experiment file are resolved relative to the project root.
A scenario declares the resources and bidder production possibilities:
{
"id": "small_market",
"resources": {
"A": {
"supply": 2,
"eligibility": 1,
"initial_price": 10
}
},
"bidders": [
{
"id": "B1",
"budget": 30,
"products": [
{
"id": "product_a",
"resources": {"A": 1},
"value": 20
}
]
}
]
}Resource names are dynamic strings; the mechanism is not limited to A, B,
and C. Product resource quantities must be positive integers. Supply, budgets,
prices, and values may be zero. Eligibility weights must be positive.
The optional bidder field behavior defaults to truthful. The experiment-(c)
scenario uses "behavior": "early_exit" for B2 to force a premature eligibility
reduction while leaving the bidder's products and values unchanged.
A run profile controls simulator and price-update behavior:
{
"id": "cca_default",
"mechanism": "cca",
"seed": 42,
"max_rounds": 100,
"max_clock_rounds": 10,
"price_increment": 2
}max_roundslimits simulator message-processing rounds.max_clock_roundslimits evaluated economic clock rounds.price_incrementis the base price step before excess-demand scaling.seedis stored with the result. If omitted, the runner generates and stores a seed for that run.
Trace settings can also be placed in a profile as trace_enabled,
trace_to_stdout, and trace_round_delay_seconds. The CLI --trace option
enables them for the current execution without modifying the JSON file.
An experiment combines one or more scenarios and profiles. The runner executes their Cartesian product for every repetition:
{
"id": "small_experiment",
"scenarios": [
"configs/scenarios/simple_three_resource.json"
],
"run_profiles": [
"configs/run_profiles/cca_default.json"
],
"repetitions": 1
}Show all simulator options:
python3 main.py --help| Option | Default | Description |
|---|---|---|
experiment |
configs/experiments/example.json |
Optional positional path to an experiment JSON file. |
--output |
unset | Explicit result JSON path. Parent directories are created. |
--results-root |
results |
Root directory used for timestamped output when --output is omitted. |
--trace |
off | Print auction events and store detailed trace frames in the result JSON. |
--trace-delay |
3.0 |
Seconds between printed simulator rounds. Press Enter to continue early. |
Show all plotting options:
python3 -m analysis.plot_results --help| Option | Default | Description |
|---|---|---|
result |
required | Result JSON to read. |
--output-dir |
<result-name>_plots |
Directory for generated figures and summary.txt. |