Making An Economy Simulator

Wojciech Bogócki
13 min readOct 18, 2020

--

Inspired by Perfect Competition and Victoria 2

I wanted to make an economy simulation for a while.

Why?

Like you (or anybody), I love playing video games, particularly the grand strategy genre. You know, the kind where you take control of a country and play a Grand Campaign lasting hundreds of years. One of my favourites in this genre is Victoria 2 and it does something extraordinary that no other game (none!) does: underlying the gameplay is a complete and sophisticated (some people would argue) economic simulation of the entire 19th-century world!

The real world is largely opaque to us and we have a limited ability to interact with it in both scope and magnitude. A computer simulation is like a small world where these properties don’t exist. We can watch events as they unfold in real-time and understand why and how they came to be with perfect clarity. We can also change anything we like at will. In an economic simulation, we can add and remove goods, people, factories, money, etc. and watch how the markets respond. Isn’t this über-cool?

If this doesn’t make you feel wonder and the desire for exploration I have nothing to offer you and you can probably stop reading here.

But if it does, I have good news. We’re going to create our own simulation of an economy! 😁

Source code will be available at the end of the article.

Simulating The World Economy

How do we do that? First of all, we sort of can’t. To simulate the real world accurately we’d have to accurately simulate everything in it, including humans. At the moment — not possible!

What we can do is design a model that behaves by economic principles and simulate it instead of the real world. Victoria 2 does that for fun and economists do it for science. We’re going to do it for both.

Slight off-topic here: It might be interesting to make a neural net and let it play the economic game. I’m not going to do it here but it might be interesting to see what would happen. 😝

So, let’s define the rules that will govern our simulation.

The Market Structure

I chose to base the sim on a widely known model called Perfect Competition. If you’re interested in economics this is basic knowledge for you. If you’re not — go read about it — it’s basic stuff and it’s super cool.

Perfect Competition has a sister market structure known as Imperfect Competition that is a better fit for most real markets. We won’t use it because it would make the sim much more complicated.

Perfect Competition makes the following assumptions:

  1. Goods are commodities (i.e. identical)
  2. Firms are price-takers
  3. Buyers have perfect information about the market
  4. Resources are perfectly mobile
  5. There are no barriers to enter or exit the market

I won’t explain them here in detail but the gist is that they let us do some nice things:

  1. Because goods from different firms are homogeneous, we can store them as a single integer. There are no Snickers’ and Twix’s, just chocolate bars.
  2. Because firms are price-takers, we can calculate and set the price centrally for the whole market.
  3. Because there are no entry barriers, we can create and remove new firms freely. This has the added benefit of making the market more efficient.

Pretty cool, no?

The Price Equilibrium

The next thing to do is deciding how we’re going to calculate prices.

You probably already know about the laws of demand and supply. If not, they are very intuitive:

The Law Of Demand — All else being equal, as the price of a good increases, quantity demanded decreases; conversely, as the price of a good decreases, quantity demanded increases.

The Law Of Supply — All else being equal, as the price of a good increases, quantity supplied increases; conversely, as the price of a good decreases, quantity supplied decreases.

What we want is to meet in the middle, where supply and demand are equal. In less abstract terms we want to produce exactly the amount we’re trying to consume.

I found that a simple oscillator that changes direction based on whether demand or supply is greater works best. Let me show you the code, then talk a little about how it works.

Market Definition

Then on each day, we do:

Market Logic

This is very similar to doing a Binary Search for the equilibrium price (equilibrium is where demand equals supply).

I don’t remember where I got the idea of doing it this way but (AFAIK) this is also one of the method calculators use to find roots of equations, intersection points, etc. I love how the same works here for a totally different application.

Before I close this part, there are two more things to say:

  1. We could improve the smoothness and accuracy of the oscillator by using a float to store the price. I do that in the final version as an intermediate step before rounding the price and storing it as an int. You can look at the source to see exactly how this works.
  2. By playing with the magic numbers we could adjust how aggressively the market responds to demand and supply changes. The numbers I used work well.

To avoid rounding errors we need to store prices and money as integers. Real world software also does this. Well… most of the time.

Alright. We got ourselves a pricing mechanism. 🎉

Designing The World

We have to decide what we’re actually going to simulate. By that I mean things like:

  1. What goods are there going to exist?
  2. What actors are going to be producing and consuming those goods?
  3. How is the flow of trade going to look like?

Model selection is actually fairly arbitrary. There could be 2 products being circulated or 1000. There could be one class of people or multiple. There could be one type of factory or 1000 types of factories. The flow of goods could be arbitrarily complex. It’s up to you. 😁

Earlier, I hinted that I was going to go for a Victoria 2-inspired system with pops (people) and factories. I’m aiming for clarity so I’m also going to make it relatively simple.

Pops are a unit of population in Victoria 2. I’m going to use that term too. You can think of pops as simulated people.

Let’s look at the model we’re going to use.

Here are the goods:

Here are the actors:

Here is the flow of trade:

Flow Of Trade

Great! Now that we have the model let’s see how we can implement it.

Building The World

I’ll start by showing you how everything is defined in code, then we’ll look at the trading and actor’s logic:

