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 and abce.Messaging classes are included. An agent can also inheriting from abce.Firm, abce.FirmMultiTechnologies or abce.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’

class abce.agent.DummyContracts[source]

Bases: object

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.
contracts_to_deliver(good)[source]
contracts_to_deliver_all()[source]
contracts_to_receive(good)[source]
contracts_to_receive_all()[source]
deliver_contract(contract)[source]

delivers on a contract

end_contract(contract)[source]
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
pay_contract(contract)[source]

delivers on a contract

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
was_delivered_last_round(contract)[source]
was_delivered_this_round(contract)[source]
was_paid_last_round(contract)[source]
was_paid_this_round(contract)[source]
abce.credit.bound_zero(x)[source]

asserts that variable is above zero, where foating point imprecission is accounted for, and than makes sure it is above 0, without floating point imprecission

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

make_aggregation_and_write()[source]
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

class abce.expiringgood.ExpiringGood(duration)[source]

Bases: object

A good that expires after X rounds

abce.financial module

abce.group module

class abce.group.Action(_agents, actions)[source]

Bases: object

class abce.group.Chain(iterables)[source]

Bases: object

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

calculate_assetvalue(prices)[source]
calculate_liablityvalue(prices)[source]
calculate_netvalue(prices)[source]
calculate_valued_assets(prices)[source]
calculate_valued_liablities(prices)[source]
commit(good, committed_quantity, final_quantity)[source]
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
possession(good)[source]
possessions()[source]

returns all possessions

reserve(good, quantity)[source]
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
rewind(good, quantity)[source]
transform(ingredient, unit, product, quantity=None)[source]
abce.inventory.isclose(a, b)[source]

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() or get_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

class abce.online_variance.OnlineVariance[source]

Bases: object

clear()[source]
mean()[source]
std()[source]
sum()[source]
update(x)[source]

abce.online_variance module

class abce.online_variance.OnlineVariance[source]

Bases: object

clear()[source]
mean()[source]
std()[source]
sum()[source]
update(x)[source]

abce.postbox module

class abce.postbox.Postbox[source]

Bases: object

clear(group)[source]
copy(group_names)[source]
receive(group, id)[source]
send(group, id, message)[source]
class abce.postbox.PostboxManager(address=None, authkey=None, serializer='pickle', ctx=None)[source]

Bases: multiprocessing.managers.BaseManager

abce.postprocess module

abce.postprocess.create_aggregated_table(group, dataset)[source]
abce.postprocess.get_columns(dataset, table_name)[source]
abce.postprocess.get_str_columns(dataset, table_name, redundant_columns)[source]
abce.postprocess.join_table(tables, group, indexes, type_, dataset)[source]
abce.postprocess.save_to_csv(prefix, group, dataset)[source]
abce.postprocess.to_csv(directory, dataset)[source]

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() and accept_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.show.show()[source]

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:

  1. 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

  2. Next subround: An agent receives the offer get_offers(), and can accept(), reject() or partially accept it. accept()

    The good is credited and the price is deducted from the agent’s possessions.

  3. 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 of abce.trade.Offer as values

Example:

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.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:

  1. 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

  2. Next subround: An agent receives the offer get_offers(), and can accept(), reject() or partially accept it. accept()

    The good is credited and the price is deducted from the agent’s possessions.

  3. 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 of abce.trade.Offer as values

Example:

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()
advance_round(time)[source]
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_agent(AgentClass, group_name, simulation_parameters=None, agent_parameters=None)[source]
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 in firms = 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_agent(*ang)[source]
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)