I was reading Nate Silver’s The Signal and the Noise today and I ran across his idea of Bayesland, a place where people walk around with sandwich boards listing things on which they would place a bet. If they meet a person whose odds on an event differs substantially from their own odds on that event, then the two will make a bet.
I thought that it would be neat to simulate this idea and see what would happen. In my example, we have three agents that bet on the probability of a coin coming up heads. The coin is simulated through a Bernoulli process, and the true probability or heads is 60%.
I created an agent class that would be initialized with a key, a hypothesis regarding the probability of heads, a bankroll, and some idea of the past events. When two agents meet, they compare keys. If they have the same keys, and a difference of opinion regarding the probability of a heads, then they make a bet. Each participant is willing to bet 5% of their bankroll, and when they meet and bet, they just bet the average of whatever they’re willing to wager. (That’s not a very important detail.)
Another arbitrary implementation detail was the fact that each agent has a slightly different recollection of past events. This is controlled in a probabilistic manner. I thought that agents with perfect knowledge would be less interesting. This could also be interpreted as a form of irrationality. Anyway, what I was hoping to see was the bettors converging around the actual value of the probability of heads, which I set at 60%. This sort of happened most of the time.
Code
import scipy.stats import numpy as np import random
Define an Agent class with a number of randomly assigned parameters, and a means of learning about the environment.
class Agent: def __init__( self ): # two agents will interact if they have the same key self.key = random.randint(1,5) # select a random probability of heads self.hypothesis = scipy.stats.uniform(0,1).rvs() # start with a hundred dolalrs self.bank = 100 # set the bet at 5% of the bankroll self.bet = self.bank * 0.05 # initialize the "memory" self.memory = [ scipy.stats.uniform(0,1).rvs() ] # set some recollection accuracy self.accuracy = scipy.stats.uniform(0,0.1).rvs() def inform( self, outcome ): # if u is less than the recollection accuracy # then the agent "forgets" the outcome of the flip u = scipy.stats.uniform(0,1).rvs() if u < self.accuracy: self.memory.append( outcome ) # take the mean of the observations observations = np.mean( self.memory ) # update the hypothesis based on the observations self.hypothesis = np.mean( [ self.hypothesis, observations ] ) def update( self ): # reset the key self.key = random.randint(1,5) # reset the recollection accuracy self.accuracy = scipy.stats.uniform(0,0.1).rvs() # update the bet self.bet = self.bank * 0.05
A loop to pit the agents against each other in a random fashion according to the “key” each agent holds, which is changed at the end of each iteration.
# create a list of three agents a = [ Agent() for i in range(3) ] # create three clunky lists A, B, C = list(), list(), list() # go for 500 turns for i in range( 500 ): # flip a coin with a 60% chance of landing heads up flip = scipy.stats.bernoulli(0.6).rvs() # for each agent.. for j in range( len( a ) ): # for each remaining agent.. for k in range( j+1, len(a) ): # if they meet by chance (have the same key) if a[j].key == a[k].key: # and if their opinions differ greatly enough.. h0, h1 = a[j].hypothesis, a[k].hypothesis if np.abs( h0 - h1 ) > 0.1: # the greater hypothesis bets heads # the lesser hypothesis bets tails if h0 > h1: head = a[j] tail = a[k] bet = np.mean( [ a[j].bet, a[k].bet ] ) elif h1 > h0: head = a[k] tail = a[j] bet = np.mean( [ a[j].bet, a[k].bet ] ) # if the flip was a heads.. if flip == 1: head.bank += bet tail.bank -= bet elif flip == 0: head.bank -= bet tail.bank += bet # inform the agents of the flip # change their keys and recollection probability for agent in a: agent.inform( flip ) agent.update() # clunkily record the results A.append( [ a[0].hypothesis, a[0].bank ] ) B.append( [ a[1].hypothesis, a[1].bank ] ) C.append( [ a[2].hypothesis, a[2].bank ] )
Now, plot the results!
# convert to NumPy arrays A = np.array( A ).T B = np.array( B ).T C = np.array( C ).T # begin plotting fig, axs = subplots(2,1) axs[0].set_ylabel("Prediction") axs[0].plot( A[0] ) axs[0].plot( B[0] ) axs[0].plot( C[0] ) axs[0].set_ylim(0,1) axs[1].set_ylabel('Bankroll') axs[1].plot( A[1] ) axs[1].plot( B[1] ) axs[1].plot( C[1] ) savefig("market_bets.png",dpi=200,bbox_inches='tight')