Source code for turberfield.eargain.trade

#!/usr/bin/env python3
# encoding: UTF-8

# This file is part of turberfield.
#
# Turberfield is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Turberfield is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with turberfield.  If not, see <http://www.gnu.org/licenses/>.

import asyncio
from collections import defaultdict
from decimal import Decimal
import itertools
import logging

from turberfield.common.accounts import Accounts
from turberfield.common.dramatics import Dramatics
from turberfield.common.inventory import Inventory
from turberfield.common.inventory import Resource
from turberfield.common.types import Move
from turberfield.common.types import RenderGoods

from turberfield.dynamics.types import Stop

from turberfield.eargain.exchange import Exchange
from turberfield.eargain.types import Commodity
from turberfield.eargain.types import HOUR
from turberfield.eargain.types import Mass
from turberfield.eargain.types import TradePosition


[docs]class Trade(Exchange): @asyncio.coroutine def __call__(self, q, jq, priority): log = logging.getLogger( "turberfield.eargain.trade.{}".format(priority)) accounts = Accounts() dramatics = Dramatics() inventory = Inventory() tick = None while not isinstance(tick, Stop): tick = yield from q.get() if not self.start <= tick.t % self.period < self.end: continue parties = list(self.parties) for p in self.parties: if p not in inventory.places[self.meet]: parties.remove(p) yield from jq.put( tick.t + HOUR, tick.priority, Move(p, self.meet)) market = defaultdict(lambda: defaultdict(set)) shouts = ( (a, c, t) for a, c in itertools.product(parties, Commodity) for t in dramatics.relations[a, c] if isinstance(t, TradePosition) ) for a, c, p in shouts: market[c][p].add(a) for commodity, positions in market.items(): try: src = positions[TradePosition.selling].pop() dst = positions[TradePosition.buying].pop() except KeyError as e: log.debug(e) continue else: measure = Mass.Kg # FIXME quantity = Decimal( inventory.pockets[src][commodity] / measure.value) if quantity < 1: log.debug(quantity) continue goods = Resource(commodity, measure, quantity) ref = accounts.banking.ledger.ref cost = accounts.currency.exchange[commodity, ref] total = cost * quantity credit, debit = ( accounts.banking.ledger.columns[i.uuid] for i in (src, dst)) accounts.banking.ledger.commit(total, credit) accounts.banking.ledger.commit(-total, debit) yield from jq.put( tick.t, tick.priority, RenderGoods(src, dst, goods, self.meet, None) ) else: return tick