-
Notifications
You must be signed in to change notification settings - Fork 0
/
market.py
116 lines (95 loc) · 4.49 KB
/
market.py
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
# -*- coding: utf-8 -*-
"""
/!\ Convergence issue when finding best-responses for bounded random variables (e.g. uniform)
[*] Choose starting point (first guess) wisely
- So far 0.001 works for the uniform([0,1]), but may be inappropriate another one
[*] No issue for unbounded distributions
"""
from . import Firm, FirmWithoutOutsideOption
from scipy.stats import uniform
TOLERANCE = 0.001
MAX_ITER = 1000
class Market:
def __init__(self,
products_per_firms=[2,2],
marginal_costs=[0,0],
outside_option=True,
distributions=[uniform(),uniform()],
tolerance=TOLERANCE,
max_iter=MAX_ITER,
starting_price=0.2
):
# Check right input
if len(products_per_firms) != len(marginal_costs):
msg = 'products_per_firms and marginal_cost: different lengths.'
raise ValueError(msg)
if len(products_per_firms) < 2:
# Is it so much of an issue? Yes, when you consider you have to deal with lists!
msg = 'There are less than two firms.'
raise ValueError(msg)
# Initialize variables
self.number_firms = len(products_per_firms)
self.products_per_firms = products_per_firms
self.marginal_costs = marginal_costs
self.outside_option = outside_option
self.distributions = distributions
if outside_option == True:
self.firms = [Firm(products_per_firms[i],
marginal_costs[i],
distributions[i])
for i in range(self.number_firms)]
else:
self.firms = [FirmWithoutOutsideOption(products_per_firms[i],
marginal_costs[i],
distributions[i])
for i in range(self.number_firms)]
# Convergence parameters
self.tolerance = tolerance
self.max_iter = max_iter
self.starting_price = starting_price
def equilibrium_prices(self):
"""
Finds the equilibrium prices through iteration of firms' best responses.
"""
count = 0
error = 100000
prices = [self.starting_price] * len(self.firms)
while error > self.tolerance and count < self.max_iter:
new_prices = []
for n in range(len(self.firms)):
competitors = self.firms[:n] + self.firms[n+1:]
competitors_prices = prices[:n] + prices[n+1:]
new_prices += [self.firms[n].best_response(competitors, competitors_prices)]
error = max([abs(prices[n] - new_prices[n]) for n in range(len(self.firms))])[0]
print('Finding prices ... {}'.format(new_prices))
print('Error: {}'.format(error))
count += 1
prices = new_prices
return new_prices
def equilibrium_demands(self):
demands = []
prices = self.equilibrium_prices()
for n in range(len(self.firms)):
price = prices[n]
competitors = self.firms[:n] + self.firms[n+1:]
competitors_prices = prices[:n] + prices[n+1:]
demands += [self.firms[n].demand(price, competitors, competitors_prices)]
return demands
def equilibrium_profits(self):
prices = self.equilibrium_prices()
marginal_costs = self.marginal_costs
demands = self.equilibrium_demands()
return [(prices[n] - marginal_costs[n]) * demands[n] for n in range(len(self.firms))]
class MarketWithoutOutsideOption(Market):
def equilibrium_demands(self):
demands = []
prices = self.equilibrium_prices()
for n in range(len(self.firms)):
price = prices[n]
competitors = self.firms[:n] + self.firms[n+1:]
competitors_prices = prices[:n] + prices[n+1:]
if self.outside_option == True:
demands += [self.firms[n].demand(price, competitors, competitors_prices)]
else:
demands += [self.firms[n].demand_no_outside_option(price, competitors, competitors_prices)]
return demands