Oil Market Simulation
- Python
- Agent-Based Modeling
- Discrete-Time Simulation
- Monte Carlo Analysis

The Oil Market Simulation is a discrete-time, agent-based model designed to study how a semi-stable commodity market responds to sudden supply disruptions. It tracks prices, seller inventory, transaction volume, resource availability, and unmet demand as independent buyers and sellers interact over time.
The model is intentionally narrow. It does not attempt to reproduce the entire global oil industry or predict real market prices. Instead, it isolates a smaller engineering question: how does a constrained market evolve after a major shock when no external corrective intervention is introduced?
Why I built it
I built this project to study modeling and simulation as an engineering discipline rather than treating a simulation as only a visual demonstration.
Oil markets are useful for this purpose because they depend on limited resources, relatively stable production rates, distributed participants, and repeated interactions between supply and demand. They can remain semi-stable for long periods before production outages, geopolitical disruptions, or unexpected changes in demand push the system into a transient state.
Analytical models can describe equilibrium behavior, but they do not always make it easy to observe how individual market participants, uncertainty, and local decision rules produce system-wide behavior over time. This project allowed me to define those participants directly, control the assumptions of the model, introduce repeatable shocks, and inspect the resulting dynamics.
Simulation objective
The simulation investigates how the following variables change after a disruptive supply shock:
- seller prices
- available inventory
- transaction volume
- fulfilled demand
- unmet demand
- market recovery behavior
Each run begins from a semi-stable market state. At a predefined timestep, a shock reduces or removes production capacity from one or more major sellers. After that event, the market is allowed to evolve according to the existing agent rules without regulatory action, emergency production, or other outside intervention.
System model
The simulation contains four primary components:
Buyer agents
Buyers represent individual consumers or aggregate consumer groups. Each buyer is initialized with a fixed willingness-to-pay value that represents persistent constraints such as budget or consumption tolerance.
At each timestep, a buyer generates demand stochastically. The buyer then attempts to purchase from sellers whose price does not exceed its willingness to pay and whose inventory is greater than zero. Buyers operate only on locally available information and do not know the complete state of the market.
Seller agents
Sellers represent oil producers. Each seller maintains:
- a price per unit
- current inventory
- a production rate
- a maximum capacity
At the start of each timestep, sellers replenish inventory according to their production rate and capacity constraints. After transactions are processed, sellers adjust prices using feedback from recent utilization and sales performance.
Sellers do not forecast future conditions, coordinate strategically, or possess global market awareness.
Market mechanism
The market processes transactions between buyers and sellers. It determines which sellers are eligible for a buyer, enforces willingness-to-pay and inventory constraints, executes purchases, and records unmet demand when a buyer cannot obtain the requested quantity.
The market does not optimize for fairness, efficiency, or equilibrium. It applies consistent allocation rules and allows larger behavior to emerge from repeated local interactions.
Shock events
Shock events are discrete, externally scheduled disruptions. A shock can reduce a seller’s production rate or capacity for a defined duration and severity.
This makes it possible to compare normal market behavior against controlled supply-loss scenarios while keeping the rest of the model unchanged.
How it works
The simulation advances through fixed timesteps. A single step follows this sequence:
- Sellers replenish inventory.
- Any scheduled shock is applied.
- Buyers generate stochastic demand.
- The market processes buyer-seller transactions.
- Unfulfilled demand is recorded.
- Sellers update prices from observed utilization.
- System metrics are logged.
- Time advances to the next step.
Buyer demand can be sampled from a discrete probability distribution such as a Poisson distribution, while willingness-to-pay values are assigned from a bounded distribution during initialization.
Seller pricing adapts through a feedback rule based on utilization. Sellers with high sell-through can increase price, while sellers with low utilization can reduce it toward a defined minimum. The rule is deliberately simple and interpretable so that observed behavior can be traced back to model assumptions.
Engineering approach
The model was implemented in Python using a lightweight custom architecture rather than a prebuilt simulation framework. This keeps the relationship between the conceptual model and executable logic visible.
The core system separates responsibilities across simulation, buyer, seller, market, shock-event, and metrics-logging components. Each run is initialized with an explicit random seed so that stochastic behavior remains reproducible.
The simulation records structured output at each timestep, including:
- individual seller prices
- inventory levels
- production rates
- transaction volumes
- unmet demand
- active shock state
The resulting data supports both inspection of a single run and comparison across repeated runs with different random seeds or shock parameters.
Model boundaries
This project deliberately simplifies the real oil market. The current model assumes:
- one homogeneous commodity
- no product substitutes
- no international trade network
- fixed buyer willingness-to-pay traits
- stochastic but non-learning buyer demand
- adaptive but non-strategic sellers
- no forecasting or collusion
- no external intervention after a shock
- local information only
- discrete-time progression
These constraints are not presented as realistic descriptions of every market participant. They are model boundaries chosen to isolate the effects of supply disruption, demand uncertainty, inventory constraints, and adaptive pricing.
Current state
The first version of the simulation is complete. It includes the core agent structure, market transaction process, shock scheduling, adaptive seller behavior, reproducible execution, and metric collection needed to study market response over time.
The project repository also contains the model documentation and UML artifacts used to define the class structure and execution flow before implementation.
What I learned
The most important lesson from this project was that simulation quality depends less on adding complexity than on defining boundaries clearly.
Every additional behavior can make a model appear more realistic while also making its results harder to explain. Fixed buyer traits, local decision rules, controlled randomness, and explicit shock events made it possible to trace market behavior back to concrete assumptions.
The project also reinforced the value of separating the conceptual model from the implementation. Defining the agents, system boundaries, state transitions, and measured outputs before writing the simulation reduced ambiguity and made the final system easier to test and analyze.
What I would do differently
I would define the experimental plan and validation criteria earlier in development.
The system architecture and agent rules were established before the final analysis workflow was fully specified. In a future version, I would define baseline scenarios, shock-severity ranges, run counts, comparison metrics, and expected invariants before implementing the complete model.
I would also separate simulation execution from analysis more aggressively so that large Monte Carlo studies could be run headlessly and evaluated through an independent analysis pipeline.