Module SimEconomica.Actor

Expand source code
from typing import List
from dataclasses import dataclass

# Systems
from Inventory import Inventory
from Order import Order, OrderResult, ActorOrderRecord, WaitingOrder
from OrderFactory import OrderFactory

# Data
from Resources import Recipe, Resource
from Resources import RESOURCES, RECIPES
from Job import JOBS

# Interfaces 
from Interfaces import IClearable, IMarket


class BaseActor(object):
    pass


class Actor(BaseActor, IClearable):
    def __init__(self, id: int, job: int, capital: int, recipe: Recipe):
        self.kID: int = id
        self.mJob: int = job
        self.mCapital: int = capital
        self.mAvailableCapital: int = capital
        self.mInventory: Inventory = Inventory()
        self.mCurrentRecipe: Recipe = recipe
        self.mWaitingOrders: List[WaitingOrder] = list()
        self._mOrderResults: List[OrderResult] = list()
        self.mOrderRecords: List[ActorOrderRecord] = list()

    def __str__(self):
        return JOBS[self.mJob].Name + " - " + self.mCurrentRecipe.Name + " - Capital: " + str(self.mCapital)

    def __repr__(self):
        return str(self)

    def GetProductionCapacity(self) -> int:
        """
            Check current recipe and current state of inventory to compute max number of units that can be produced.
        """
        capacity = 0
        if len(self.mCurrentRecipe.Inputs) > 0:
            for ingredient in self.mCurrentRecipe.Inputs:
                temp = self.mInventory[ingredient.ResourceID].Stock / ingredient.Quantity
                if temp < capacity or capacity == 0:
                    capacity = temp
        else:
            resourceID = self.mCurrentRecipe.Outputs[0].ResourceID
            capacity = int((self.mInventory[resourceID].GetCapacity() - self.mInventory[resourceID].GetStock()) / self.mCurrentRecipe.Outputs[0].Quantity)
        return int(capacity)

    def Produce(self, quantityToProduce: int):
        """
            Adjust state according to what resources are needed for current recipe, its outputs and a given quantity to produce.  
            This function is unsafe, and GetProductionCapacity must be called to ensure quantityToProduce is valid, and inventory quantities does not go negative
        """
        for ingredient in self.mCurrentRecipe.Inputs:
            self.mInventory[ingredient.ResourceID].Sub(ingredient.Quantity * quantityToProduce)
        for ingredient in self.mCurrentRecipe.Outputs:
            self.mInventory[ingredient.ResourceID].Add(ingredient.Quantity * quantityToProduce)

    def DeterminePurchaseQuantity(self, idProduct: int, market: IMarket):
        """
            Determine how much to bid for for current recipe
        """
        pass

    def CreateOrder(self, side: bool, quantity: int, price: int) -> Order:
        return OrderFactory.CreateNew(self.kID, side, quantity, price)
        #return Order(OrderFactory.ID, self.kID, side, price, quantity)

    def PrepareOrders(self):
        """
            Prepare bids and offers according to current state of inventory and capital available
        """
        tempOrder = OrderFactory.CreateNew(self.kID, True, 4, 11)
        self.mWaitingOrders.append(WaitingOrder(self.mCurrentRecipe.Outputs[0].ResourceID, tempOrder))

    def PostOrder(self, order: Order, marketID: int, markets: List[IMarket]):
        self.PostOrder_SingleMarket(order, markets[marketID])

    def PostOrder_SingleMarket(self, order: Order, market: IMarket):
        self.mAvailableCapital -= order.Quantity * order.Price
        market.AddOrder(order)
        self.mOrderRecords.append(ActorOrderRecord(order.Side, order.Price, order.Quantity))

    def NotifyOrderResult(self, orderResult: OrderResult): 
        """
            Called by a market to notify the actor of the result of one of its orders. 
            Takes an OrderResult instance as argument and appends it to _mOrderResults
        """
        self._mOrderResults.append(orderResult)

    def ProcessOrderResults(self):
        """
            Adjust inventory according to matched bids and offers on markets, and set data to compute adjustments to price belief.
        """
        # only process successful orders for now
        for order in self._mOrderResults:
            if (order.IsMatched):
                if (not order.Side):
                    self.mInventory[order.MarketID].Add(order.Quantity)
                    self.mCapital -= order.Quantity * order.ClearingPrice
                else:
                    self.mInventory[order.MarketID].Sub(order.Quantity)
                    self.mCapital += order.Quantity * order.ClearingPrice

    def AdjustPriceBeliefs(self):
        """
            Adjust price beliefs according to quantity matched and price given
        """
        # need to recompose stuff
        marketIDs = set()
        for order in self._mOrderResults:
            marketIDs.add(order.MarketID)
        marketIDs = list(marketIDs)

    def ClearTempData(self):
        """
            Clear order results, order records and set available capital back to capital
        """
        self._mOrderResults = []
        self.mOrderRecords = []
        self.mAvailableCapital = self.mCapital

Classes

