HA looks good

This commit is contained in:
2023-06-29 09:48:11 +02:00
parent 4bfe5245a9
commit 4d4d609cea
13 changed files with 134 additions and 98 deletions
+3 -3
View File
@@ -2,7 +2,7 @@ kind: production
spec: spec:
- name: Grain - name: Grain
amount: 10 amount: 100
prod: prod:
Raw_Agriculture_Plot: 1 Raw_Agriculture_Plot: 1
# - name: Fruit # - name: Fruit
@@ -20,11 +20,11 @@ spec:
# Wood: 1 # Wood: 1
- name: Food - name: Food
amount: 1 amount: 50
prod: prod:
# Fuel: 1 # Fuel: 1
# Fruit: 1 # Fruit: 1
Grain: 5 Grain: 2
Binary file not shown.
+11 -5
View File
@@ -19,7 +19,9 @@ class Base_Aquire_Agent(BaseAgent,ABC):
self.trades=[] self.trades=[]
self.tqty=0 self.tqty=0
self.qty_offset=0 self.qty_offset=0
self.expense=0
self.texpense=0
self.expense_offset=0
self.max_price=-1 self.max_price=-1
super().__init__(simulation) super().__init__(simulation)
@@ -37,7 +39,7 @@ class Base_Aquire_Agent(BaseAgent,ABC):
If err < 0 then agent needs to aquire resources If err < 0 then agent needs to aquire resources
""" """
err=self.business.inventory[self.resource]-self.target err=self.business.inventory[self.resource]-self.target
return err return int(err)
def set_price_max(self,price: int): def set_price_max(self,price: int):
""" """
@@ -60,7 +62,6 @@ class Base_Aquire_Agent(BaseAgent,ABC):
return None # we dont have enough balance return None # we dont have enough balance
self.business.balance-=total_price self.business.balance-=total_price
self.expense+=total_price
cx.add_to_account(self.id,"balance",total_price) # prepaid charge account for cx 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) order=cx.submit_order(self.id,self.resource,amount,price_per,Side.BUY)
if order==None: # Order failed if order==None: # Order failed
@@ -77,7 +78,7 @@ class Base_Aquire_Agent(BaseAgent,ABC):
amount=cx.get_account_resource_amount(self.id,"balance") amount=cx.get_account_resource_amount(self.id,"balance")
cx.remove_from_account(self.id,"balance",amount) cx.remove_from_account(self.id,"balance",amount)
self.business.balance+=amount self.business.balance+=amount
self.expense-=amount
def collect_resource_from_cxs(self,resource): def collect_resource_from_cxs(self,resource):
""" """
@@ -94,6 +95,7 @@ class Base_Aquire_Agent(BaseAgent,ABC):
""" """
trades=[] trades=[]
self.tqty=0 self.tqty=0
self.texpense=0
for cx_id in range(len(self.exchanges)): for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id] cx=self.exchanges[cx_id]
orders=self.orders[cx_id] orders=self.orders[cx_id]
@@ -105,18 +107,22 @@ class Base_Aquire_Agent(BaseAgent,ABC):
self.trades=trades self.trades=trades
for t in trades: for t in trades:
self.tqty+=t.trade_qty self.tqty+=t.trade_qty
self.texpense+=round(t.trade_qty*t.trade_price,2)
return trades return trades
# Confirm a purchase of x amount to reduce qty and expense counter # Confirm a purchase of x amount to reduce qty and expense counter
def confirm_purchase(self,confirmed_qty): def confirm_purchase(self,confirmed_qty):
expensePer=self.expense/self.qty expensePer=self.expense/self.qty
confirmedExpense=expensePer*confirmed_qty confirmedExpense=expensePer*confirmed_qty
self.expense-=confirmedExpense self.expense_offset-=confirmedExpense
self.qty_offset-=confirmed_qty self.qty_offset-=confirmed_qty
@property @property
def qty(self): def qty(self):
return self.tqty+self.qty_offset return self.tqty+self.qty_offset
@property
def expense(self):
return self.texpense+self.expense_offset
def reset(self, episode): def reset(self, episode):
#self.tqty=0 #self.tqty=0
+4 -1
View File
@@ -29,6 +29,8 @@ class Base_Distribution_Agent(BaseAgent,ABC):
""" """
Sets the amount of resources the agent should keep in business inventory Sets the amount of resources the agent should keep in business inventory
""" """
if target<0:
target=0
self.target=target self.target=target
@@ -46,7 +48,7 @@ class Base_Distribution_Agent(BaseAgent,ABC):
If err < 0 then agent needs to distribute resources If err < 0 then agent needs to distribute resources
""" """
err=self.business.inventory[self.resource]-self.target err=self.business.inventory[self.resource]-self.target
return err return int(err)
def distribute_resource(self,price_per,amount,cx_id): 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): def confirm_distribution(self,dis_qty,step):
income_per=self.income/self.qty income_per=self.income/self.qty
income_to_confirm=income_per*dis_qty income_to_confirm=income_per*dis_qty
income_to_confirm=round(income_to_confirm,2)
self.income_offset-=income_to_confirm self.income_offset-=income_to_confirm
self.qty_offset-=dis_qty self.qty_offset-=dis_qty
self.income_offset=round(self.income_offset,2) self.income_offset=round(self.income_offset,2)
+78 -62
View File
@@ -1,59 +1,63 @@
from .base_aquire_agent import Base_Aquire_Agent from .base_aquire_agent import Base_Aquire_Agent
import random import random
class Price_Believe_Aquire_Agent(Base_Aquire_Agent): class Price_Believe_Aquire_Agent(Base_Aquire_Agent):
""" """
Aquire agent with internal price believe system. Aquire agent with internal price believe system.
""" """
def __init__(self, simulation, business, resource, exchanges: list, lr, max_price_adj_rate) -> None: def __init__(self, simulation, business, resource, exchanges: list, lr, max_price_adj_rate) -> None:
super().__init__(simulation, business, resource, exchanges) super().__init__(simulation, business, resource, exchanges)
self.lr=lr self.lr = lr
self.max_price_adj_rate=max_price_adj_rate self.max_price_adj_rate = max_price_adj_rate
self.price_believe={i: 1 for i in range(len(self.exchanges))} 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_orders = {i: [] for i in range(len(self.exchanges))}
self.open_qty=0 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 # aquire based on current price believe
cx_id=self.select_best_cx() cx_id = self.select_best_cx()
order=self.order_resource(self.price_believe[cx_id],order_error*-1,cx_id) order = self.order_resource(
if not order==None: self.price_believe[cx_id], order_error*-1, cx_id)
self.register_order(cx_id,order) if not order == None:
self.register_order(cx_id, order)
else: else:
# order failed due to missing balance.. we need to adjust our price believe # order failed due to missing balance.. we need to adjust our price believe
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) self.collect_resource_from_cxs(self.resource)
self.update_believe(cx_id,-1) self.update_believe(cx_id, -1)
self.tick_open_orders() self.tick_open_orders()
def select_best_cx(self): def select_best_cx(self):
best_id=-1 best_id = -1
best=999999999 best = 999999999
for cx_id in range(len(self.exchanges)): for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id] cx = self.exchanges[cx_id]
available=(cx.get_total_supply(self.resource)>0) available = (cx.get_total_supply(self.resource) > 0)
if available: if available:
potential=1*self.price_believe[cx_id] potential = 1*self.price_believe[cx_id]
else: else:
continue continue
if potential<best: if potential < best:
best=potential best = potential
best_id=cx_id best_id = cx_id
if best_id==-1: if best_id == -1:
best_id=random.randint(0,len(self.exchanges)-1) best_id = random.randint(0, len(self.exchanges)-1)
return best_id return best_id
def register_order(self,cx_id,order): def register_order(self, cx_id, order):
self.open_orders[cx_id].append({ self.open_orders[cx_id].append({
'id': order.order_id, 'id': order.order_id,
'lifetime': self.max_price_adj_rate, 'lifetime': self.max_price_adj_rate,
'leaves': order.leaves_qty 'leaves': order.leaves_qty
}) })
if order.leaves_qty!=order.qty: if order.leaves_qty != order.qty:
self.update_trades() self.update_trades()
def tick_open_orders(self) -> int: def tick_open_orders(self) -> 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. Removes 1 from pending orders timeout timer and cancels timeed out orders.
Returns ids of orders that timeed out. Returns ids of orders that timeed out.
""" """
self.open_qty=0 self.open_qty = 0
for cx_id in range(len(self.exchanges)): for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id] cx = self.exchanges[cx_id]
cx_orders=self.open_orders[cx_id] cx_orders = self.open_orders[cx_id]
for i in cx_orders: for i in cx_orders:
# Check for each order if it is fullfiled or if it is timed # Check for each order if it is fullfiled or if it is timed
o=self.orders[cx_id][i["id"]] o = self.orders[cx_id][i["id"]]
leaves=o.leaves_qty leaves = o.leaves_qty
if o.leaves_qty==0: if o.leaves_qty == 0:
#order is done # order is done
self.open_orders[cx_id].remove(i) # remove order from open self.open_orders[cx_id].remove(i) # remove order from open
self.update_believe(cx_id,-1) # update price believe self.update_believe(cx_id, -1) # update price believe
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) self.collect_resource_from_cxs(self.resource)
continue continue
if not (i["leaves"]==leaves): if not (i["leaves"] == leaves):
#update in order # update in order
i["leaves"]=leaves i["leaves"] = leaves
self.update_trades() self.update_trades()
#reset lifetime # reset lifetime
i["lifetime"]=self.max_price_adj_rate i["lifetime"] = self.max_price_adj_rate
if i["lifetime"]>0: if i["lifetime"] > 0:
self.open_qty+=o.leaves_qty self.open_qty += o.leaves_qty
i["lifetime"]-=1 # subtract lifetime i["lifetime"] -= 1 # subtract lifetime
else: else:
# timeout # timeout
self.update_trades() self.update_trades()
buy = o.qty-o.leaves_qty
buyp=buy/o.qty modifier =0
sup = cx.total_supply[self.resource]+buy success=self.calc_order_success(cx,o)
if sup == 0: if success>=self.lp_threshold:
sup = 1 modifier=-1
coverage = buy/sup elif success<=self.hp_threshold:
# 50 % coverage limit modifier=1
modifier = (max([coverage,buyp])*2)-1
cx.cancel_order(i["id"]) cx.cancel_order(i["id"])
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) 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) 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. Updates the believe based on the modifier.
If positive will add lr to believe If positive will add lr to believe
If negative will sub lr to believe If negative will sub lr to believe
""" """
self.price_believe[cx_id]+=modifier*self.lr self.price_believe[cx_id] += modifier*self.lr
if self.price_believe[cx_id]<0: if self.price_believe[cx_id] < 0:
self.price_believe[cx_id]=0 self.price_believe[cx_id] = 0
def reset(self,episode): def reset(self, episode):
# Clean shop for today # Clean shop for today
for cx_id in range(len(self.exchanges)): for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id] cx = self.exchanges[cx_id]
cx_orders=self.open_orders[cx_id] cx_orders = self.open_orders[cx_id]
for i in cx_orders: for i in cx_orders:
cx.cancel_order(i["id"]) cx.cancel_order(i["id"])
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) self.collect_resource_from_cxs(self.resource)
# book keeping # book keeping
self.update_trades() self.update_trades()
self.open_orders={i: [] for i in range(len(self.exchanges))} self.open_orders = {i: [] for i in range(len(self.exchanges))}
self.orders={i: {} for i in range(len(self.exchanges))} self.orders = {i: {} for i in range(len(self.exchanges))}
return super().reset(episode) return super().reset(episode)
+26 -19
View File
@@ -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.price_believe = {i: 1 for i in range(len(self.exchanges))}
self.open_orders = {i: [] for i in range(len(self.exchanges))} self.open_orders = {i: [] for i in range(len(self.exchanges))}
self.open_qty = 0 self.open_qty = 0
self.lp_threshold=0.25
self.hp_threshold=0.90
def tick(self, step, episode): def tick(self, step, episode):
@@ -72,16 +74,12 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent):
if o.leaves_qty == 0: if o.leaves_qty == 0:
# order is done # order is done
self.open_orders[cx_id].remove(i) # remove order from open self.open_orders[cx_id].remove(i) # remove order from open
sold = o.qty-o.leaves_qty succsess=self.calc_order_success(cx,o)
if o.qty==0: modifier=0
o.qty=1 if succsess>=self.hp_threshold:
soldperc=sold/o.qty modifier=1
dem = cx.total_demand[self.resource]+sold elif succsess<=self.lp_threshold:
if dem == 0: modifier=-1
dem = 1
coverage = sold/dem
# 50 % coverage limit
modifier = (max([coverage,soldperc])*2)-1
self.update_believe(cx_id, modifier) # update price believe self.update_believe(cx_id, modifier) # update price believe
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) self.collect_resource_from_cxs(self.resource)
@@ -101,20 +99,29 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent):
else: else:
# timeout # timeout
self.update_trades() self.update_trades()
succsess=self.calc_order_success(cx,o)
sold = o.qty-o.leaves_qty modifier=0
soldperc=sold/o.qty if succsess>=self.hp_threshold:
dem = cx.total_demand[self.resource]+sold modifier=1
if dem == 0: elif succsess<=self.lp_threshold:
dem = 1 modifier=-1
coverage = sold/dem
# 50 % coverage limit
modifier = (max([coverage,soldperc])*2)-1
cx.cancel_order(i["id"]) cx.cancel_order(i["id"])
self.collect_balance_from_cxs() self.collect_balance_from_cxs()
self.collect_resource_from_cxs(self.resource) self.collect_resource_from_cxs(self.resource)
self.update_believe(cx_id, modifier) self.update_believe(cx_id, modifier)
self.open_orders[cx_id].remove(i) 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): def update_believe(self, cx_id, modifier):
""" """
+3 -3
View File
@@ -37,7 +37,7 @@ class Price_Believe_Business(Business):
self.update_income_per_unit(step) self.update_income_per_unit(step)
# calc descision # calc descision
orderForNewProds = 1 orderForNewProds = self.max_storage
if self.income_per_unit<=0 or self.expense_per_unit<=0: if self.income_per_unit<=0 or self.expense_per_unit<=0:
# dont have data # dont have data
retain=0 retain=0
@@ -47,7 +47,7 @@ class Price_Believe_Business(Business):
ie = 0 ie = 0
if ie > 1: if ie > 1:
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 retain=0
@@ -59,7 +59,7 @@ class Price_Believe_Business(Business):
self.aquire[k].set_target(v*orderForNewProds) self.aquire[k].set_target(v*orderForNewProds)
# update production # update production
targetUnit = self.production["amount"]*self.max_storage targetUnit = self.production["amount"]*orderForNewProds
self.craft.set_target(targetUnit) self.craft.set_target(targetUnit)
# set min distribute # set min distribute
+5 -1
View File
@@ -125,8 +125,12 @@ class Exchange():
Returns an order if the order is active. Returns None if submit has failed. Returns an order if the order is active. Returns None if submit has failed.
""" """
# calculate price for complete order fullfilment # calculate price for complete order fullfilment
prev=amount
amount=int(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 # Move resources into escrow