Definitions

If you’re curious why I put pops and factories in fixed-size arrays, it's because C doesn't have dynamic arrays in the standard library.

Buying & Selling

Our economic sim will need a mechanism for actors to buy and sell goods. This is a subtler problem than it might seem because whatever mechanism we come up with will become the basis for actor logic later on.

Let’s first look at how we do this in real life.

Here are some of the factors that could go into making a decision:

  1. The price of a good
  2. The degree to which we need or want it
  3. The amount of money we make
  4. The amount of money we have
  5. The price of other goods and the degree to which we need or want them
  6. The plans and expectations about the future

Good luck with implementing that! 😵

I can’t say if there is a good solution that works this way — I didn’t find one. Perhaps one using weights or a neural net would work. I’ll leave it for you to find out. I can tell you that writing this out in a procedural fashion quickly becomes too complex to work with.

There’s a better way.

While tinkering I noticed that instead of trying to calculate optimal buying parameters, allocating a fixed budget upfront was far simpler and worked reasonably well. More importantly, buying logic at that point was complex and full of branches, the change made it almost linear!

Let me show you what I came up with.

The buy() procedure looks like this:

Buy

This lets us say things like:

  1. Spend 40% of the money on food.
  2. Spend 20% of the money on clothes.
  3. Save the remainder.

Notice that we are not saying how much to buy, only for how much. This is on purpose and makes for a very streamlined budgeting logic.

I have to point out that this is also the opposite of what we do in real life. We usually start with how much of something we want rather than how much money we have (at least I do). If we wanted to, we could change the buy() signature to account for this. The only reason I hadn't done so is that I only thought about it at the time of editing this article. 😛

Here are a few ways this approach exceeds in:

  1. It depends on a single variable: budget.
  2. It composes really well if we want to buy multiple things.
  3. It responds to price changes in a reasonable way.
  4. It amortizes spending over time thus lowering the likelihood of suddenly running out of money.
  5. It’s balls-to-the-wall simple.

By doing things this way we also accidentally introduced control over another real-life economic phenomenon: the velocity of money. This isn’t useful for us right now but getting it by accident made me smile! 😂

The glaring deficiency of this approach is that constant budgets are rigid and therefore not optimal. We could add some sort of dynamic budgeting and limit the bought amounts to amend this. I’ll leave it to you as an exercise if you’re interested in doing it.

One more thing. Do you remember the demand and supply fields on the market struct? In addition to buying, buy() will add the amount afforded by budget to demand. Supply is handled by buy()'s sister procedure sell(), which doesn't actually sell anything but merely informs the market about goods being available for sale. The name is a bit bad but it will do. 🤷‍♂️ If you were wondering where we get the supply and demand data, now you know. 😁

Sell

Ok, cool. We have laid down the groundwork for trade. It’s time to implement actors.

Pops

Here are the rules I came up with for pops based on the model from before.

On each day, each pop will:

  1. Buy food and clothes.
  2. “Produce” labour.
  3. Lose or gain health depending on if the pop got enough food and clothes.

In addition, once all pops finish simulating we process them again and:

  1. Pops who reach 0 health die.
  2. Pops who reach 10 health reproduce.

Here’s how that looks like in code:

Pop Life
Pop Death
Pop Birth

Factories

Factories will do a similar thing except that each factory will produce either food or clothes, depending on its type.

On each day, each factory will:

  1. Buy labour.
  2. Produce based on the amount of acquired labour.
  3. Close if it can’t obtain enough labour.

In addition, once all factories finish simulating:

  1. If a factory has been closed for 5 days, it’s liquidated.
  2. If a factory has more than FACTORY_COST money then it creates a new factory.

The 2nd point is not at all how this happens in real life. However, because we’re simulating a Perfectly Competitive market, we need some way to create new factories as existing ones become profitable. Doing so in response to factories accumulating money is the direct solution.

As for FACTORY_COST, it's just a magic number I chose. In a bigger simulation, this might be expressed in terms of goods needed to build a new factory.

In the real world a new firm would enter the market when the expected profit is greater than or equal its opportunity cost. You can read on opportunity cost here, it’s a really simple and cool idea that’s also useful in everyday life.

Okay, here’s the code for factories:

Factory Operation
Factory Liquidation
Factory Building

That’s it. This was the last part we needed. It’s almost time to run the sim!

Before we do that I want to talk about two more things that I couldn’t find a place for earlier. Namely, the money supply and the production equation.

Notice how we always make sure to never “lose” or “gain” any money whenever we add or remove actors? That’s because the quantity of money affects its value. There’s even a theory dedicated to this: Quantity Theory of Money.

For example, this is what happens if you 2x the money supply:

300,000 Virtual Dollars In Circulation
600,000 Virtual Dollars In Circulation

Note that for this to work I had to 2x the FACTORY_COST because it won't automatically scale with the money supply. If you don't change it, you'll get roughly the same prices because more factories will be built, more pops born and the ratios will end up the same.

There’s one other thing that can happen if the money supply is too low. Imagine if the lowest denomination of the real-life US dollar was 100. Yep, no 1, 5, 10, 20, 50 dollar bills. Coins don’t exist either. What’s the lowest price a thing can have? Yep, it’s $100. The second-lowest is $200. 😎 While is unlikely to pass in real life, it might happen in our sim.

