abce package¶
Submodules¶
abce.agent module¶
The abce.Agent
class is the basic class for creating your agents.
It automatically handles the possession of goods of an agent. In order to
produce/transforme goods you also need to subclass the abce.Firm
or
to create a consumer the abce.Household
.
For detailed documentation on:
Trading, see Trade
Logging and data creation, see Database.
Messaging between agents, see Messaging.
-
class
abce.agent.
Agent
(id, agent_parameters, simulation_parameters, group, trade_logging, database, check_unchecked_msgs, expiring, perishable, resource_endowment, start_round=None)[source]¶ Bases:
abce.database.Database
,abce.trade.Trade
,abce.messaging.Messaging
,abce.goods.Goods
Every agent has to inherit this class. It connects the agent to the simulation and to other agent. The
abce.Trade
,abce.Database
andabce.Messaging
classes are included. An agent can also inheriting fromabce.Firm
,abce.FirmMultiTechnologies
orabce.Household
classes.Every method can return parameters to the simulation.
For example:
class Household(abce.Agent, abce.Household): def init(self, simulation_parameters, agent_parameters): self.num_firms = simulation_parameters['num_firms'] self.type = agent_parameters['type'] ... def selling(self): for i in range(self.num_firms): self.sell('firm', i, 'good', quantity=1, price=1) ... def return_quantity_of_good(self): return['good'] ... simulation = Simulation() households = Simulation.build_agents(household, 'household', parameters={...}, agent_parameters=[{'type': 'a'}, {'type': 'b'}]) for r in range(10): simulation.advance_round(r) households.selling() print(households.return_quantity_of_good())
-
group
= None¶ self.group returns the agents group or type READ ONLY!
-
id
= None¶ self.id returns the agents id READ ONLY
-
init
()[source]¶ This method is called when the agents are build. It can be overwritten by the user, to initialize the agents. Parameters are the parameters given to
abce.Simulation.build_agents()
.Example:
class Student(abce.Agent): def init(self, rounds, age, lazy, school_size): self.rounds = rounds self.age = age self.lazy = lazy self.school_size = school_size def say(self): print('I am', self.age ' years old and go to a school that is ', self.school_size') def main(): sim = Simulation() students = sim.build_agents(Student, 'student', agent_parameters=[{'age': 12, lazy: True}, {'age': 12, lazy: True}, {'age': 13, lazy: False}, {'age': 14, lazy: True}], rounds=50, school_size=990)
-
name
= None¶ self.name returns the agents name, which is the group name and the id
-
round
= None¶ self.round is depreciated
-
time
= None¶ self.time, contains the time set with simulation.advance_round(time) you can set time to anything you want an integer or (12, 30, 21, 09, 1979) or ‘monday’
-
abce.compile module¶
abce.credit module¶
-
class
abce.credit.
Credit
[source]¶ Bases:
object
This class implements a bank credit, without a due date
-
accept_contract
(contract, quantity=None)[source]¶ Accepts the contract. The contract is completely accepted, when the quantity is not given. Or partially when quantity is set.
Args:
- contract:
- the contract in question, received with get_contract_requests or get_contract_offers
- quantity (optional):
- the quantity that is accepted. Defaults to all.
-
get_contract_offers
(good, descending=False)[source]¶ Returns all contract offers and removes them. The contract are ordered by price (ascending), when tied they are randomized.
- Args:
- good:
- good that underlies the contract
- descending(bool,default=False):
- False for descending True for ascending by price
- Returns:
- list of contract offers ordered by price
-
request_credit
(receiver_group, receiver_id, quantity, interest)[source]¶ This method offers a contract to provide a good or service to the receiver. For a given time at a given price.
Args:
- receiver_group:
- group to receive the good
- receiver_id:
- group to receive the good
- quantity:
- original amount to be borrowed
- interest:
- period interest
-
abce.database module¶
The abceagent.Agent
class is the basic class for creating your agent.
It automatically handles the
possession of goods of an agent. In order to produce/transforme goods you
need to also subclass the abceagent.Firm
[1]_ or to create a
consumer the abceagent.Household
.
For detailed documentation on:
- Trading:
- see
abceagent.Trade
- Logging and data creation:
- see
abceagent.Database
and simulation_results - Messaging between agents:
- see
abceagent.Messaging
.
-
exception
abce.
NotEnoughGoods
(_agent_name, good, amount_missing)[source]¶ Methods raise this exception when the agent has less goods than needed
These functions (self.produce, self.offer, self.sell, self.buy) should be encapsulated by a try except block:
try: self.produce(...) except NotEnoughGoods: alternative_statements()
[1] | or abceagent.FirmMultiTechnologies for complex technologies. |
-
class
abce.database.
Database
(id, agent_parameters, simulation_parameters, group, trade_logging, database, check_unchecked_msgs, expiring, perishable, resource_endowment, start_round=None)[source]¶ Bases:
object
The database class
-
log
(action_name, data_to_log)[source]¶ With log you can write the models data. Log can save variable states and and the working of individual functions such as production, consumption, give, but not trade(as its handled automatically). Sending a dictionary instead of several using several log statements with a single variable is faster.
- Args:
- ‘name’(string):
- the name of the current action/method the agent executes
- data_to_log:
- a variable or a dictionary with data to log in the the database
Example:
self.log('profit', profit) self.log('employment_and_rent', {'employment': self['LAB'], 'rent': self['CAP'], 'composite': self.composite}) self.log(self.produce_use_everything())
- See also:
log_nested()
:- handles nested dictianaries
log_change()
:- loges the change from last round
observe_begin()
:
-
log_change
(action_name, data_to_log)[source]¶ This command logs the change in the variable from the round before. Important, use only once with the same action_name.
- Args:
- ‘name’(string):
- the name of the current action/method the agent executes
- data_to_log:
- a dictianary with data for the database
Examples:
self.log_change('profit', {'money': self['money']]}) self.log_change('inputs', {'money': self.possessions(['money', 'gold', 'CAP', 'LAB')]})
-
observe_begin
(action_name, data_to_observe)[source]¶ observe_begin and observe_end, observe the change of a variable. observe_begin(…), takes a list of variables to be observed. observe_end(…) writes the change in this variables into the log file
you can use nested observe_begin / observe_end combinations
- Args:
- ‘name’(string):
- the name of the current action/method the agent executes
- data_to_log:
- a dictianary with data for the database
Example:
self.log('production', {'composite': self.composite, self.sector: self.final_product[self.sector]}) ... different method ... self.log('employment_and_rent', { 'employment': self['LAB'], 'rent': self['CAP']})
-
observe_end
(action_name, data_to_observe)[source]¶ This command puts in a database called log, whatever values you want values need to be delivered as a dictionary:
- Args:
- ‘name’(string):
- the name of the current action/method the agent executes
- data_to_log:
- a dictianary with data for the database
Example:
self.log('production', {'composite': self.composite, self.sector: self.final_product[self.sector]}) ... different method ... self.log('employment_and_rent', { 'employment': self['LAB'], 'rent':self['CAP']})
-
abce.db module¶
-
class
abce.db.
Database
(directory, in_sok, trade_log)[source]¶ Bases:
threading.Thread
Separate thread that receives data from in_sok and saves it into a database
-
run
()[source]¶ Method representing the thread’s activity.
You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.
-
abce.expiringgood module¶
abce.financial module¶
abce.group module¶
-
class
abce.group.
Group
(sim, processorgroup, group_names, agent_classes, ids=None, agent_arguments=None)[source]¶ Bases:
object
A group of agents. Groups of agents inherit the actions of the agents class they are created by. When a group is called with an agent action all agents execute this actions simultaneously. e.G.
banks.buy_stocks()
, then all banks buy stocks simultaneously.agents groups are created like this:
sim = Simulation() Agents = sim.build_agents(AgentClass, 'group_name', number=100, param1=param1, param2=param2) Agents = sim.build_agents(AgentClass, 'group_name', param1=param1, param2=param2, agent_parameters=[dict(ap=ap1_agentA, ap=ap2_agentA), dict(ap=ap1_agentB, ap=ap2_agentB), dict(ap=ap1_agentC, ap=ap2_agentC)])
Agent groups can be combined using the + sign:
financial_institutions = banks + hedgefunds ... financial_institutions.buy_stocks()
or:
(banks + hedgefunds).buy_stocks()
Simultaneous execution means that all agents act on the same information set and influence each other only after this action.
individual agents in a group are addressable, you can also get subgroups (only from non combined groups):
banks[5].buy_stocks()
(banks[6,4] + hedgefunds[7,9]).buy_stocks()
agents actions can also be combined:
buying_stuff = banks.buy_stocks & hedgefunds.buy_feraries buy_stocks()
or:
(banks.buy_stocks & hedgefunds.buy_feraries)()
-
agg_log
(variables=[], goods=[], func={}, len=[])[source]¶ agg_log(.) writes a aggregate data of variables and goods of a group of agents into the database, so that it is displayed in the gui.
- Args:
- goods (list, optional):
- a list of all goods you want to track as ‘strings’
- variables (list, optional):
- a list of all variables you want to track as ‘strings’
- func (dict, optional):
- accepts lambda functions that execute functions. e.G.
func = lambda self: self.old_money - self.new_money
- len (list, optional):
- records the length of the list or dictionary with that name.
Example in start.py:
for round in simulation.next_round(): firms.produce_and_sell() firms.agg_log(goods=['money', 'input'], variables=['production_target', 'gross_revenue']) households.buying()
-
create_agents
(number=1, agent_parameters=None, **common_parameters)[source]¶ Create new agents to this group. Works only for non-combined groups
- Args:
- agent_parameters:
- List of dictionaries of agent_parameters
- number:
- number of agents to create if agent_parameters is not set
- any keyword parameter:
- parameters directly passed to
agent.init
methood
- Returns:
- The id of the new agent
-
delete_agents
(ids)[source]¶ Remove an agents from a group, by specifying their id.
- Args:
- ids:
- list of ids of the agent
Example:
students.delete_agents([1, 5, 15])
-
panel_log
(variables=[], goods=[], func={}, len=[])[source]¶ panel_log(.) writes a panel of variables and goods of a group of agents into the database, so that it is displayed in the gui.
- Args:
- goods (list, optional):
- a list of all goods you want to track as ‘strings’
- variables (list, optional):
- a list of all variables you want to track as ‘strings’
- func (dict, optional):
- accepts lambda functions that execute functions. e.G.
func = lambda self: self.old_money - self.new_money
- len (list, optional):
- records the length of the list or dictionary with that name.
Example in start.py:
for round in simulation.next_round(): firms.produce_and_sell() firms.panel_log(goods=['money', 'input'], variables=['production_target', 'gross_revenue']) households.buying()
-
abce.inventory module¶
-
class
abce.inventory.
Inventory
(name)[source]¶ Bases:
object
-
create
(good, quantity)[source]¶ creates quantity of the good out of nothing
Use with care. As long as you use it only for labor and natural resources your model is macro-economically complete.
- Args:
- ‘good’: is the name of the good quantity: number
-
create_timestructured
(good, quantity)[source]¶ creates quantity of the time structured good out of nothing. For example:
self.creat_timestructured('capital', [10,20,30])
Creates capital. 10 units are 2 years old 20 units are 1 year old and 30 units are new.
It can also be used with a quantity instead of an array. In this case the amount is equally split on the years.:
self.creat_timestructured('capital', 60)
In this case 20 units are 2 years old 20 units are 1 year old and 20 units are new.
- Args:
- ‘good’:
- is the name of the good
- quantity:
- an arry or number
-
destroy
(good, quantity=None)[source]¶ destroys quantity of the good. If quantity is omitted destroys all
Use with care.
Args:
'good': is the name of the good quantity (optional): number
Raises:
NotEnoughGoods: when goods are insufficient
-
not_reserved
(good)[source]¶ returns how much of good an agent possesses.
- Returns:
- A number.
possession does not return a dictionary for self.log(…), you can use self.possessions([…]) (plural) with self.log.
Example:
if self['money'] < 1: self.financial_crisis = True if not(is_positive(self['money']): self.bankruptcy = True
-
reserved
(good)[source]¶ returns how much of a good an agent has currently reseed to sell or buy.
- Returns:
- A number.
possession does not return a dictionary for self.log(…), you can use self.possessions([…]) (plural) with self.log.
Example:
if self['money'] < 1: self.financial_crisis = True if not(is_positive(self['money']): self.bankruptcy = True
-
abce.messaging module¶
This is the agent’s facility to send and receive messages. Messages can
either be sent to an individual with messaging.Messaging.message()
or to a group with
messaging.Messaging.message_to_group()
. The receiving agent can either get all messages
with messaging.Messaging.get_messages_all()
or messages with a specific topic with
messaging.Messaging.get_messages()
.
-
class
abce.messaging.
Message
(sender, receiver, topic, content)[source]¶ Bases:
object
-
content
¶
-
receiver
¶
-
sender
¶
-
topic
¶
-
-
class
abce.messaging.
Messaging
(id, agent_parameters, simulation_parameters, group, trade_logging, database, check_unchecked_msgs, expiring, perishable, resource_endowment, start_round=None)[source]¶ Bases:
object
-
get_messages
(topic='m')[source]¶ self.messages() returns all new messages send with
message()
(topic=’m’). The order is randomized. self.messages(topic) returns all messages with a topic.A message is a string with the message. You can also retrieve the sender by message.sender_group and message.sender_id and view the topic with ‘message.topic’. (see example)
If you are sending a float or an integer you need to access the message content with message.content instead of only message.
! if you want to recieve a float or an int, you must msg.content
- Returns a message object:
- msg.content:
- returns the message content string, int, float, …
- msg:
- returns also the message content, but only as a string
- sender_group:
- returns the group name of the sender
- sender_id:
- returns the id of the sender
- topic:
- returns the topic
Example:
... agent_01 ... self.messages('firm_01', 'potential_buyers', 'hello message') ... firm_01 - one subround later ... potential_buyers = get_messages('potential_buyers') for msg in potential_buyers: print('message: ', msg) print('message: ', msg.content) print('group name: ', msg.sender_group) print('sender id: ', msg.sender_id) print('topic: ', msg.topic)
-
get_messages_all
()[source]¶ returns all messages irregardless of the topic, in a dictionary by topic
A message is a string with the message. You can also retrieve the sender by message.sender_group and message.sender_id and view the topic with ‘message.topic’. (see example)
If you are sending a float or an integer you need to access the message content with message.content instead of only message.
-
send
(receiver, topic, content)[source]¶ sends a message to agent. Agents receive it at the beginning of next round with
get_messages()
orget_messages_all()
.Args:
receiver: The name of the receiving agent a tuple (group, id). e.G. ('firm', 15) topic: string, with which this message can be received content: string, dictionary or class, that is send.
Example:
... household_01 ... self.message('firm', 01, 'quote_sell', {'good':'BRD', 'quantity': 5}) ... firm_01 - one subround later ... requests = self.get_messages('quote_sell') for req in requests: self.sell(req.sender, req.good, reg.quantity, self.price[req.good])
Example2:
self.message('firm', 01, 'm', "hello my message")
-
abce.multicurrencytrade module¶
abce.notenoughgoods module¶
This file defines the tools.NotEnoughGoods
-
exception
abce.notenoughgoods.
NotEnoughGoods
(_agent_name, good, amount_missing)[source]¶ Bases:
Exception
Methods raise this exception when the agent has less goods than needed
These functions (self.produce, self.offer, self.sell, self.buy) should be encapsulated by a try except block:
try: self.produce(...) except NotEnoughGoods: alternative_statements()
abce.online_variance module¶
abce.online_variance module¶
abce.postbox module¶
abce.postprocess module¶
abce.processorgroup module¶
abce.quote module¶
-
class
abce.quote.
Quotation
(sender_group, sender_id, receiver_group, receiver_id, good, quantity, price, buysell, id)[source]¶ Bases:
object
-
buysell
¶
-
good
¶
-
id
¶
-
price
¶
-
quantity
¶
-
receiver_group
¶
-
receiver_id
¶
-
sender_group
¶
-
sender_id
¶
-
-
class
abce.quote.
Quote
[source]¶ Bases:
object
Quotes as opposed to trades are uncommitted offers. They can be made even if they agent can not fullfill them. With
accept_quote()
andaccept_quote_partial()
, the receiver of a quote can transform them into a trade.-
accept_quote
(quote)[source]¶ makes a commited buy or sell out of the counterparties quote. For example, if you receive a buy quote you can accept it and a sell offer is send to the offering party.
- Args::
- quote: buy or sell quote that is accepted
-
accept_quote_partial
(quote, quantity)[source]¶ makes a commited buy or sell out of the counterparties quote
- Args::
- quote: buy or sell quote that is accepted quantity: the quantity that is offered/requested it should be less than propsed in the quote, but this is not enforced.
-
get_quotes
(good, descending=False)[source]¶ self.get_quotes() returns all new quotes and removes them. The order is randomized.
- Args:
- good:
- the good which should be retrieved
- descending(bool,default=False):
- False for descending True for ascending by price
- Returns:
- list of quotes ordered by price
Example:
quotes = self.get_quotes()
-
get_quotes_all
(descending=False)[source]¶ self.get_quotes_all() returns a dictionary with all now new quotes ordered by the good type and removes them. The order is randomized.
- Args:
- descending(bool,default=False):
- False for descending True for ascending by price
- Returns:
- dictionary of list of quotes ordered by price. The dictionary itself is ordered by price.
Example:
quotes = self.get_quotes()
-
quote_buy
(receiver, good=None, quantity=None, price=None)[source]¶ quotes a price to buy quantity of ‘good’ a receiver. Use None, if you do not want to specify a value.
price (money) per unit offers a deal without checking or committing resources
- Args:
- receiver_group:
- agent group name of the agent
- receiver_id:
- the agent’s id number
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to buy at this price
- price:
- price per unit
-
quote_sell
(receiver, good=None, quantity=None, price=None)[source]¶ quotes a price to sell quantity of ‘good’ to a receiver. Use None, if you do not want to specify a value.
price (money) per unit offers a deal without checking or committing resources
- Args:
- receiver_group:
- agent group name of the agent
- receiver_id:
- the agent’s id number
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to sell at this price
- price:
- price per unit
-
abce.show module¶
python -m abce.show
shows the simulation results in ./result/*
abce.trade module¶
The abceagent.Agent
class is the basic class for creating your agent. It
automatically handles the possession of goods of an agent. In order to produce/transform
goods you need to also subclass the abceagent.Firm
[1]_ or to create a consumer
the abceagent.Household
.
For detailed documentation on:
- Trading:
- see
abceagent.Trade
- Logging and data creation:
- see
abceagent.Database
and simulation_results - Messaging between agents:
- see
abceagent.Messaging
.
[1] | or abceagent.FirmMultiTechnologies for simulations with complex technologies. |
-
class
abce.trade.
Offer
(sender, receiver, good, quantity, price, currency, sell, id, made)[source]¶ Bases:
object
-
currency
¶
-
final_quantity
¶
-
good
¶
-
id
¶
-
made
¶
-
price
¶
-
quantity
¶
-
receiver
¶
-
sell
¶
-
sender
¶
-
status
¶
-
status_round
¶
-
-
class
abce.trade.
Trade
(id, agent_parameters, simulation_parameters, group, trade_logging, database, check_unchecked_msgs, expiring, perishable, resource_endowment, start_round=None)[source]¶ Bases:
object
Agents can trade with each other. The clearing of the trade is taken care of fully by ABCE. Selling a good works in the following way:
An agent sends an offer.
sell()
ABCE does not allow you to sell the same good twice; self.free(good) shows how much good is not reserved yet
Next subround: An agent receives the offer
get_offers()
, and canaccept()
,reject()
or partially accept it.accept()
The good is credited and the price is deducted from the agent’s possessions.
Next subround:
- in case of acceptance the money is automatically credited.
- in case of partial acceptance the money is credited and part of the reserved good is unblocked.
- in case of rejection the good is unblocked.
Analogously for buying:
buy()
Example:
# Agent 1 def sales(self): self.remember_trade = self.sell('Household', 0, 'cookies', quantity=5, price=self.price) # Agent 2 def receive_sale(self): oo = self.get_offers('cookies') for offer in oo: if offer.price < 0.3: try: self.accept(offer) except NotEnoughGoods: self.accept(offer, self['money'] / offer.price) else: self.reject(offer) # Agent 1, subround 3 def learning(self): offer = self.info(self.remember_trade) if offer.status == 'reject': self.price *= .9 elif offer.status = 'accepted': self.price *= offer.final_quantity / offer.quantity
Example:
# Agent 1 def sales(self): self.remember_trade = self.sell('Household', 0, 'cookies', quantity=5, price=self.price, currency='dollars') # Agent 2 def receive_sale(self): oo = self.get_offers('cookies') for offer in oo: if ((offer.currency == 'dollars' and offer.price < 0.3 * exchange_rate) or (offer.currency == 'euros' and dollars'offer.price < 0.3)): try: self.accept(offer) except NotEnoughGoods: self.accept(offer, self['money'] / offer.price) else: self.reject(offer)
If we did not implement a barter class, but one can use this class as a barter class,
-
accept
(offer, quantity=-999, epsilon=1e-11)[source]¶ The buy or sell offer is accepted and cleared. If no quantity is given the offer is fully accepted; If a quantity is given the offer is partial accepted.
Args:
- offer:
- the offer the other party made
- quantity:
- quantity to accept. If not given all is accepted
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
- Return:
- Returns a dictionary with the good’s quantity and the amount paid.
-
buy
(receiver, good, quantity, price, currency='money', epsilon=1e-11)[source]¶ Sends a offer to buy a particular good to somebody. The money promised is reserved. (self.free(currency), shows the not yet reserved goods)
- Args:
- receiver:
- The name of the receiving agent a tuple (group, id). e.G. (‘firm’, 15)
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to buy at this price
- price:
- price per unit
- currency:
- is the currency of this transaction (defaults to ‘money’)
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
-
get_offers
(good, sorted=True, descending=False, shuffled=True)[source]¶ returns all offers of the ‘good’ ordered by price.
Offers that are not accepted in the same subround (def block) are automatically rejected. However you can also manually reject.
peek_offers can be used to look at the offers without them being rejected automatically
- Args:
- good:
- the good which should be retrieved
- sorted(bool, default=True):
- Whether offers are sorted by price. Faster if False.
- descending(bool, default=False):
- False for descending True for ascending by price
- shuffled(bool, default=True):
- whether the order of messages is randomized or correlated with the ID of the agent. Setting this to False speeds up the simulation considerably, but introduces a bias.
- Returns:
- A list of
abce.trade.Offer
ordered by price.
Example:
offers = get_offers('books') for offer in offers: if offer.price < 50: self.accept(offer) elif offer.price < 100: self.accept(offer, 1) else: self.reject(offer) # optional
-
get_offers_all
(descending=False, sorted=True)[source]¶ returns all offers in a dictionary, with goods as key. The in each goods-category the goods are ordered by price. The order can be reversed by setting descending=True
Offers that are not accepted in the same subround (def block) are automatically rejected. However you can also manually reject.
Args:
- descending(optional):
- is a bool. False for descending True for ascending by price
- sorted(default=True):
- Whether offers are sorted by price. Faster if False.
Returns:
a dictionary with good types as keys and list ofabce.trade.Offer
as valuesExample:
oo = get_offers_all(descending=False) for good_category in oo: print('The cheapest good of category' + good_category + ' is ' + good_category[0]) for offer in oo[good_category]: if offer.price < 0.5: self.accept(offer) for offer in oo.beer: print(offer.price, offer.sender)
-
give
(receiver, good, quantity, epsilon=1e-11)[source]¶ gives a good to another agent
- Args:
- receiver:
- The name of the receiving agent a tuple (group, id). e.G. (‘firm’, 15)
- good:
- the good to be transfered
- quantity:
- amount to be transfered
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
Raises:
AssertionError, when good smaller than 0.- Return:
- Dictionary, with the transfer, which can be used by self.log(…).
Example:
self.log('taxes', self.give('money': 0.05 * self['money'])
-
peak_offers
(good, sorted=True, descending=False, shuffled=True)[source]¶ returns a peak on all offers of the ‘good’ ordered by price. Peaked offers can not be accepted or rejected and they do not expire.
- Args:
- good:
- the good which should be retrieved descending(bool, default=False): False for descending True for ascending by price
- Returns:
- A list of offers ordered by price
Example:
offers = get_offers('books') for offer in offers: if offer.price < 50: self.accept(offer) elif offer.price < 100: self.accept(offer, 1) else: self.reject(offer) # optional
-
reject
(offer)[source]¶ Rejects and offer, if the offer is subsequently accepted in the same subround it is accepted’. Peaked offers can not be rejected.
Args:
- offer:
- the offer to be rejected
-
sell
(receiver, good, quantity, price, currency='money', epsilon=1e-11)[source]¶ Sends a offer to sell a particular good to somebody. The amount promised is reserved. (self.free(good), shows the not yet reserved goods)
- Args:
- receiver:
- the receiving agent
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to buy at this price
- price:
- price per unit
- currency:
- is the currency of this transaction (defaults to ‘money’)
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
- Returns:
- A reference to the offer. The offer and the offer status can be accessed with self.info(offer_reference).
Example:
def subround_1(self): self.offer = self.sell('household', 1, 'cookies', quantity=5, price=0.1) def subround_2(self): offer = self.info(self.offer) if offer.status == 'accepted': print(offer.final_quantity , 'cookies have be bougth') else: offer.status == 'rejected': print('On diet')
-
take
(receiver, good, quantity, epsilon=1e-11)[source]¶ take a good from another agent. The other agent has to accept. using self.accept()
Args:
- receiver:
- the receiving agent
- good:
- the good to be taken
- quantity:
- the quantity to be taken
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
abce.trade module¶
The abceagent.Agent
class is the basic class for creating your agent. It
automatically handles the possession of goods of an agent. In order to produce/transform
goods you need to also subclass the abceagent.Firm
[1]_ or to create a consumer
the abceagent.Household
.
For detailed documentation on:
- Trading:
- see
abceagent.Trade
- Logging and data creation:
- see
abceagent.Database
and simulation_results - Messaging between agents:
- see
abceagent.Messaging
.
[1] | or abceagent.FirmMultiTechnologies for simulations with complex technologies. |
-
class
abce.trade.
Offer
(sender, receiver, good, quantity, price, currency, sell, id, made)[source] Bases:
object
-
currency
-
final_quantity
-
good
-
id
-
made
-
price
-
quantity
-
receiver
-
sell
-
sender
-
status
-
status_round
-
-
class
abce.trade.
Trade
(id, agent_parameters, simulation_parameters, group, trade_logging, database, check_unchecked_msgs, expiring, perishable, resource_endowment, start_round=None)[source] Bases:
object
Agents can trade with each other. The clearing of the trade is taken care of fully by ABCE. Selling a good works in the following way:
An agent sends an offer.
sell()
ABCE does not allow you to sell the same good twice; self.free(good) shows how much good is not reserved yet
Next subround: An agent receives the offer
get_offers()
, and canaccept()
,reject()
or partially accept it.accept()
The good is credited and the price is deducted from the agent’s possessions.
Next subround:
- in case of acceptance the money is automatically credited.
- in case of partial acceptance the money is credited and part of the reserved good is unblocked.
- in case of rejection the good is unblocked.
Analogously for buying:
buy()
Example:
# Agent 1 def sales(self): self.remember_trade = self.sell('Household', 0, 'cookies', quantity=5, price=self.price) # Agent 2 def receive_sale(self): oo = self.get_offers('cookies') for offer in oo: if offer.price < 0.3: try: self.accept(offer) except NotEnoughGoods: self.accept(offer, self['money'] / offer.price) else: self.reject(offer) # Agent 1, subround 3 def learning(self): offer = self.info(self.remember_trade) if offer.status == 'reject': self.price *= .9 elif offer.status = 'accepted': self.price *= offer.final_quantity / offer.quantity
Example:
# Agent 1 def sales(self): self.remember_trade = self.sell('Household', 0, 'cookies', quantity=5, price=self.price, currency='dollars') # Agent 2 def receive_sale(self): oo = self.get_offers('cookies') for offer in oo: if ((offer.currency == 'dollars' and offer.price < 0.3 * exchange_rate) or (offer.currency == 'euros' and dollars'offer.price < 0.3)): try: self.accept(offer) except NotEnoughGoods: self.accept(offer, self['money'] / offer.price) else: self.reject(offer)
If we did not implement a barter class, but one can use this class as a barter class,
-
accept
(offer, quantity=-999, epsilon=1e-11)[source] The buy or sell offer is accepted and cleared. If no quantity is given the offer is fully accepted; If a quantity is given the offer is partial accepted.
Args:
- offer:
- the offer the other party made
- quantity:
- quantity to accept. If not given all is accepted
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
- Return:
- Returns a dictionary with the good’s quantity and the amount paid.
-
buy
(receiver, good, quantity, price, currency='money', epsilon=1e-11)[source] Sends a offer to buy a particular good to somebody. The money promised is reserved. (self.free(currency), shows the not yet reserved goods)
- Args:
- receiver:
- The name of the receiving agent a tuple (group, id). e.G. (‘firm’, 15)
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to buy at this price
- price:
- price per unit
- currency:
- is the currency of this transaction (defaults to ‘money’)
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
-
get_buy_offers
(good, sorted=True, descending=False, shuffled=True)[source]
-
get_buy_offers_all
(descending=False, sorted=True)[source]
-
get_offers
(good, sorted=True, descending=False, shuffled=True)[source] returns all offers of the ‘good’ ordered by price.
Offers that are not accepted in the same subround (def block) are automatically rejected. However you can also manually reject.
peek_offers can be used to look at the offers without them being rejected automatically
- Args:
- good:
- the good which should be retrieved
- sorted(bool, default=True):
- Whether offers are sorted by price. Faster if False.
- descending(bool, default=False):
- False for descending True for ascending by price
- shuffled(bool, default=True):
- whether the order of messages is randomized or correlated with the ID of the agent. Setting this to False speeds up the simulation considerably, but introduces a bias.
- Returns:
- A list of
abce.trade.Offer
ordered by price.
Example:
offers = get_offers('books') for offer in offers: if offer.price < 50: self.accept(offer) elif offer.price < 100: self.accept(offer, 1) else: self.reject(offer) # optional
-
get_offers_all
(descending=False, sorted=True)[source] returns all offers in a dictionary, with goods as key. The in each goods-category the goods are ordered by price. The order can be reversed by setting descending=True
Offers that are not accepted in the same subround (def block) are automatically rejected. However you can also manually reject.
Args:
- descending(optional):
- is a bool. False for descending True for ascending by price
- sorted(default=True):
- Whether offers are sorted by price. Faster if False.
Returns:
a dictionary with good types as keys and list ofabce.trade.Offer
as valuesExample:
oo = get_offers_all(descending=False) for good_category in oo: print('The cheapest good of category' + good_category + ' is ' + good_category[0]) for offer in oo[good_category]: if offer.price < 0.5: self.accept(offer) for offer in oo.beer: print(offer.price, offer.sender)
-
get_sell_offers
(good, sorted=True, descending=False, shuffled=True)[source]
-
get_sell_offers_all
(descending=False, sorted=True)[source]
-
give
(receiver, good, quantity, epsilon=1e-11)[source] gives a good to another agent
- Args:
- receiver:
- The name of the receiving agent a tuple (group, id). e.G. (‘firm’, 15)
- good:
- the good to be transfered
- quantity:
- amount to be transfered
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
Raises:
AssertionError, when good smaller than 0.- Return:
- Dictionary, with the transfer, which can be used by self.log(…).
Example:
self.log('taxes', self.give('money': 0.05 * self['money'])
-
peak_buy_offers
(good, sorted=True, descending=False, shuffled=True)[source]
-
peak_offers
(good, sorted=True, descending=False, shuffled=True)[source] returns a peak on all offers of the ‘good’ ordered by price. Peaked offers can not be accepted or rejected and they do not expire.
- Args:
- good:
- the good which should be retrieved descending(bool, default=False): False for descending True for ascending by price
- Returns:
- A list of offers ordered by price
Example:
offers = get_offers('books') for offer in offers: if offer.price < 50: self.accept(offer) elif offer.price < 100: self.accept(offer, 1) else: self.reject(offer) # optional
-
peak_sell_offers
(good, sorted=True, descending=False, shuffled=True)[source]
-
reject
(offer)[source] Rejects and offer, if the offer is subsequently accepted in the same subround it is accepted’. Peaked offers can not be rejected.
Args:
- offer:
- the offer to be rejected
-
sell
(receiver, good, quantity, price, currency='money', epsilon=1e-11)[source] Sends a offer to sell a particular good to somebody. The amount promised is reserved. (self.free(good), shows the not yet reserved goods)
- Args:
- receiver:
- the receiving agent
- ‘good’:
- name of the good
- quantity:
- maximum units disposed to buy at this price
- price:
- price per unit
- currency:
- is the currency of this transaction (defaults to ‘money’)
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
- Returns:
- A reference to the offer. The offer and the offer status can be accessed with self.info(offer_reference).
Example:
def subround_1(self): self.offer = self.sell('household', 1, 'cookies', quantity=5, price=0.1) def subround_2(self): offer = self.info(self.offer) if offer.status == 'accepted': print(offer.final_quantity , 'cookies have be bougth') else: offer.status == 'rejected': print('On diet')
-
take
(receiver, good, quantity, epsilon=1e-11)[source] take a good from another agent. The other agent has to accept. using self.accept()
Args:
- receiver:
- the receiving agent
- good:
- the good to be taken
- quantity:
- the quantity to be taken
- epsilon (optional):
- if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting – floating point problems
-
abce.trade.
compare_with_ties
(x, y)[source]
-
abce.trade.
get_epsilon
()[source]
abce.webtext module¶
Module contents¶
The best way to start creating a simulation is by copying the start.py file and other files from ‘abce/template’ in https://github.com/AB-CE/examples.
To see how to create a simulation, read ipython_tutorial.
This is a minimal template for a start.py:
from agent import Agent
from abce import *
simulation = Simulation(name='ABCE')
agents = simulation.build_agents(Agent, 'agent', 2)
for time in range(100):
simulation.advance_round(time)
agents.one()
agents.two()
agents.three()
simulation.graphs()
Note two things are important: there must be either a
graphs()
or a finalize()
at the end
otherwise the simulation blocks at the end.
Furthermore, every round needs to be announced using simulation.advance_round(time),
where time is any representation of time.
-
class
abce.
Simulation
(name='abce', random_seed=None, trade_logging='off', processes=1, check_unchecked_msgs=False)[source]¶ Bases:
object
This is the class in which the simulation is run. Actions and agents have to be added. Databases and resource declarations can be added. Then run the simulation.
- Args:
- name:
- name of the simulation
- random_seed (optional):
- a random seed that controls the random number of the simulation
- trade_logging:
- Whether trades are logged,trade_logging can be ‘group’ (fast) or ‘individual’ (slow) or ‘off’
- processes (optional):
- The number of processes that runs in parallel. Each process hosts a share of the agents. By default, if this parameter is not specified, processes is all your logical processor cores times two, using hyper-threading when available. For easy debugging, set processes to one and the simulation is executed without parallelization. Sometimes it is advisable to decrease the number of processes to the number of logical or even physical processor cores on your computer. For easy debugging set processes to 1, this way only one agent runs at a time and only one error message is displayed
- check_unchecked_msgs:
- check every round that all messages have been received with get_massages or get_offers.
Example:
simulation = Simulation(name='ABCE', trade_logging='individual', processes=None)
Example for a simulation:
num_firms = 5 num_households = 2000 w = Simulation(name='ABCE', trade_logging='individual', processes=None) w.declare_round_endowment(resource='labor_endowment', productivity=1, product='labor') w.panel('firm', command='after_sales_before_consumption') firms = w.build_agents(Firm, 'firm', num_firms) households = w.build_agents(Household, 'household', num_households) all = firms + households for r in range(100): self.advance_round(r) households.recieve_connections() households.offer_capital() firms.buy_capital() firms.production() if r == 250: centralbank.intervention() households.buy_product() all.after_sales_before_consumption() households.consume() w.finalize() w.graphs()
-
build_agents
(AgentClass, group_name, number=None, agent_parameters=None, **parameters)[source]¶ This method creates agents.
Args:
- AgentClass:
- is the name of the AgentClass that you imported
- group_name:
- the name of the group, as it will be used in the action list and transactions. Should generally be lowercase of the AgentClass.
- number:
- number of agents to be created.
- agent_parameters:
- a list of dictionaries, where each agent gets one dictionary. The number of agents is the length of the list
- any other parameters:
- are directly passed to the agent
Example:
firms = simulation.build_agents(Firm, 'firm', number=simulation_parameters['num_firms']) banks = simulation.build_agents(Bank, 'bank', agent_parameters=[{'name': 'UBS'}, {'name': 'amex'},{'name': 'chase'} **simulation_parameters, loanable=True) centralbanks = simulation.build_agents(CentralBank, 'centralbank', number=1, rounds=num_rounds)
-
create_agents
(AgentClass, group_name, simulation_parameters=None, agent_parameters=None, number=1)[source]¶ Creates an additional agent in an existing group during the simulation. If agents have been deleted, their id’s are reduced.
Args:
- AgentClass:
- the class of agent to create. (can be the same class as the creating agent)
- ‘group_name’:
- the name of the group the agent should belong to. This is the
group name string e.G.
'firm'
, not the group variable e.G.firms
infirms = simulation.build_agents(...)
- simulation_parameters:
- a dictionary of parameters
- agent_parameters:
- List of a dictionary of parameters
- number:
- if no agent_parameters list is given the number of agents to be created can be specified
- Returns:
- id of new agent.
Example:
self.create_agent(BeerFirm, 'beerfirm', parameters=self.parameters, agent_parameters={'creation': self.time})
-
declare_expiring
(good, duration)[source]¶ This type of good lasts for several rounds, but eventually expires. For example computers would last for several years and than become obsolete.
Args:
- good:
- the good, which expires
- duration:
- the duration before the good expires
-
declare_perishable
(good)[source]¶ This good only lasts one round and then disappears. For example labor, if the labor is not used today today’s labor is lost. In combination with resource this is useful to model labor or capital.
In the example below a worker has an endowment of labor and capital. Every round he can sell his labor service and rent his capital. If he does not the labor service for this round and the rent is lost.
Args:
good: the good that perishes Example:: w.declare_perishable(good='LAB') w.declare_perishable(good='CAP')
-
declare_round_endowment
(resource, units, product)[source]¶ At the beginning of very round the agent gets ‘units’ units of good ‘product’ for every ‘resource’ he possesses.
Round endowments are group specific, that means when somebody except the specified group holds them they do not produce.
Args:
resource: The good that you have to hold to get the other units: the multiplier to get the produced good product: the good that is produced if you hold the first good groups: a list of agent groups, which gain the second good, if they hold the first one
Example:
A farmer gets a ton of harvest for every acre: w.declare_round_endowment(resource='land', units=1000, product='wheat')
-
declare_service
(human_or_other_resource, units, service)[source]¶ When the agent holds the human_or_other_resource, he gets ‘units’ of service every round the service can be used only with in this round.
Args:
human_or_other_resource: the good that needs to be in possessions to create the other good 'self.create('adult', 2)' units: how many units of the service is available service: the service that is created groups: a list of agent groups that can create the service
Example:
For example if a household has two adult family members, it gets 16 hours of work w.declare_service('adult', 8, 'work')
-
delete_agents
(group, ids)[source]¶ This deletes a group of agents. The model has to make sure that other agents are notified of the death of agents in order to stop them from corresponding with this agent. Note that if you create new agents after deleting agents the ID’s of the deleted agents are reused.
- Args:
- group:
- group of the agent
- ids:
- a list of ids of the agents to be deleted in that group
-
finalize
()[source]¶ simulation.finalize() must be run after each simulation. It will write all data to disk
Example:
simulation = Simulation(...) ... for r in range(100): simulation.advance_round(r) agents.do_something() ... simulation.finalize()
-
graphs
()[source]¶ after the simulation is run, graphs() shows graphs of all data collected in the simulation. Shows the same output as the @gui decorator shows.
Example:
simulation = Simulation(...) for r in range(100): simulation.advance_round(r) agents.do_something() ... simulation.graphs()
-
path
= None¶ the path variable contains the path to the simulation outcomes it can be used to generate your own graphs as all resulting csv files are there.
-
time
= None¶ Returns the current time set with simulation.advance_round(time)