from .base_agent import BaseAgent from ..exchange import Exchange from lightmatchingengine.lightmatchingengine import Order,Side from abc import ABC from decimal import * class Base_Distribution_Agent(BaseAgent,ABC): def __init__(self,simulation,business,resource,exchanges: list) -> None: """ Agent for distribute of resources. business: Business to distribute resources for. resource: Resource to distribute. exchanges: list of exchanges to distribute resources to. """ self.business=business self.resource=resource self.exchanges=exchanges self.orders={i: {} for i in range(len(self.exchanges))} self.target=0 self.min_price=-1 self.max_batch_qty=10 self.tincome=0 self.tqty=0 self.income_offset=0 self.qty_offset=0 super().__init__(simulation) def set_target(self,target: int): """ Sets the amount of resources the agent should keep in business inventory """ if target<0: target=0 self.target=target def set_price_min(self,price: int): """ Sets the min price the agent should distribute the resources for. Set to -1 to disable minimum. """ self.min_price=price def target_error(self): """ Returns the difference between target and current business inventory. If err >0 the business is in surplus If err < 0 then agent needs to distribute resources """ err=self.business.inventory[self.resource]-self.target return int(err) def distribute_resource(self,price_per,amount,cx_id): """ distribute resource from selected exchange. Return true if order has been placed. """ # Get exchange cx=self.exchanges[cx_id] if not self.business.inventory[self.resource]>=amount: return False # we dont have enough balance self.business.inventory[self.resource]-=amount cx.add_to_account(self.id,self.resource,amount) # prepaid charge account for cx order=cx.submit_order(self.id,self.resource,amount,price_per,Side.SELL) if order==None: # Order failed return False self.orders[cx_id][order.order_id]=order return order def collect_balance_from_cxs(self): """ Collects resouces from account inventory in cxs. """ for cx in self.exchanges: amount=cx.get_account_resource_amount(self.id,"balance") cx.remove_from_account(self.id,"balance",amount) self.business.balance+=amount def collect_resource_from_cxs(self,resource): """ Collects resouces from account inventory in cxs. """ for cx in self.exchanges: amount=cx.get_account_resource_amount(self.id,resource) cx.remove_from_account(self.id,resource,amount) self.business.inventory[resource]+=amount def update_trades(self) -> list: """ Returns a list of all trades performed by this agent """ trades=[] self.tqty=0 self.tincome=0 for cx_id in range(len(self.exchanges)): cx=self.exchanges[cx_id] orders=self.orders[cx_id] if len(orders)>0: for k,o in orders.items(): if k in cx.order_trades_map: trades.extend(cx.order_trades_map[k]) self.trades=trades for t in trades: self.tqty+=t.trade_qty self.tincome+=t.trade_qty*t.trade_price self.tincome=round(self.tincome,2) return trades @property def qty(self): return self.tqty+self.qty_offset @property def income(self): return self.tincome+self.income_offset def confirm_distribution(self,dis_qty,step): income_per=self.income/self.qty income_to_confirm=income_per*dis_qty income_to_confirm=round(income_to_confirm,2) self.income_offset-=income_to_confirm self.qty_offset-=dis_qty self.income_offset=round(self.income_offset,2) def reset(self, episode): self.qty_offset=0 self.income_offset=0 self.trades=[] return super().reset(episode)