Source code for abce.credit

# pylint: disable=W0232, C1001, C0111, R0913, E1101, W0212
# TODO end_contract; record all payments

from builtins import str
from builtins import object
from abce.notenoughgoods import NotEnoughGoods
from random import shuffle
from abce.trade import get_epsilon

epsilon = get_epsilon()


class Credit(object):
    __slots__ = ['sender_group', 'sender_id', 'deliver_good_group',
                 'deliver_good_id', 'pay_group', 'pay_id', 'amount', 'interest']

    def __init__(self, sender_group, sender_id, deliver_good_group,
                 deliver_good_id, pay_group, pay_id, quantity, interest):
        self.sender_group = sender_group
        self.sender_id = sender_id
        self.deliver_good_group = deliver_good_group
        self.deliver_good_id = deliver_good_id
        self.pay_group = pay_group
        self.pay_id = pay_id
        self.quantity = quantity
        self.interest = interest
        self.id = id
        self.round = round

    def __str__(self):
        return str(('sender', self.sender_group, self.sender_id, 'deliver', self.deliver_good_group,
                    self.deliver_good_id, self.pay_group, self.pay_id, self.quantity, self.interest))


[docs]class Credit(object): """ This class implements a bank credit, without a due date """
[docs] def request_credit(self, receiver_group, receiver_id, quantity, interest): """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 """ offer = Credit(sender_group=self.group, sender_id=self.id, deliver_good_group=self.group, deliver_good_id=self.id, pay_group=receiver_group, pay_id=receiver_id, quantity=quantity, interest=interest) self._send(receiver_group, receiver_id, '!o', offer) self._contract_offers_made[offer.id] = offer return offer
[docs] def get_contract_offers(self, good, descending=False): """ 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 """ ret = self._contract_offers[good] del self._contract_offers[good] shuffle(ret) ret.sort(key=lambda objects: objects.price, reverse=descending) return ret
[docs] def accept_contract(self, contract, quantity=None): """ 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. """ if quantity is None: quantity = contract.quantity else: contract.quantity = min(contract.quantity, quantity) assert quantity < contract.quantity + \ epsilon * max(quantity, contract.quantity) if quantity > contract.quantity: quantity = contract.quantity if contract.pay_group == self.group and contract.pay_id == self.id: self._contracts_pay[contract.good][contract.id] = contract self._send(contract.sender_group, contract.sender_id, '_ac', contract) else: self._contracts_deliver[contract.good][contract.id] = contract self._send(contract.sender_group, contract.sender_id, '_ac', contract) # if contract is Credit: return contract
[docs] def deliver_contract(self, contract): """ delivers on a contract """ assert contract.deliver_good_group == self.group and contract.deliver_good_id == self.id quantity = contract.quantity available = self._haves[contract.good] if quantity > available + epsilon + epsilon * max(quantity, available): raise NotEnoughGoods(self.name, contract.good, quantity - available) if quantity > available: quantity = available self._haves[contract.good] -= quantity self._send(contract.pay_group, contract.pay_id, '_dp', contract)
[docs] def pay_contract(self, contract): """ delivers on a contract """ assert contract.pay_group == self.group and contract.pay_id == self.id money = contract.quantity * contract.price available = self._haves['money'] if money > available + epsilon + epsilon * max(money, available): raise NotEnoughGoods(self.name, 'money', money - available) if money > available: money = available self._haves['money'] -= money self._send(contract.deliver_good_group, contract.deliver_good_id, '_dp', contract)
[docs] def contracts_to_deliver(self, good): return list(self._contracts_deliver[good].values())
[docs] def contracts_to_receive(self, good): return list(self._contracts_pay[good].values())
[docs] def contracts_to_deliver_all(self): ret = {} for good in self._contracts_deliver: ret[good] = list(self._contracts_deliver[good].values()) return request_offer
[docs] def contracts_to_receive_all(self): ret = {} for good in self._contracts_pay: ret[good] = list(self._contracts_pay[good].values()) return request_offer
[docs] def end_contract(self, contract): if contract.id in self._contracts_deliver[contract.good]: self._send(contract.pay_group, contract.pay_id, '!d', ('r', contract.good, contract.id)) del self._contracts_deliver[contract.good][contract.id] elif contract.id in self._contracts_pay[contract.good]: self._send(contract.deliver_good_group, contract.deliver_good_id, '!d', ('d', contract.good, contract.id)) del self._contracts_pay[contract.good][contract.id] else: raise Exception("Contract not found")
[docs] def was_paid_this_round(self, contract): return contract.paid[-1] == self.round
[docs] def was_delivered_this_round(self, contract): return contract.delivered[-1] == self.round
[docs] def was_paid_last_round(self, contract): return self.round - 1 in contract.paid
[docs] def was_delivered_last_round(self, contract): return self.round - 1 in contract.delivered
[docs]def bound_zero(x): """ 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 """ assert x > - \ epsilon, '%.30f is smaller than 0 - epsilon (%.30f)' % (x, - epsilon) if x < 0: return 0 else: return x