diff --git a/db/production.yml b/db/production.yml index d4dee85..1aaa10a 100644 --- a/db/production.yml +++ b/db/production.yml @@ -2,7 +2,7 @@ kind: production spec: - name: Grain - amount: 10 + amount: 100 prod: Raw_Agriculture_Plot: 1 # - name: Fruit @@ -20,11 +20,11 @@ spec: # Wood: 1 - name: Food - amount: 1 + amount: 50 prod: # Fuel: 1 # Fruit: 1 - Grain: 5 + Grain: 2 diff --git a/econ/__pycache__/exchange.cpython-310.pyc b/econ/__pycache__/exchange.cpython-310.pyc index 55ebdcf..ed015d3 100644 Binary files a/econ/__pycache__/exchange.cpython-310.pyc and b/econ/__pycache__/exchange.cpython-310.pyc differ diff --git a/econ/agents/__pycache__/base_aquire_agent.cpython-310.pyc b/econ/agents/__pycache__/base_aquire_agent.cpython-310.pyc index c451fdf..4eebc45 100644 Binary files a/econ/agents/__pycache__/base_aquire_agent.cpython-310.pyc and b/econ/agents/__pycache__/base_aquire_agent.cpython-310.pyc differ diff --git a/econ/agents/__pycache__/base_distribution_agent.cpython-310.pyc b/econ/agents/__pycache__/base_distribution_agent.cpython-310.pyc index 048ed10..68a11fc 100644 Binary files a/econ/agents/__pycache__/base_distribution_agent.cpython-310.pyc and b/econ/agents/__pycache__/base_distribution_agent.cpython-310.pyc differ diff --git a/econ/agents/__pycache__/price_believe_aquire.cpython-310.pyc b/econ/agents/__pycache__/price_believe_aquire.cpython-310.pyc index 5e5a600..ed68de6 100644 Binary files a/econ/agents/__pycache__/price_believe_aquire.cpython-310.pyc and b/econ/agents/__pycache__/price_believe_aquire.cpython-310.pyc differ diff --git a/econ/agents/__pycache__/price_believe_distribute.cpython-310.pyc b/econ/agents/__pycache__/price_believe_distribute.cpython-310.pyc index 4eaa4dd..35c1b31 100644 Binary files a/econ/agents/__pycache__/price_believe_distribute.cpython-310.pyc and b/econ/agents/__pycache__/price_believe_distribute.cpython-310.pyc differ diff --git a/econ/agents/base_aquire_agent.py b/econ/agents/base_aquire_agent.py index 032ce89..9a07876 100644 --- a/econ/agents/base_aquire_agent.py +++ b/econ/agents/base_aquire_agent.py @@ -19,7 +19,9 @@ class Base_Aquire_Agent(BaseAgent,ABC): self.trades=[] self.tqty=0 self.qty_offset=0 - self.expense=0 + + self.texpense=0 + self.expense_offset=0 self.max_price=-1 super().__init__(simulation) @@ -37,7 +39,7 @@ class Base_Aquire_Agent(BaseAgent,ABC): If err < 0 then agent needs to aquire resources """ err=self.business.inventory[self.resource]-self.target - return err + return int(err) def set_price_max(self,price: int): """ @@ -60,7 +62,6 @@ class Base_Aquire_Agent(BaseAgent,ABC): return None # we dont have enough balance self.business.balance-=total_price - self.expense+=total_price cx.add_to_account(self.id,"balance",total_price) # prepaid charge account for cx order=cx.submit_order(self.id,self.resource,amount,price_per,Side.BUY) if order==None: # Order failed @@ -77,7 +78,7 @@ class Base_Aquire_Agent(BaseAgent,ABC): amount=cx.get_account_resource_amount(self.id,"balance") cx.remove_from_account(self.id,"balance",amount) self.business.balance+=amount - self.expense-=amount + def collect_resource_from_cxs(self,resource): """ @@ -94,6 +95,7 @@ class Base_Aquire_Agent(BaseAgent,ABC): """ trades=[] self.tqty=0 + self.texpense=0 for cx_id in range(len(self.exchanges)): cx=self.exchanges[cx_id] orders=self.orders[cx_id] @@ -105,18 +107,22 @@ class Base_Aquire_Agent(BaseAgent,ABC): self.trades=trades for t in trades: self.tqty+=t.trade_qty + self.texpense+=round(t.trade_qty*t.trade_price,2) return trades # Confirm a purchase of x amount to reduce qty and expense counter def confirm_purchase(self,confirmed_qty): expensePer=self.expense/self.qty confirmedExpense=expensePer*confirmed_qty - self.expense-=confirmedExpense + self.expense_offset-=confirmedExpense self.qty_offset-=confirmed_qty @property def qty(self): return self.tqty+self.qty_offset + @property + def expense(self): + return self.texpense+self.expense_offset def reset(self, episode): #self.tqty=0 diff --git a/econ/agents/base_distribution_agent.py b/econ/agents/base_distribution_agent.py index 50992d2..24353ff 100644 --- a/econ/agents/base_distribution_agent.py +++ b/econ/agents/base_distribution_agent.py @@ -29,6 +29,8 @@ class Base_Distribution_Agent(BaseAgent,ABC): """ Sets the amount of resources the agent should keep in business inventory """ + if target<0: + target=0 self.target=target @@ -46,7 +48,7 @@ class Base_Distribution_Agent(BaseAgent,ABC): If err < 0 then agent needs to distribute resources """ err=self.business.inventory[self.resource]-self.target - return err + return int(err) def distribute_resource(self,price_per,amount,cx_id): @@ -119,6 +121,7 @@ class Base_Distribution_Agent(BaseAgent,ABC): 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) diff --git a/econ/agents/price_believe_aquire.py b/econ/agents/price_believe_aquire.py index 4f01475..b308a90 100644 --- a/econ/agents/price_believe_aquire.py +++ b/econ/agents/price_believe_aquire.py @@ -1,59 +1,63 @@ from .base_aquire_agent import Base_Aquire_Agent import random + + class Price_Believe_Aquire_Agent(Base_Aquire_Agent): """ Aquire agent with internal price believe system. """ + def __init__(self, simulation, business, resource, exchanges: list, lr, max_price_adj_rate) -> None: super().__init__(simulation, business, resource, exchanges) - self.lr=lr - self.max_price_adj_rate=max_price_adj_rate - self.price_believe={i: 1 for i in range(len(self.exchanges))} - self.open_orders={i: [] for i in range(len(self.exchanges))} - self.open_qty=0 - + self.lr = lr + self.max_price_adj_rate = max_price_adj_rate + self.price_believe = {i: 1 for i in range(len(self.exchanges))} + self.open_orders = {i: [] for i in range(len(self.exchanges))} + self.open_qty = 0 + self.hp_threshold=0.25 + self.lp_threshold=0.90 - def tick(self,tick,episode): + def tick(self, tick, episode): - - order_error=self.open_qty+self.target_error() - if order_error<0: + order_error = self.open_qty+self.target_error() + if order_error < 0: # aquire based on current price believe - cx_id=self.select_best_cx() - order=self.order_resource(self.price_believe[cx_id],order_error*-1,cx_id) - if not order==None: - self.register_order(cx_id,order) + cx_id = self.select_best_cx() + order = self.order_resource( + self.price_believe[cx_id], order_error*-1, cx_id) + if not order == None: + self.register_order(cx_id, order) else: # order failed due to missing balance.. we need to adjust our price believe self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) - self.update_believe(cx_id,-1) - self.tick_open_orders() + self.update_believe(cx_id, -1) + self.tick_open_orders() def select_best_cx(self): - best_id=-1 - best=999999999 + best_id = -1 + best = 999999999 for cx_id in range(len(self.exchanges)): - cx=self.exchanges[cx_id] - available=(cx.get_total_supply(self.resource)>0) + cx = self.exchanges[cx_id] + available = (cx.get_total_supply(self.resource) > 0) if available: - potential=1*self.price_believe[cx_id] + potential = 1*self.price_believe[cx_id] else: continue - if potential int: @@ -61,69 +65,81 @@ class Price_Believe_Aquire_Agent(Base_Aquire_Agent): Removes 1 from pending orders timeout timer and cancels timeed out orders. Returns ids of orders that timeed out. """ - self.open_qty=0 + self.open_qty = 0 for cx_id in range(len(self.exchanges)): - cx=self.exchanges[cx_id] - cx_orders=self.open_orders[cx_id] + cx = self.exchanges[cx_id] + cx_orders = self.open_orders[cx_id] for i in cx_orders: - # Check for each order if it is fullfiled or if it is timed - o=self.orders[cx_id][i["id"]] - leaves=o.leaves_qty - if o.leaves_qty==0: - #order is done - self.open_orders[cx_id].remove(i) # remove order from open - self.update_believe(cx_id,-1) # update price believe + # Check for each order if it is fullfiled or if it is timed + o = self.orders[cx_id][i["id"]] + leaves = o.leaves_qty + if o.leaves_qty == 0: + # order is done + self.open_orders[cx_id].remove(i) # remove order from open + self.update_believe(cx_id, -1) # update price believe self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) continue - if not (i["leaves"]==leaves): - #update in order - i["leaves"]=leaves + if not (i["leaves"] == leaves): + # update in order + i["leaves"] = leaves self.update_trades() - #reset lifetime - i["lifetime"]=self.max_price_adj_rate - if i["lifetime"]>0: - self.open_qty+=o.leaves_qty - i["lifetime"]-=1 # subtract lifetime + # reset lifetime + i["lifetime"] = self.max_price_adj_rate + if i["lifetime"] > 0: + self.open_qty += o.leaves_qty + i["lifetime"] -= 1 # subtract lifetime else: # timeout self.update_trades() - buy = o.qty-o.leaves_qty - buyp=buy/o.qty - sup = cx.total_supply[self.resource]+buy - if sup == 0: - sup = 1 - coverage = buy/sup - # 50 % coverage limit - modifier = (max([coverage,buyp])*2)-1 + + modifier =0 + success=self.calc_order_success(cx,o) + if success>=self.lp_threshold: + modifier=-1 + elif success<=self.hp_threshold: + modifier=1 cx.cancel_order(i["id"]) self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) - self.update_believe(cx_id,1) + self.update_believe(cx_id, modifier) self.open_orders[cx_id].remove(i) - def update_believe(self,cx_id,modifier): + def calc_order_success(self, cx, o): + """ + Calculate how we should adjust the price belive + """ + buy = o.qty-o.leaves_qty + buyperc = buy/o.qty + dem = cx.total_supply[self.resource]+buy + if dem == 0: + dem = 1 + coverage = buy/dem + base_success = max([coverage, buyperc]) + return base_success + + def update_believe(self, cx_id, modifier): """ Updates the believe based on the modifier. If positive will add lr to believe If negative will sub lr to believe """ - self.price_believe[cx_id]+=modifier*self.lr - if self.price_believe[cx_id]<0: - self.price_believe[cx_id]=0 + self.price_believe[cx_id] += modifier*self.lr + if self.price_believe[cx_id] < 0: + self.price_believe[cx_id] = 0 - def reset(self,episode): + def reset(self, episode): # Clean shop for today for cx_id in range(len(self.exchanges)): - cx=self.exchanges[cx_id] - cx_orders=self.open_orders[cx_id] + cx = self.exchanges[cx_id] + cx_orders = self.open_orders[cx_id] for i in cx_orders: cx.cancel_order(i["id"]) self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) # book keeping self.update_trades() - self.open_orders={i: [] for i in range(len(self.exchanges))} - self.orders={i: {} for i in range(len(self.exchanges))} - return super().reset(episode) \ No newline at end of file + self.open_orders = {i: [] for i in range(len(self.exchanges))} + self.orders = {i: {} for i in range(len(self.exchanges))} + return super().reset(episode) diff --git a/econ/agents/price_believe_distribute.py b/econ/agents/price_believe_distribute.py index 6ae0846..9013636 100644 --- a/econ/agents/price_believe_distribute.py +++ b/econ/agents/price_believe_distribute.py @@ -14,6 +14,8 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent): self.price_believe = {i: 1 for i in range(len(self.exchanges))} self.open_orders = {i: [] for i in range(len(self.exchanges))} self.open_qty = 0 + self.lp_threshold=0.25 + self.hp_threshold=0.90 def tick(self, step, episode): @@ -72,16 +74,12 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent): if o.leaves_qty == 0: # order is done self.open_orders[cx_id].remove(i) # remove order from open - sold = o.qty-o.leaves_qty - if o.qty==0: - o.qty=1 - soldperc=sold/o.qty - dem = cx.total_demand[self.resource]+sold - if dem == 0: - dem = 1 - coverage = sold/dem - # 50 % coverage limit - modifier = (max([coverage,soldperc])*2)-1 + succsess=self.calc_order_success(cx,o) + modifier=0 + if succsess>=self.hp_threshold: + modifier=1 + elif succsess<=self.lp_threshold: + modifier=-1 self.update_believe(cx_id, modifier) # update price believe self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) @@ -101,20 +99,29 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent): else: # timeout self.update_trades() - - sold = o.qty-o.leaves_qty - soldperc=sold/o.qty - dem = cx.total_demand[self.resource]+sold - if dem == 0: - dem = 1 - coverage = sold/dem - # 50 % coverage limit - modifier = (max([coverage,soldperc])*2)-1 + succsess=self.calc_order_success(cx,o) + modifier=0 + if succsess>=self.hp_threshold: + modifier=1 + elif succsess<=self.lp_threshold: + modifier=-1 cx.cancel_order(i["id"]) self.collect_balance_from_cxs() self.collect_resource_from_cxs(self.resource) self.update_believe(cx_id, modifier) self.open_orders[cx_id].remove(i) + def calc_order_success(self,cx, o): + """ + Calculate how we should adjust the price belive + """ + sold = o.qty-o.leaves_qty + soldperc=sold/o.qty + dem = cx.total_demand[self.resource]+sold + if dem == 0: + dem = 1 + coverage = sold/dem + base_success=max([coverage,soldperc]) + return base_success def update_believe(self, cx_id, modifier): """ diff --git a/econ/business/Price_Believe_Business.py b/econ/business/Price_Believe_Business.py index 5c3ff1b..3630703 100644 --- a/econ/business/Price_Believe_Business.py +++ b/econ/business/Price_Believe_Business.py @@ -37,7 +37,7 @@ class Price_Believe_Business(Business): self.update_income_per_unit(step) # calc descision - orderForNewProds = 1 + orderForNewProds = self.max_storage if self.income_per_unit<=0 or self.expense_per_unit<=0: # dont have data retain=0 @@ -47,7 +47,7 @@ class Price_Believe_Business(Business): ie = 0 if ie > 1: ie = 1 - #retain=(self.max_storage-ie*self.max_storage)*amount + #retain=((self.max_storage-ie*self.max_storage)*amount)-amount retain=0 @@ -59,7 +59,7 @@ class Price_Believe_Business(Business): self.aquire[k].set_target(v*orderForNewProds) # update production - targetUnit = self.production["amount"]*self.max_storage + targetUnit = self.production["amount"]*orderForNewProds self.craft.set_target(targetUnit) # set min distribute diff --git a/econ/business/__pycache__/Price_Believe_Business.cpython-310.pyc b/econ/business/__pycache__/Price_Believe_Business.cpython-310.pyc index 2f11569..3641e43 100644 Binary files a/econ/business/__pycache__/Price_Believe_Business.cpython-310.pyc and b/econ/business/__pycache__/Price_Believe_Business.cpython-310.pyc differ diff --git a/econ/exchange.py b/econ/exchange.py index 620c08b..3eeda63 100644 --- a/econ/exchange.py +++ b/econ/exchange.py @@ -125,8 +125,12 @@ class Exchange(): Returns an order if the order is active. Returns None if submit has failed. """ # calculate price for complete order fullfilment + prev=amount amount=int(amount) - full_price=round(price*amount,2) + if amount<1: + # invalid order + return None + full_price=round(price*amount) # Move resources into escrow