class Actor (id: int, job: int, capital: int, recipe: Resources.Recipe)

Interface related to clearing data in between rounds, and resetting elements

Expand source code
class Actor(BaseActor, IClearable):
    def __init__(self, id: int, job: int, capital: int, recipe: Recipe):
        self.kID: int = id
        self.mJob: int = job
        self.mCapital: int = capital
        self.mAvailableCapital: int = capital
        self.mInventory: Inventory = Inventory()
        self.mCurrentRecipe: Recipe = recipe
        self.mWaitingOrders: List[WaitingOrder] = list()
        self._mOrderResults: List[OrderResult] = list()
        self.mOrderRecords: List[ActorOrderRecord] = list()

    def __str__(self):
        return JOBS[self.mJob].Name + " - " + self.mCurrentRecipe.Name + " - Capital: " + str(self.mCapital)

    def __repr__(self):
        return str(self)

    def GetProductionCapacity(self) -> int:
        """
            Check current recipe and current state of inventory to compute max number of units that can be produced.
        """
        capacity = 0
        if len(self.mCurrentRecipe.Inputs) > 0:
            for ingredient in self.mCurrentRecipe.Inputs:
                temp = self.mInventory[ingredient.ResourceID].Stock / ingredient.Quantity
                if temp < capacity or capacity == 0:
                    capacity = temp
        else:
            resourceID = self.mCurrentRecipe.Outputs[0].ResourceID
            capacity = int((self.mInventory[resourceID].GetCapacity() - self.mInventory[resourceID].GetStock()) / self.mCurrentRecipe.Outputs[0].Quantity)
        return int(capacity)

    def Produce(self, quantityToProduce: int):
        """
            Adjust state according to what resources are needed for current recipe, its outputs and a given quantity to produce.  
            This function is unsafe, and GetProductionCapacity must be called to ensure quantityToProduce is valid, and inventory quantities does not go negative
        """
        for ingredient in self.mCurrentRecipe.Inputs:
            self.mInventory[ingredient.ResourceID].Sub(ingredient.Quantity * quantityToProduce)
        for ingredient in self.mCurrentRecipe.Outputs:
            self.mInventory[ingredient.ResourceID].Add(ingredient.Quantity * quantityToProduce)

    def DeterminePurchaseQuantity(self, idProduct: int, market: IMarket):
        """
            Determine how much to bid for for current recipe
        """
        pass

    def CreateOrder(self, side: bool, quantity: int, price: int) -> Order:
        return OrderFactory.CreateNew(self.kID, side, quantity, price)
        #return Order(OrderFactory.ID, self.kID, side, price, quantity)

    def PrepareOrders(self):
        """
            Prepare bids and offers according to current state of inventory and capital available
        """
        tempOrder = OrderFactory.CreateNew(self.kID, True, 4, 11)
        self.mWaitingOrders.append(WaitingOrder(self.mCurrentRecipe.Outputs[0].ResourceID, tempOrder))

    def PostOrder(self, order: Order, marketID: int, markets: List[IMarket]):
        self.PostOrder_SingleMarket(order, markets[marketID])

    def PostOrder_SingleMarket(self, order: Order, market: IMarket):
        self.mAvailableCapital -= order.Quantity * order.Price
        market.AddOrder(order)
        self.mOrderRecords.append(ActorOrderRecord(order.Side, order.Price, order.Quantity))

    def NotifyOrderResult(self, orderResult: OrderResult): 
        """
            Called by a market to notify the actor of the result of one of its orders. 
            Takes an OrderResult instance as argument and appends it to _mOrderResults
        """
        self._mOrderResults.append(orderResult)

    def ProcessOrderResults(self):
        """
            Adjust inventory according to matched bids and offers on markets, and set data to compute adjustments to price belief.
        """
        # only process successful orders for now
        for order in self._mOrderResults:
            if (order.IsMatched):
                if (not order.Side):
                    self.mInventory[order.MarketID].Add(order.Quantity)
                    self.mCapital -= order.Quantity * order.ClearingPrice
                else:
                    self.mInventory[order.MarketID].Sub(order.Quantity)
                    self.mCapital += order.Quantity * order.ClearingPrice

    def AdjustPriceBeliefs(self):
        """
            Adjust price beliefs according to quantity matched and price given
        """
        # need to recompose stuff
        marketIDs = set()
        for order in self._mOrderResults:
            marketIDs.add(order.MarketID)
        marketIDs = list(marketIDs)

    def ClearTempData(self):
        """
            Clear order results, order records and set available capital back to capital
        """
        self._mOrderResults = []
        self.mOrderRecords = []
        self.mAvailableCapital = self.mCapital

Ancestors

Methods

def AdjustPriceBeliefs(self)

Adjust price beliefs according to quantity matched and price given

Expand source code
def AdjustPriceBeliefs(self):
    """
        Adjust price beliefs according to quantity matched and price given
    """
    # need to recompose stuff
    marketIDs = set()
    for order in self._mOrderResults:
        marketIDs.add(order.MarketID)
    marketIDs = list(marketIDs)
