Zero Intelligence Traders: Gode and Sunder (1993)¶
Overview¶
This section covers Zero Intelligence trading (or ZI traders). The idea of putting very low intelligence traders into a simple market was originally suggested in the influential paper of [GS93]. They wanted to explore the common feature of experimental trading markets where humans often did very well in terms of market efficiency and allocation of consumer/producer surplus. This was often thought of as a strength of human behavior, and our ability to interact well with common market institutions.
However, the fraction of market success to attribute to the institutional setup rather than the humans themselves had not been tested. Gode and Sunder used standard experimental protocols, but populated their markets with simple computer robo traders as would be done in any standard agent-based model. However, the traders were assumed not to think strategically, or do any advanced learning, or statistical modeling of the world around them. They generally did follow their budget constraints and did not trade in a way that would lose them money. For these reasons they referred to them as zero intelligence (ZI) traders.
We will see them in action in this section. The results will show that ZI traders can trade very effectively in a simulated market. Market efficiency is near 100 percent, and the prices often converge to the standard equilibrium price as predicted by economic theory. This surprising result demonstrates that many economic market features may rely as much, or maybe more, on institutional design than they do on actual agent behavior.
Experimental design¶
Traders¶
The market is designed to replicate experimental markets. Keep in mind that in the experimental markets we have humans, and the markets that we run here are purely machine traders. There are \(N_b\) buyers, and \(N_s\) sellers. Each type is determined at the start of the game, and traders cannot switch from one side of the market to the other.
Induced values¶
In the 1970’s Vernon Smith introduced the concept of induced value to simulate demand and supply in experimental markets. Buyers are endowed with the right to sell tokens in the market. They are each assigned a random value distributed uniformly across \(v = [0,maxValue]\). Once a buyer has purchased the good for a given price, p, they can turn it in for v, and get a profit of \(v-p\).
The market is symmetric on the sell side. Sellers must incur costs, c, when they sell their tokens. These costs are assumed to be distributed \(c=[0,maxCost]\). Sellers net profits from a sale are then \(p-c\).
These heterogeneous values create a downward sloping demand, and upward sloping supply curve in the market. Efficient trading would entail sorting the agents on their valuations. Then moving from highest to lowest valued buyer, and lowest to highest valued seller, implementing a trade, and assuming that surplus \(v-c\) is distributed to the traders. This is a centralized planner solution to who should be trading with whom. The imputed demand and supply curves also give a predicted price and quantity traded for the market by simply looking at their crossing point.
The following figure gives an example of that this would look like in a market. Values works there way down the demand curve, and costs go up the supply curve. Sorting a random draw for buyers and sellers gives a representative figure which except for the discreteness should be familiar to anyone from a principles of economics class. The figure quickly predicts the final price and quantity traded. Calculating the area to the left of the market clearing quantity would give the consumer/producer surplus. Traders on this side of the market are labeled inframarignal, while the traders on the other side would be extramarginal. In the textbook market, the latter do not trade. In experiments this may not always be the case.
The objective of this market is to see how close the completely decentralized version will get to the stylized theoretical version. This was the key objective with human subjects, and is the same with computer algorithms.
It is important to note two of the key simplifying assumptions in this market. First, there is no retrade of the goods. Once a token is bought or sold, it cannot return to the market. This is related to locking down the buyers and sellers. They do not get to change roles. A second key assumption is that the agents only trade single fixed units of the good. They do not decide on quantities for purchase and sale. This is set to one for all transactions. We are still interested in the aggregate quantities traded in the market, but that corresponds to the number of trades that occur.
Trading¶
The market replicates a simple form of a double auction with a restricted limit order book. In general a limit order book keeps track of offers to buy (bids) and sell (offers). Agents can post new bids and offers, or trade with any existing live order. Obviously, a potential buyer would take the lowest offer, and a potential seller would take the highest bid. In this market several simplifying assumptions will require us to maintain the best bid (highest), and best offer (lowest).
Traders are randomly selected to enter the market in each moment. Once a trader has made one trade (purchase or sale) they are removed from the market.
In what is called the constrained simulation each buyer (i) will generate a buy limit order (bid) with a price chosen uniformly in the range,
guaranteeing a profitable trade. The agent takes this bid to the market and takes the following action:
- If the bid is greater than the current best ask price, then the agent purchases the token at the best ask. The trade price is recorded, and both agents are pulled from the live trader pool.
- If the bid is greater than the current best bid, then it replaces that order in the book, and the agent’s id number is recorded. It now is live on the book, and standing ready to buy if a seller wants to trade.
- If the bid is less than the best bid then the order is forgotten and the trader returns to the pool.
A similar procedure is followed for sellers. They find a random offer
that again guarantees a profitable trade. The agent will go to the market and take the following actions:
- If the offer is less than the current best bid price, then the agent sells the token at the best bid. The trade price is recorded, and both agents are pulled from the live trader pool.
- If the offer is less than the current best offer, then it replaces that order in the book, and the agent’s id number is recorded. It now is live on the book, and standing ready to sell if a buyer wants to trade.
- If the offer is greater than the best offer then the order is forgotten and the trader returns to the pool.
When a trade occurs, the price is recorded, the two agents are removed from the live trading pool, and the limit order book is cleared.
Software: Python¶
The code is written with several simple objects sitting below a main program in the file labeled script.py. Buyer and seller are objects supporting the system, and the code in the module dotrade.py supports the trading process.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | # -*- coding: utf-8 -*-
# Trading with Zero Intelligence Agents Model without Marshallian Path
# Python version: David Ritzwoller, Blake LeBaron
# based on original matlab code by,
# Axel Szmulewiez, Blake LeBaron, Patrick Herb
# Brandeis University
# 04/14/2015
# 07/22/2016
# We implement a dynamic model of zero intelligence traders developed by
# Gode & Sunder (1993). We evaluate the role of the market as a natural
# allocator of resources in the economy. By having near Zero Intelligence
# agents who don't maximize profits or utility functions, we exclude the
# human factor in trade and isolate the roles of demand and supply.
# The market is structured as a double aucion order book. When a trade takes
# places, it reinitializes the order book. The price of the transaction is
# that of the bid/ask that is submitted to match the current best standing
# offer. Each trade is for one unit. There are 100 buyers and 100 sellers
# that submit offers for 8000 iterations. Each trader is allowed to trade
# only once. The program compares the simulation's performance with the
# theoretical economically efficient outcome.
# Sources:
# Allocative Efficiency of Markets with Zero-Intelligence
# Traders: Market as a Partial Substitute for Individual
# Rationality, Gode & Sunder (1993)
#
# On the Behavioral Foundations of the Law of Supply and Demand:
# Human Convergence and Robot Randomness, Brewer, Huang, Nelson &
# Plott (2002)
#
# Mark E. McBride, Department of Economics, Miami University, on
# the development of the model in NetLogo and particular
# contribution to this program in the design of order book
# mechanics.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from Buyer import Buyer
from Seller import Seller
from initializeBook import initializeBook
from doTrade import doTrade
# Get parameters from user
# Simulation runs with 100 buyers and 100 sellers (a market big enough to
# consider it perfectly competitive
numberTraders = 500
# refresh demands
# This option if set to true will draw new values/costs for all agents who
# have not traded. This is like a continuous refresh and this eliminates
# the Marshallian path (see )
refresh = False
# Get input for maximum buyer value and seller cost (shape the demand and
# supply curves). Make sure inputs are positive
maxValue = 0
while maxValue <= 0:
maxValue = float(input('Please enter the desired maximum buyer value(demand curve upper bound, > 10 suggested): '))
maxCost = 0
while maxCost <= 0:
maxCost = float(input('Please enter the desired maximum seller cost (supply curve upper bound, > 10 suggested): '))
# Run simulation with 50000 iteration
iterations = 50000
# Determine whether simulation will be constrained or unconstrained. Lock
# in while loop until valid input is given
constrained = -1
while (constrained != 0) & (constrained != 1):
constrained = int(input('Please enter ''1'' for constrained simulation , ''0'' for unconstrained: '))
# Determine whether simulation will have a price ceiling 5% above
# theoretical equilibrium price. Lock in while loop until valid input is
# given
ceiling = -1
# while (ceiling != 0) & (ceiling != 1):
# ceiling = int(input('Please enter ''1'' to include a price ceiling in the simulation, ''0'' otherwise: '))
# Create vector holding all buyers
buyers = []
for i in range(numberTraders):
buyers.append(Buyer(maxValue))
# Initialize all buyers to not traded state and give them a reservation
# price (random variable bounded above)
valueVec = maxValue*np.random.rand(numberTraders)
for i in range(numberTraders):
buyers[i].Value = valueVec[i]
buyers[i].Traded = 0
# Create vector holding all sellers
sellers = []
for i in range(numberTraders):
sellers.append(Seller(maxCost))
# Initialize all sellers to not traded state and give them a reservation
# cost (random variable bounded below)
costVec = maxCost*np.random.rand(numberTraders)
for i in range(numberTraders):
sellers[i].Cost = costVec[i]
sellers[i].Traded = 0
# Sort buyer and seller vectors to calculate equilibrium values and to
# later plot demand and supply curves
buyerValues = []
for i in range(numberTraders):
buyerValues.append(buyers[i].Value)
buyerValues.sort(reverse = True)
sellerCosts = []
for i in range(numberTraders):
sellerCosts.append(sellers[i].Cost)
sellerCosts.sort()
# Compute theoretical equilibrium and surplus
predictedPrice = 0
predictedQuantity = 0
maximumSurplus = 0
for i in range(numberTraders):
# If value of buyer is greater than cost of seller, there is a trade.
# Then, quantity increases by one, there are gains for trade (surplus)
# and the price is updated
if(buyerValues[i] - sellerCosts[i]) > 0:
predictedPrice = (buyerValues[i] + sellerCosts[i]) /2
predictedQuantity = predictedQuantity + 1
maximumSurplus = maximumSurplus + (buyerValues[i] - sellerCosts[i])
# Initialize the order book vector. Please see function description for the
# values held in each index
orderBookValues = initializeBook(maxCost)
# Initialize vector with transaction prices (update as iterations execute).
# Let the length of the vector be the maximum number of iterations, then
# discard leftover indexes initialized to zero for efficiency
transactionPrices = []
# Initial surplus is 0
surplus = 0
# Initial quantity traded is 0
quantity = 0
tradedValues = []
tradedCosts = []
for i in range(iterations):
# Stop the loop if all buyers and sellers have already traded. Note
# that if all buyers have traded, all sellers have traded, since each
# trader is allowed to trade only once
if sum(buyers.Traded for buyers in buyers) == numberTraders:
break
# Attempt a trade or a new bid/ask (report update if trade occurs).
# Pass vectors of buyers and sellers to manipulate, the order book
# values to update trade information, number of traders to give upper
# bound for random generation of index that determines chosen trader,
# and constraing choice along with predicted price and max value for
# trader to generate bid/offer
orderBookValues = doTrade(buyers, sellers, orderBookValues, numberTraders, predictedPrice, constrained, maxValue, maxCost)
# Record transaction price, update surplus and quantity, mark traders
# to record that they have traded, and reinitialize the order book
# if a trade occured
if orderBookValues[6] > 0:
transactionPrices.append(orderBookValues[6])
surplus = surplus + orderBookValues[7]
buyers[orderBookValues[1]].Traded = 1
sellers[orderBookValues[4]].Traded = 1
tradedValues.append(buyers[orderBookValues[1]].Value)
tradedCosts.append(sellers[orderBookValues[4]].Cost)
orderBookValues = initializeBook(maxCost)
quantity = quantity +1
# if refresh is True, then redraw values for all buyers and sellers
# this makes this as if at start with a complete refresh
if refresh:
for checkBuyer in buyers:
if(checkBuyer.Traded == 0):
checkBuyer.Value = valueVec[np.random.randint(numberTraders)]
for checkSeller in sellers:
if(checkSeller.Traded == 0):
checkSeller.Cost = costVec[np.random.randint(numberTraders)]
# Calculate simulation surplus as percentage of total possible surplus
# This is a prototype area for the refresh option
# This should probably be eliminated in production
# no great way to estimate theoretical surplus under refresh
if refresh:
tradedValnp = np.array(tradedValues)
tradedCostnp = np.array(tradedCosts)
tradedValnp = np.sort(tradedValnp)[::-1]
tradedCostnp.sort()
infraMarginal = (tradedValnp>tradedCostnp)
maximumSurplus = np.sum(tradedValnp[infraMarginal]-tradedCostnp[infraMarginal])
surplusPercentage = surplus / maximumSurplus * 100.
SimulationPrice = np.mean(transactionPrices[-50:])
# Generate rolling means and variances with Panda (needs version 0.18)
priceTS = pd.Series(transactionPrices,index=range(len(transactionPrices)))
priceRoll = priceTS.rolling(window=50,min_periods=10)
priceVar = priceRoll.var()
priceMean = priceRoll.mean()
################################
# REPORT RESULTS AND GRAPH #
################################
# Plot demand and supply curves and price pattern
# Plot Supply and Demand using sorted values and costs vectors initialized
# to calculate equlibrium values. Also plot price path
xPrice = [1*x for x in range(len(transactionPrices))]
x = [1*x for x in range(numberTraders)]
fig,ax = plt.subplots()
ax.plot(x, buyerValues, 'r')
ax.plot(x, sellerCosts, 'g')
ax.plot(xPrice, transactionPrices, 'k')
ax.plot(xPrice, priceMean.values, 'b')
# Adjust and label axes and title
ax.set_xlabel('Quantity')
ax.set_ylabel('Price')
ax.set_title('Market For Traded Asset')
ax.grid()
# ax
fig2, a2 = plt.subplots()
a2.plot(priceVar)
# a2.plot(priceMean)
a2.set_xlabel('Period')
a2.set_ylabel('Price variance')
a2.grid()
plt.show()
# Report statistics results
print('Simulation Results:')
print('The predicted quantity was '+str(predictedQuantity)+', and the predicted price was '+ str(predictedPrice)[0:5])
print('The simulation quantity is '+str(quantity)+' ,and the simulation price is '+ str(SimulationPrice)[0:5])
print('The simulation achieved '+str(surplusPercentage)[0:5]+' ,of the total available surplus')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # -*- coding: utf-8 -*-
import numpy as np
# Trading with Zero Intelligence Agents Model without Marshallian Path
# Axel Szmulewiez, Blake LeBaron, Patrick Herb
# Brandeis University
# 04/14/2015
def doTrade(buyers, sellers, bookValues, numberTraders, predictedPrice, constrained, maxValue, maxCost):
# This function operates the double auction order book. The function
# determines with 50% probability whether the next trader to submit an
# offer is a buyer or a seller. Then, it compares the new bid/ask and
# executes a trade if it satisfies the counterposing best standing offer,
# or it takes the place as best offer of its kind if it is better than the
# currently standing one (for example, if a new bid is submitted and it is
# higher than the best ask, a trade will occur, but if it's not higher than
# the best ask but higher than the best standing bid it will take its
# place. A similar process takes place if a seller submits an ask). The
# function returns an updated state of the order book to update simulation.
# Initialize return vector to current book values
updatedValues = bookValues
# Randomly choose between a buyer and a seller (belor 0.5 we select a
# buyer, otherwise we select a seller).
traderDeterminer = np.random.rand()
# Process as buyer
if traderDeterminer <0.5:
# Initialize a new buyer ID (at first 0)
newBuyer = -1
#Choose a random buyer that has yet not traded. Lock selection of a
# buyer in a while loop until it chooses a buyer that hasn't traded
while newBuyer == -1:
# Choose a random index in the buyers vector to select a buyer
randomIndex = np.random.randint(0, numberTraders)
if buyers[randomIndex].Traded == 0:
newBuyer = randomIndex
# Make buyer generate a random bid based on its reservation price and
# simulation constraint
newBid = buyers[newBuyer].formBidPrice(constrained, predictedPrice, maxValue)
# Do a trade if there is currently a standing ask that the bid can
# trade with. Check the logical variable and the value of the best
# standing ask
if (updatedValues[5] == 1) & (newBid > updatedValues[3]):
# Set the transaction price to the best ask value
updatedValues[6] = updatedValues[3]
# Record surplus added by the trade
updatedValues[7] = buyers[newBuyer].Value - sellers[updatedValues[4]].Cost
# Update ID of buyer
updatedValues[1] = newBuyer
# If the there is no trade, set the bid as best bid if it is higher
# than the currently standing best bid, even if it doesn't satisfy the
# ask or if there currently is no ask
else:
if newBid > updatedValues[0]:
# Set new bid as best bid, and update the ID of bidder
updatedValues[0]= newBid
updatedValues[1] = newBuyer
# Set logical variable for standing bid to true
updatedValues[2] = 1
# If new bid is lower than best bid, do nothing
# Process a seller
else:
# Initialize a new seller ID (at first 0)
newSeller = -1
# Choose a random seller that has yet not traded. Lock selection of a
# seller in a while loop until it chooses a seller that hasn't traded
while newSeller == -1:
# Choose a random index in the sellers vector to select a seller
randomIndex = np.random.randint(0, numberTraders)
if sellers[randomIndex].Traded == 0:
newSeller = randomIndex
# Make seller generate a random ask based on its reservation cost and
# simulation constraint
newAsk = sellers[newSeller].formAskPrice(constrained, predictedPrice, maxValue, maxCost)
# Do a trade if there is currently a standing bid that the ask can
# trade with. Check the logical variable and the value of the best
# standing bid
if (updatedValues[2] == 1) & (updatedValues[0] > newAsk):
# Set the transaction price to the best bid value
updatedValues[6] = updatedValues[0]
# Record surplus added by the trade
updatedValues[7] = buyers[updatedValues[1]].Value - sellers[newSeller].Cost
# Record ID of seller
updatedValues[4] = newSeller
# If the there is no trade, set the ask as best ask if it is lower
# than the currently standing best ask, even if it doesn't satisfy the
# bid or if there currently is no bid
else:
if newAsk < updatedValues[3]:
# Set new ask as best ask, and update the ID of bidder
updatedValues[3] = newAsk
updatedValues[4] = newSeller
# Set logical variable for standing ask to true
updatedValues[5] = 1
# If new ask is higher than best ask, do nothing
return updatedValues
|
Results¶
For all runs we set \(N_b=N_s=500\). The market is run for 50,000 iterations, or until all traders have traded. These parameters do not align with those from experiments in that they increase the size of the market. For computer traders we have the luxury of using many of them, and making them stay around for a long time. The basic results are robust to the changes, and are often clearer with the larger samples.
Constrained agents¶
In the first case we will run the code with agents constrained by their token values as described. Starting the script.py program will prompt you for two values which set the max and min range for the buyer’s tokens (demand) and seller’s tokens (supply).
For your first run try setting both max values to 25. The program also asked if you want the agents to be constrained, and for this answer 1 (yes).
Your will get a plot with the theoretical demand and supply curves along with the traded prices against the cumulative traded values as in Basic convergence. The figure also shows a rolling average of the traded prices. In most of your runs, you should see a pretty clear convergence to the equilibrium market price. There are obvious random fluctuations which generally are larger at first, but diminish as trades go by. This reduction in price variability is displayed in Rolling Variance. This displays a rolling variance of the transaction prices using a moving average over 50 periods. The price variability falls as it does in human experiments.
The program also reports a summary of the market performance. Here is an example of a run:
The predicted quantity was 255, and the predicted price was 12.43
The simulation quantity is 290 ,and the simulation price is 12.69
The simulation achieved 96.74 ,of the total available surplus
You can see both the theoretical predictions for price and volume are very close to the actual levels. Also, market efficiency is pretty high with a level over 95 percent. This is all very impressive when one considers that the traders are behaving completely randomly.
What exactly is the cause for this excellent market performance and replication of our economic predictions? (The latter we may have hoped to have come from strong assumptions about utility maximization, or other important assumptions about agent behavior.) One obvious possibility might be the easy symmetry of this problem. The supply and demand curves are exactly matched. What would happen if we make them slightly different. We do this by now typing in different parameters, 25 and 10 for the supply and demand maximum. An example plot is displayed in Asymmetric Curves.
The figure again shows a strong convergence to the expected price, and a steady reduction in the variance as the market continues. The asymmetry in the supply and demand curves is also clear. Predictions and efficiency are again reported in the program by:
The predicted quantity was 354, and the predicted price was 7.29
The simulation quantity is 394 ,and the simulation price is 6.71
The simulation achieved 97.19 ,of the total available surplus
Again we have a good theoretical forecasts from the classic economic model, and market efficiency well over 90 percent.
Unconstrained agents¶
In the previous examples agents were not completely random in their behavior. They were constrained to eventually make money in the market. In other words, their budget constraints were binding. Buyers did not purchase tokens that they could not afford, and sellers did not sell tokens for less than they cost to acquire. These are simply basic economic common sense, but how much do they matter in these markets. In this section we will release these constraints.
Figure Unconstrained repeats the simulation for the case where the constraints have been removed and agents simply bid randomly. Buyers in the range (0,maxValue), and sellers in the range (0,maxCost). The demand and supply values are skewed to (25,10) to further emphasize the results which are displayed in Unconstrained and Rolling variance.
The figure displays what one might expect from completely random behavior. There is no indication of any convergence to the equilibrium price, and prices continue to wildly fluctuate through the entire run. The price variance shows no trend toward converging to zero. The market performance and predictive statistics show a similar picture as in:
The predicted quantity was 357, and the predicted price was 7.16
The simulation quantity is 500 ,and the simulation price is 8.80
The simulation achieved 83.82, of the total available surplus
The quantity and price forecasts from economic theory are way off target, and trading efficiency is about 80 percent.
Summary¶
At this point we have the intriguing result that zero intelligence traders, constrained by standard budget constraints, generate a market which appears relatively orderly and possibly intelligent. The institutional structure seems to be giving us a lot here. The next section explores some of the robustness relative the market structure.
Continuous order inflow¶
Several authors have critiqued the ZI result. [BHNP02] detail the existence of a Marshallian path as being a key element of the ZI trader convergence. They describe how random trading proceeds in the market. As traders are eliminated from the market this leads often to the elimination of the most extreme values and costs of traders. The new distribution of traders is now distributed more tightly about the equilibrium price. The random mechanism alone leads to a path toward equilibrium.
There are several ways to eliminate this problem, and [BHNP02] use an experimental framework. In the computational world this can be done more easily. The idea is to refresh the market with the same starting distributions of values and costs after each trade is made. Setting the flag refresh to True will accomplish this in the code. After a trade takes place, the order book is cleared and all agent valuations are redrawn from the initial distribution. Trading then proceeds as usual. Bids and offers are constrained as they were in all the early runs of the model.
Results for the asymmetric valuations (25,10) are displayed in figure Continuous inflow. It is clear that there is no convergence to the equilibrium price, and the system stays well above the theoretical price. The price variance also shows no convergence as well. in Price variance.
The market quantitatively shows these results and the lack of prediction of the theoretical values for prices and trading volume. (Calculating theoretical consumer surplus in the continuously refreshed case not an easy calculation. See [BHNP02] for discussions.):
The predicted quantity was 370, and the predicted price was 7.36
The simulation quantity is 500 ,and the simulation price is 10.61
Summary¶
Continuously refreshed demands opens interesting questions about the ZI convergence result. If markets are best represented by a fixed set of agents who arrive at the market, and depart once their trades are completed, then the Gode and Sunder version of ZI trader convergence seems to be a relatively robust picture of markets. However, if one views markets as being continuously fed with new traders arriving with heterogeneous valuations, then ZI convergence may not be a good representation.
In real markets it seems like both these situations are possible.
Regardless of how we think about markets, the ZI results of [GS93] remain an important part of agent-based finance, and agent-based modeling in general. In any modeling situation it is always a good idea to see which features might be generated by near random behavior. Institutional mechanisms along with some endogenous self-organization of agents may generate surprising empirical structure.