The lowest price possible in the sim is 1 unit of money. You just saw that “printing” money rises prices. The opposite is also true, destroying money lowers prices. If the money supply is too low relative to the size of the economy, the markets won’t be able to accurately represent the value of goods and the sim will misbehave.

Ever wanted those $100 ice cream? 😁

Because the money supply in our sim is fixed, we should observe deflation as the economy inside grows.

The Production Equations

The second thing I wanted to talk about is the output calculation for factories. You may have noticed that we defined factory outputs as logarithmic functions. There’s a good reason for this.

Here are a few function types and their effects.

If the function is linear then the number of factories doesn’t matter because a single factory will produce the same amount as any number of factories, whether one hundred or one million. We want some sort of efficiency change built into the equation.

If the function is upward-pointing (e.g. a quadratic function) then a single factory is optimal. However, the simulation will grow at an exponential rate and prices will collapse to 1 (assuming fixed money supply). We don’t want that.

I couldn’t think of a better term so I just said upward-pointing. Hopefully you understand what I mean. 😜

A working function must create diminishing marginal returns. We want to make sure that it’s reasonable for many factories to exist — but not too many. We do this by making factories first gain then lose efficiency per unit of labour.

In other words:

Output Equations

Running The Simulation

If you read this far I applaud you. You’re awesome! Let’s actually run the simulation. The source code will be available at the end of the article for you to play with.

I’ll play the simulation now and let you follow along. I wrote some commentary for each day I show. Enjoy!

<Presses The Button>

Day 1

It’s the first day in a new world. There are 10 pops, 10 food factories and 10 clothes factories. Prices are parked at 1 and some trades are already happening. The demand is abundant, the supply is scarce. The markets have yet to move.

Day 2

There’s a slight pressure forming — as long as it continues, prices will eventually budge. 10 new pops are born and 20 new factories are built.

Day 10

On day 10, prices have moved for the first time in history. The world is slowly starting to populate with pops, there are now 40 of them. Factory counts are also rising, 135 food and 100 clothes factories have been built.

Day 17

Today the supply of food exceeded the demand for the first time and the population more than doubled — as did the supply of food.

Day 21

11 days since prices first started moving they finally decouple from each other. Food and clothes are starting to stabilize as labour costs continue to climb.

Day 24

In three days, labour price grew by over 150 units and tripled. This is the largest swing this world will ever see.

Day 40

The rapidly growing population continues to fuel instability in the labour market. A few factories go out of business but all three markets keep growing. The labour market has expanded more than four times. The future looks bright.

Day 50

There are finally signs of consolidation. The labour market has finally caught up with the population boom.

Day 100

The days of market instability and large swings are over. The pop count has exceeded the market’s ability to provide clothes. Deflation due to fixed money supply combined with fast growth is starting to become a problem.

Day 300

The population has plateaued around 7600. It’s unable to outgrow the limited supply of clothes. This world has reached its peak and settled.

The End.

Areas For Improvement

The pop budgeting strategy ultimately fell short overbuying food and underbuying clothes towards the end. If pops committed a bigger percentage of their money to buy clothes, the sim would’ve been able to grow more.

My factory building strategy caused all factories to be built towards the beginning and their number only decreased later. A different method might’ve also been able to solve the final clothes shortage. In hindsight, this was a bad idea.

The fixed money supply also caused trouble towards the end. Can you see that the prices towards the end are all very low and seem stable but the market forces are imbalanced? Let’s take the example of food, its price is 6 but its value is actually closer to 6.5. As deflation progressed, the market began alternating between 6 and 7 each day to stay balanced. If the money supply was greater or growing with the economy, this wouldn’t have been a problem.

Closing Thoughts

There you go. I’m resisting the temptation of saying et voila right now. Whoops… I said it. 😂

This the first time ever I write an article for the public (you). If you somehow read this far you’re a true madman. I love how the final simulation report ended up. Overall there is a lot of emergent stuff happening all over that I didn’t expect and it’s amazing. 🤠

Alright, while I’m almost finished here, there’s still a ton to explore — I’ll leave that for another article. I hope you enjoyed this as much as I did. Economy sims are cool, no? 😁

One last thing. We (me and my GF) recently started a small dev school project called W&J Dev School. The plan is to make stuff, teach and help people. There’s also a YouTube channel to go with it.

We’re going to be making more things like this sim, tutorials, playing Zachtronics games and more so go check it out and give us a sub! Next in the queue are a game console emulator (Chip8) and a scripting language. At least I think so — we’ll see. 😁

If you have any questions or want to learn/need help with programming email me at wojciech@wjdevschoolcom.

I’m happy to assist you in any way I can. 🧐😊

If you like this article and want to help us you can follow us on Facebook and Twitter. We’ll also be posting updates about new articles there. 😋

Currently, we’re still super tiny and every single like is of BIG help! 🙏🤠

See you in the future and let’s make more cool stuff!

Cheers!

Links

Originally published at https://wjdevschool.com.

--

--