def ClearTempData(self)

Clear order results, order records and set available capital back to capital

Expand source code
def ClearTempData(self):
    """
        Clear order results, order records and set available capital back to capital
    """
    self._mOrderResults = []
    self.mOrderRecords = []
    self.mAvailableCapital = self.mCapital
def CreateOrder(self, side: bool, quantity: int, price: int) ‑> Order.Order
Expand source code
def CreateOrder(self, side: bool, quantity: int, price: int) -> Order:
    return OrderFactory.CreateNew(self.kID, side, quantity, price)
    #return Order(OrderFactory.ID, self.kID, side, price, quantity)
def DeterminePurchaseQuantity(self, idProduct: int, market: Interfaces.IMarket)

Determine how much to bid for for current recipe

Expand source code
def DeterminePurchaseQuantity(self, idProduct: int, market: IMarket):
    """
        Determine how much to bid for for current recipe
    """
    pass
def GetProductionCapacity(self) ‑> int

Check current recipe and current state of inventory to compute max number of units that can be produced.

Expand source code
def GetProductionCapacity(self) -> int:
    """
        Check current recipe and current state of inventory to compute max number of units that can be produced.
    """
    capacity = 0
    if len(self.mCurrentRecipe.Inputs) > 0:
        for ingredient in self.mCurrentRecipe.Inputs:
            temp = self.mInventory[ingredient.ResourceID].Stock / ingredient.Quantity
            if temp < capacity or capacity == 0:
                capacity = temp
    else:
        resourceID = self.mCurrentRecipe.Outputs[0].ResourceID
        capacity = int((self.mInventory[resourceID].GetCapacity() - self.mInventory[resourceID].GetStock()) / self.mCurrentRecipe.Outputs[0].Quantity)
    return int(capacity)
def NotifyOrderResult(self, orderResult: Order.OrderResult)

Called by a market to notify the actor of the result of one of its orders. Takes an OrderResult instance as argument and appends it to _mOrderResults

Expand source code
def NotifyOrderResult(self, orderResult: OrderResult): 
    """
        Called by a market to notify the actor of the result of one of its orders. 
        Takes an OrderResult instance as argument and appends it to _mOrderResults
    """
    self._mOrderResults.append(orderResult)
def PostOrder(self, order: Order.Order, marketID: int, markets: List[Interfaces.IMarket])
Expand source code
def PostOrder(self, order: Order, marketID: int, markets: List[IMarket]):
    self.PostOrder_SingleMarket(order, markets[marketID])
def PostOrder_SingleMarket(self, order: Order.Order, market: Interfaces.IMarket)
Expand source code
def PostOrder_SingleMarket(self, order: Order, market: IMarket):
    self.mAvailableCapital -= order.Quantity * order.Price
    market.AddOrder(order)
    self.mOrderRecords.append(ActorOrderRecord(order.Side, order.Price, order.Quantity))
def PrepareOrders(self)

Prepare bids and offers according to current state of inventory and capital available

Expand source code
def PrepareOrders(self):
    """
        Prepare bids and offers according to current state of inventory and capital available
    """
    tempOrder = OrderFactory.CreateNew(self.kID, True, 4, 11)
    self.mWaitingOrders.append(WaitingOrder(self.mCurrentRecipe.Outputs[0].ResourceID, tempOrder))
def ProcessOrderResults(self)

Adjust inventory according to matched bids and offers on markets, and set data to compute adjustments to price belief.

Expand source code
def ProcessOrderResults(self):
    """
        Adjust inventory according to matched bids and offers on markets, and set data to compute adjustments to price belief.
    """
    # only process successful orders for now
    for order in self._mOrderResults:
        if (order.IsMatched):
            if (not order.Side):
                self.mInventory[order.MarketID].Add(order.Quantity)
                self.mCapital -= order.Quantity * order.ClearingPrice
            else:
                self.mInventory[order.MarketID].Sub(order.Quantity)
                self.mCapital += order.Quantity * order.ClearingPrice
def Produce(self, quantityToProduce: int)

Adjust state according to what resources are needed for current recipe, its outputs and a given quantity to produce.
This function is unsafe, and GetProductionCapacity must be called to ensure quantityToProduce is valid, and inventory quantities does not go negative

Expand source code
def Produce(self, quantityToProduce: int):
    """
        Adjust state according to what resources are needed for current recipe, its outputs and a given quantity to produce.  
        This function is unsafe, and GetProductionCapacity must be called to ensure quantityToProduce is valid, and inventory quantities does not go negative
    """
    for ingredient in self.mCurrentRecipe.Inputs:
        self.mInventory[ingredient.ResourceID].Sub(ingredient.Quantity * quantityToProduce)
    for ingredient in self.mCurrentRecipe.Outputs:
        self.mInventory[ingredient.ResourceID].Add(ingredient.Quantity * quantityToProduce)
class BaseActor
Expand source code
class BaseActor(object):
    pass

Subclasses