Understanding Vernon Smith's 1962 "An Experimental Study of Competitive Market Behavior" Vernon Smith's 1962 paper &quot;An Experimental Study of Competitive Market Behavior&quot; simulates a market using students (who have piece of paper giving their reservation prices). In one of the experiments, the demand/supply curves look like the graph on the left, with the corresponding market activity on the right:

Since there seems to be nothing special about using students in the experiment (i.e. as far as I can tell, they are just performing simple computations), I decided to code up the experiment in Python. My script is here.
When I run the script (which has the same demand/supply curves as above), the market activity typically looks like this:

The market price does indeed hover around $2.00, but my graph seems noticeably more jagged than the graph in the original paper. I'm trying to figure out what's going on, in particular whether:

I'm understanding the paper incorrectly somehow, or
My Python script has some error in it, or
There's some kind of error or unwritten assumption in the paper.
I suspect that the reason for that result is the way how you modeled the situation is by having the prices to be offered at random from a sample of numbers in uniform fashion (unless I am misreading the code) but this is unrealistic.
As mentioned in the paper Smith's 1962:

each sequence of experiments was conducted over sequences five to ten minutes long

So the students had only 5-10 minutes to actually conclude the trades. Students knew their own valuation of the item and they wanted to get it.
In such situation it is not in students interest to just choose random price from the sample of prices. Rather students will be choosing from some distribution that will have more mass closer to the their own valuation.
My prediction is that if instead of random sampling of prices from the array you will let the program generate numbers from some distribution that has more mass closer to the right price you will see less volatility in the data.
For example, instead of using random.choice(price_deltas) you could use random.choice(price_deltas, p=weights) that allows you to assign weights to numbers so some are more likely than others.

EDIT:
You could use the weight approach above but I also discovered much simpler one. If you are just fine assuming prices can be continuous (which from point of economic theory is fine 0.01c is really just practical limit in real life), then what you can do is skip the creation of deltas at the start:
import numpy as np
import matplotlib.pyplot as plt
buyers = [3.25 - 0.25*n for n in range(0, 11)]
sellers = [3.25 - 0.25*n for n in range(0, 11)] 

Next what you can do is to replace random.choice() with some distribution that has most mass at zero - like the exponential distribution. In python this can be done using random.exponential(), the code would thus change only minimally, and will generate deltas that are closer to the actual valuation of the traders:
trading_prices = []
trading_counts = []

for _ in range(5):
    buyers_still_in_market = list(range(len(buyers)))
    sellers_still_in_market = list(range(len(sellers)))

    transactions = []

    for _ in range(1000):
        # First, a random buyer offers to buy at some price below their number on
        # their card
        b = np.random.choice(buyers_still_in_market)
        delta = np.random.exponential(400)
        buyer_price = max(0, buyers[b] - abs(delta))
        s = np.random.choice(sellers_still_in_market)
        if buyer_price &gt;= sellers[s]:
            transactions.append((b, buyers[b], s, sellers[s], buyer_price))
            buyers_still_in_market.remove(b)
            sellers_still_in_market.remove(s)
            trading_prices.append(buyer_price)

        # Then, a random seller offers to sell at some price above their number on
        # their card. #0.65 - for log normal
        s = np.random.choice(sellers_still_in_market)
        delta = np.random.exponential(400)
        seller_price = sellers[s] + abs(delta)
        b = np.random.choice(buyers_still_in_market)
        if seller_price &lt;= buyers[b]:
            transactions.append((b, buyers[b], s, sellers[s], seller_price))
            buyers_still_in_market.remove(b)
            sellers_still_in_market.remove(s)
            trading_prices.append(seller_price)

    trading_counts.append(len(trading_prices))

    print(len(transactions), &quot;transactions&quot;)

plt.plot(list(range(len(trading_prices))), trading_prices)
plt.ylim(0, 4.00)
for x in trading_counts:
    plt.axvline(x=x-1, ymin=0, ymax=4.0, color='red')
    print(&quot;line drawn at x =&quot;, x)
plt.show()

print(trading_prices)

This new code produces results that are much less 'jagged'. Here are some examples, of behavior of price with the exponential distribution (possibly different types of distribution would yield better result but its beyond scope of SE answer to examine that). For example, here are 8 graphs generated when the prices depend on exponential distribution: