a lot of fixes

This commit is contained in:
2023-06-26 11:31:47 +02:00
parent 966db6e5ad
commit f60dca6367
23 changed files with 338 additions and 45 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"ansible.python.interpreterPath": "c:\\Users\\handg\\miniconda3\\python.exe"
}

16
db copy/commoditys.yml Normal file
View File

@@ -0,0 +1,16 @@
kind: commodity
spec:
- name: "Gem"
max_world_price: 100
- name: "Food"
max_world_price: 5
- name: "Grain"
max_world_price: 5
- name: "Fruit"
max_world_price: 1

5
db copy/demand-tags.yml Normal file
View File

@@ -0,0 +1,5 @@
kind: demand
spec:
- name: basic
res:
- 'Food': 1

17
db copy/production.yml Normal file
View File

@@ -0,0 +1,17 @@
kind: production
spec:
- name: Food
amount: 100
prod:
- "Grain": 1
- "Fruit": 1
- name: Grain
amount: 1000
prod:
- Raw_Agriculture_Plot: 1
- name: Fruit
amount: 100
prod:
- Raw_Agriculture_Plot: 1

15
db copy/world-tags.yml Normal file
View File

@@ -0,0 +1,15 @@
kind: world
spec:
- name: gems
res:
- 'Raw_Gem': 15
- name: grass
res:
- 'Raw_Agriculture_Plot': 0.3
- name: forrest
res:
- 'Raw_Agriculture_Plot': 1

1
db copy/world.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@ spec:
- name: "Grain"
max_world_price: 1
max_world_price: 5
- name: "Fruit"

View File

@@ -1,17 +1,20 @@
kind: production
spec:
- name: Food
amount: 100
prod:
- "Grain": 1
- "Fruit": 1
- name: Grain
amount: 1
amount: 10
prod:
- Raw_Agriculture_Plot: 1
- name: Fruit
amount: 10
prod:
- Raw_Agriculture_Plot: 1
- name: Fruit
amount: 1
- name: Food
amount: 5
prod:
- Raw_Agriculture_Plot: 1
- Fruit: 1
- Grain: 1

View File

@@ -6,10 +6,10 @@ spec:
- name: grass
res:
- 'Raw_Agriculture_Plot': 0.3
- 'Raw_Agriculture_Plot': 100
- name: forrest
res:
- 'Raw_Agriculture_Plot': 1
- 'Raw_Agriculture_Plot': 100

18
docker-compose.yml Normal file
View File

@@ -0,0 +1,18 @@
version: '3'
services:
database:
image: 'postgres:14'
ports:
- 15432:5432
environment:
POSTGRES_PASSWORD: econ
POSTGRES_USER: admin
POSTGRES_DB: econ
networks:
- postgres-network
networks:
postgres-network:
driver: bridge

View File

@@ -23,4 +23,16 @@ class BaseAgent(ABC):
Resets agent to new episode.
"""
assert "No reset method has been provided"
pass
pass
def unregister(self):
"""
Disables agent by removing it from the simulation
"""
self.simulation.unregister_agent(id)
def register(self):
"""
Enables agent by adding it to the simulation:
"""
self.simulation.register_agent(self.id,self.tick,self.reset)

View File

@@ -9,7 +9,7 @@ class Base_Aquire_Agent(BaseAgent,ABC):
Agent for aquire of resources.
business: Business to aquire resources for.
resource: Resource to aquire.
exchanges: list of exchanges to aquire resources from
exchanges: list of exchanges to acquire resources from
"""
self.business=business
self.resource=resource

View File

@@ -90,8 +90,11 @@ class Base_Distribution_Agent(BaseAgent,ABC):
cx=self.exchanges[cx_id]
orders=self.orders[cx_id]
if len(orders)>0:
for o in orders:
trades.append(cx.order_trades_map[o.order_id])
for k,o in orders.items():
if k in cx.order_trades_map:
trades.append(cx.order_trades_map[k])
self.trades=trades
return trades

View File

@@ -8,7 +8,7 @@ class Price_Believe_Aquire_Agent(Base_Aquire_Agent):
super().__init__(simulation, business, resource, exchanges)
self.lr=lr
self.max_price_adj_rate=max_price_adj_rate
self.price_believe={i: 0 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_qty=0
@@ -18,7 +18,7 @@ class Price_Believe_Aquire_Agent(Base_Aquire_Agent):
order_error=self.open_qty+self.target_error()
if order_error<0:
# aquire based on current price belive
# 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:
@@ -32,10 +32,14 @@ class Price_Believe_Aquire_Agent(Base_Aquire_Agent):
def select_best_cx(self):
best_id=-1
best=0
best=999999999
for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id]
potential=cx.get_total_supply(self.resource)*self.price_believe[cx_id]
available=(cx.get_total_supply(self.resource)>0)
if available:
potential=1*self.price_believe[cx_id]
else:
continue
if potential<best:
best=potential
best_id=cx_id

View File

@@ -8,7 +8,7 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent):
super().__init__(simulation, business, resource, exchanges)
self.lr=lr
self.max_price_adj_rate=max_price_adj_rate
self.price_believe={i: 0 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_qty=0
@@ -24,10 +24,14 @@ class Price_Believe_Distribiute_Agent(Base_Distribution_Agent):
def select_best_cx(self):
best_id=-1
best=0
best=-1
for cx_id in range(len(self.exchanges)):
cx=self.exchanges[cx_id]
potential=cx.get_total_supply(self.resource)*self.price_believe[cx_id]
available=(cx.get_total_demand(self.resource)>0)
if available:
potential=1*self.price_believe[cx_id]
else:
continue
if potential>best:
best=potential
best_id=cx_id

View File

@@ -2,6 +2,7 @@ from .base_business import Business
from ..agents.price_believe_aquire import Price_Believe_Aquire_Agent
from ..agents.price_believe_distribute import Price_Believe_Distribiute_Agent
from ..agents.autoproduction import AutoProductionAgent
class Price_Believe_Business(Business):
def __init__(self, id, production, balance,exchange,simulation) -> None:
super().__init__(id, production, balance)
@@ -21,7 +22,7 @@ class Price_Believe_Business(Business):
def tick_business_decisions(self,step):
for comp in self.production["prod"]:
for k,v in comp.items():
modifier=self.craft.worker+1
modifier=1
self.aquire[k].set_target(v*modifier)
max_amount=self.production["amount"]*5
self.craft.set_target(max_amount)
@@ -29,3 +30,8 @@ class Price_Believe_Business(Business):
def resource_in_possesion(self):
return self.distribute.open_qty+self.inventory[self.production["name"]]
def close_business(self):
for a in self.aquire:
a.unregister()
self.distribute.unregister()
self.production.unregister()

View File

@@ -1,4 +1,5 @@
from abc import ABC
import log
class Business(ABC):
def __init__(self,id,production,balance) -> None:
"""production (dict): {
@@ -43,3 +44,15 @@ class Business(ABC):
"""
assert "no business episode tick method has been created"
def close_business(self):
assert "close_business has not been provided"
def log(self,episode,episode_length,step):
data={}
data["id"]=self.id
data["episode"]=episode
data["step"]=step
data["tstep"]=step+episode*episode_length
data["production"]=self.production["name"]
data["balance"]=self.balance
log.BUSINESSData.append(data)

View File

@@ -69,7 +69,7 @@ class Cell:
self.exchange.reset()
for supply_key,value in self.world.items():
self.exchange.add_to_account(self.name,supply_key,value)
self.exchange.submit_order(self.name,supply_key,value,0,Side.SELL)
self.exchange.submit_order(self.name,supply_key,value,1,Side.SELL)

View File

@@ -1,5 +1,13 @@
_bal="balance"
from lightmatchingengine.lightmatchingengine import LightMatchingEngine,Side,Trade,Order,OrderBook
import log
from influxdb_client.client.write_api import SYNCHRONOUS
from influxdb_client import InfluxDBClient, Point
import time
import pandas as pd
import uuid
software_start=int(time.time())
class Exchange():
"""
Basic Commodity exchange.
@@ -110,6 +118,7 @@ class Exchange():
Returns an order if the order is active. Returns None if submit has failed.
"""
# calculate price for complete order fullfilment
amount=int(amount)
full_price=price*amount
@@ -219,15 +228,15 @@ class Exchange():
for k,v in order_book.bids.items():
self.demand[resource][k]=0
for o in v:
self.demand[resource][k]+=o.qty
self.total_demand[resource]+=o.qty
self.demand[resource][k]+=o.leaves_qty
self.total_demand[resource]+=o.leaves_qty
self.supply[resource]={}
self.total_supply[resource]=0
for k,v in order_book.asks.items():
self.supply[resource][k]=0
for o in v:
self.supply[resource][k]+=o.qty
self.total_supply[resource]+=o.qty
self.supply[resource][k]+=o.leaves_qty
self.total_supply[resource]+=o.leaves_qty
self.best_ask[resource]=best_ask
@@ -249,4 +258,61 @@ class Exchange():
def get_total_supply(self,resource):
if resource in self.total_supply:
return self.total_supply[resource]
return 0
return 0
def log_step(self,name,episode,episode_length,step):
timepoint=episode*episode_length+step
localStepDB={}
data={}
data["cxid"]=name
data["episode"]=episode
data["step"]=step
data["tstep"]=timepoint
data["instrm"]="None"
data["best_ask"]=-1
data["best_bid"]=-1
data["total_demand"]=-1
data["total_supply"]=-1
data["market_rate"]=-1
for id,order in self.orders.items():
t=data.copy()
t["instrm"]=order.instmt
localStepDB[order.instmt]=t
## add best ask/best bid
for item , value in self.best_ask.items():
if value!=None:
localStepDB[item]["best_ask"]=value
for item , value in self.best_bid.items():
if value!=None:
localStepDB[item]["best_bid"]=value
#demand supply
for item , value in self.total_demand.items():
if value!=None:
localStepDB[item]["total_demand"]=value
for item , value in self.total_supply.items():
if value!=None:
localStepDB[item]["total_supply"]=value
#last market rate
for item , value in self.market_rate.items():
if value!=None:
localStepDB[item]["market_rate"]=value
for id,item in localStepDB.items():
log.EXBooksData.append(item)
return data
def log_episode(self,name,episode):
for t in self.executed_trades:
data={}
data["id"]=uuid.uuid4()
data["cxid"]=name
data["episode"]=episode
data["order_id"]=t.order_id
data["instmt"]=t.instmt
data["price"]=t.trade_price
data["qty"]=t.trade_qty
data["side"]=t.trade_side
log.EXTradeData.append(data)

View File

@@ -3,6 +3,9 @@ from .commoditys import commoditys as cm
from .exchange import Exchange
from .business import Price_Believe_Business
import uuid
import time
class Simulation():
"""
Class for controlling the different calculation steps of the Simulation.
@@ -11,8 +14,9 @@ class Simulation():
self.tick_funcs={}
self.reset_funcs={}
self.tick_count=0
self.episode_count=0
self.episode_count=-1
self.cells={}
self.populated_cells={}
self.businesses=[]
self.production_util={}
for k in cm.productions.items():
@@ -37,6 +41,14 @@ class Simulation():
self.tick_funcs[id]=tickfunc
self.reset_funcs[id]=resetfunc
def unregister_agent(self,id):
"""
Unregisters agent
"""
self.tick_funcs.pop(id,None)
self.reset_funcs.pop(id,None)
def tick_agents_random_order(self):
"""
@@ -53,22 +65,32 @@ class Simulation():
"""
Executes a tick of the simulation
"""
self.tick_agents_random_order()
start=time.time()
for cell_id,c in self.cells.items():
c.setup_demand_for_step(episode_length)
setup=time.time()
self.tick_agents_random_order()
agentstep=time.time()
for b in self.businesses:
b.tick(self.tick_count)
if b.balance<=0:
self.close_business(b.id)
busstep=time.time()
self.tick_count+=1
self.log_cxs_tick(episode_length)
self.log_business_tick(episode_length)
def reset(self):
"""
Resets all agents to new Episode
"""
self.log_cxs_episode()
for k,v in self.reset_funcs.items():
v(self.episode_count)
for cell_id,cell in self.cells.items():
cell.setup_supply_for_episode()
self.tick_count=0
self.episode_count+=1
@@ -82,14 +104,15 @@ class Simulation():
under.append(k)
return under
def create_bussiness(self):
def create_bussiness(self,min_available_per_prod):
"""
Create a new business based on given econemy state.
Return Business
"""
selected_prod=None
# Create a business for every production rule out there
under_prods=self.get_underutelized_prods(1)
under_prods=self.get_underutelized_prods(min_available_per_prod)
if len(under_prods)>0:
# we need to create more businesses
selected_prod=random.choice(under_prods)
@@ -103,11 +126,23 @@ class Simulation():
cell_id=random.choice(cells)
cell=self.cells[cell_id]
cxs=[cell.exchange,self.cx]
self.populated_cells[cell_id]=True
business=Price_Believe_Business.Price_Believe_Business(uuid.uuid4(),prod,1000,cxs,self)
self.businesses.append(business)
self.production_util[selected_prod]+=1
return business
def remove_business(self,id):
bus=None
for i,busl in self.businesses:
if busl.id==id:
bus=i
break
bus.close_business()
self.businesses.remove(bus)
def get_max_profit_prod(self):
"""
Returns the prod with the highest profit in last episode
@@ -120,7 +155,7 @@ class Simulation():
if diff>profit:
profit=diff
prod=b.production
return prod
return prod["id"]
@@ -146,4 +181,24 @@ class Simulation():
cell_score[cell.name]+=cx.get_total_demand(prod["name"])
cell_score[cell.name]-=cx.get_total_supply(prod["name"])
max_keys = [key for key, value in cell_score.items() if value == max(cell_score.values())]
return max_keys
return max_keys
def log_cxs_tick(self,epi_length):
for id,_ in self.populated_cells.items():
cell=self.cells[id]
lcx=cell.exchange
name="lcx_{}".format(id)
lcx.log_step(name,self.episode_count,epi_length,self.tick_count)
self.cx.log_step("cx",self.episode_count,epi_length,self.tick_count)
def log_cxs_episode(self):
for id,_ in self.populated_cells.items():
cell=self.cells[id]
lcx=cell.exchange
name="lcx_{}".format(id)
lcx.log_episode(name,self.episode_count)
self.cx.log_episode("cx",self.episode_count)
def log_business_tick(self,episode_length):
for bus in self.businesses:
bus.log(self.episode_count,episode_length,self.tick_count)

41
log/__init__.py Normal file
View File

@@ -0,0 +1,41 @@
import influxdb_client, os, time
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS
from sqlalchemy import create_engine
import pandas as pd
token = "AcU0_L5vtfH-9ycHnk0txF3jgHIcWRcMOElzAVtIrAGXC0oNSjwZUzPBsWCBZHNbaJmr-9x34E1Hycow59MnQg=="
org = "econ"
url = "http://localhost:8086"
bucket="econ"
posturl='postgresql://admin:econ@localhost:15432/econ'
write_client = None
EXInit=False
EXBooksData=[]
EXTradeData=[]
BUSINESSData=[]
def get_client():
global write_client
if write_client==None:
write_client=influxdb_client.InfluxDBClient(url=url, token=token, org=org)
return write_client
def writeEXData():
db = create_engine(posturl)
conn = db.connect()
df=pd.DataFrame(EXBooksData)
df.to_sql('cx_books', con=conn, if_exists='replace',
index=False)
df=pd.DataFrame(EXTradeData)
df.to_sql("cx_trades",con=conn, if_exists='replace',
index=False)
conn.close()
def writeBusinessData():
db = create_engine(posturl)
conn = db.connect()
df=pd.DataFrame(BUSINESSData)
df.to_sql('business', con=conn, if_exists='replace',
index=False)
conn.close()

19
main.py
View File

@@ -4,7 +4,8 @@ from econ.simulation import Simulation
from econ.business.Price_Believe_Business import Price_Believe_Business
from econ.commoditys import commoditys
from econ.cells import db, cell
import log
from tqdm import tqdm
db.load_world("db/world.json")
commoditys.search_yaml_files()
@@ -30,11 +31,17 @@ cx.submit_order(2,"Gem",1,10,Side.SELL)
sim=Simulation()
sim.set_cells(cells)
sim.reset()
sim.tick(1)
#sim.tick(1)
# create info
while len(sim.get_underutelized_prods(1))>0:
sim.create_bussiness()
sim.reset()
for i in range(1000):
sim.tick(1000)
sim.create_bussiness(1)
#sim.reset()
for a in tqdm(range(30)):
for i in range(100):
sim.tick(100)
sim.reset()
sim.create_bussiness(1)
log.writeEXData()
log.writeBusinessData()
print("help")

View File

@@ -1 +1,5 @@
lightmatchingengine
lightmatchingengine
pyyaml
influxdb-client
pandas
sqlalchemy