<filename>fixed_strategies/test.py
import matplotlib.pylab as plt
import os
import pandas as pd
from random import choice
from math import inf
from agent_test import Agent, Agent_C, Agent_K
from period import Period


def simulation(redemptions, costs, info_traders, simulations, periods, time_steps):

    # sort valuations from highest to lowest, costs from lowest to highest
    redemptions.sort(reverse=True)
    costs.sort()

    # calculates maximum surplus
    maximum_surplus = max_surplus(redemptions, costs, info_traders["traders"])

    # run certain amount of simulations
    for sim in range(simulations):

        # divide the number of agents participating in auction
        agents_in_auction = divide_traders(info_traders)

        # creates transaction period object
        trans_period = Period(agents_in_auction, time_steps, info_traders["min_price"],
                              info_traders["max_price"])

        # starts loop for the total amount of transaction periods
        for period in range(periods):

            trans_period.period = period

            # loop for amount of time steps per period
            for time_step in range(time_steps):

                # set activity agents
                trans_period.set_activity_traders(time_step)

                # checks if agents that are willing to shout are found
                if trans_period.active_agents:

                    # random agent to shout bid or ask
                    trader = trans_period.shout_offer()

                    # checks if transactions is possible
                    if trans_period.check_transaction():

                        # chooses radomly a traders from the opposite market side to exchange
                        second_trader = trans_period.pick_agents_transactions(
                            trader)

                        # checks if traders that shouted is buyer
                        if trader.type == "buyer":

                            # check if buyer has enough budget
                            if trans_period.check_buyer(trader, second_trader.price):

                                # procces transactions between the two traders
                                trans_period.procces_transaction(trader, second_trader,
                                                                 second_trader.price,
                                                                 period, time_step)

                                # check if traders can still participate in auction,
                                trans_period.check_competing_agents(trader,
                                                                    second_trader,
                                                                    redemptions,
                                                                    costs)

                        # checks if trader that shouted is seller
                        else:

                            # checks if the buyer has enough budget
                            if trans_period.check_buyer(second_trader,
                                                        second_trader.price):

                                # procces transaction between the two traders
                                trans_period.procces_transaction(second_trader, trader,
                                                                 second_trader.price,
                                                                 period, time_step)

                                # check if traders can still participate in auction
                                trans_period.check_competing_agents(second_trader,
                                                                    trader,
                                                                    redemptions,
                                                                    costs)

                    # check if trades are still possible
                    if trans_period.check_end_period():
                        break

            # set all agents "reseted" in auction and keep track of min max trade price
            trans_period.update_min_max_trade(period)
            trans_period.reset_agents_new_round(redemptions, costs)

        all_data_simulation(sim, trans_period.data_surplus,
                            trans_period.data_transactions,
                            trans_period.agents_in_auction)


def max_surplus(redemptions, costs, traders):
    """
    Calculates the maximum possible surplus
    """

    surplus = 0
    transactions = 0.5 * traders

    for redemption, cost in zip(redemptions, costs):
        if redemption >= cost:
            surplus += ((redemption - cost) * transactions)

    return surplus


def divide_traders(info_traders):
    """
    Divide traders equally into buyers and sellers
    and set the right proportions of strategies '
    among the market sides
    """

    agents = []
    amount_side = info_traders["proportions"] * info_traders["traders"]
    flag = 1

    # divide the kaplan agents on the demand side
    for kaplan in range(int(info_traders["proportions_buy"] * amount_side)):
        agents.append(Agent_K(flag, "buyer", info_traders["redemptions"],
                              info_traders["time_frac"],
                              info_traders["spread_ratio"],
                              info_traders["profit_perc"]))
        flag += 1

    # divide ZI_C agents on the demand side
    for zi in range(int((1 - info_traders["proportions_buy"]) * amount_side)):
        agents.append(Agent_C(flag, "buyer", info_traders["redemptions"]))
        flag += 1

    # divide Kaplan agents on the supply side
    for kaplan in range(int(info_traders["proportions_sel"] * amount_side)):
        agents.append(Agent_K(flag, "seller", info_traders["costs"],
                              info_traders["time_frac"],
                              info_traders["spread_ratio"],
                              info_traders["profit_perc"]))
        flag += 1

    # divide ZI_C agents on the supply side
    for zi in range(int((1 - info_traders["proportions_sel"]) * amount_side)):
        agents.append(Agent_C(flag, "seller", info_traders["costs"]))
        flag += 1

    return agents


def all_data_simulation(id, surplus_periods, prices_periods, agents):
    """
    Writes all collected data to a csv file
    """

    # makes folder for simulations, if it does not yet exist
    if not os.path.exists(f"simulations/{id + 1}"):
        os.mkdir(f"simulations/{id + 1}")

    # loop for all the data collectied in transaction periods
    for period, data in enumerate(prices_periods):

        # makes folder for every period, if it does not yet exist
        if not os.path.exists(f"simulations/{id + 1}/period{period + 1}"):
            os.mkdir(f"simulations/{id + 1}/period{period + 1}")

        # makes data frame from transaction prices, surplus and quantity
        dataframe_prices = pd.DataFrame(data)
        dataframe_surplus = pd.DataFrame(surplus_periods[period])
        all_data = pd.concat([dataframe_prices, dataframe_surplus], axis=1)

        # writes the data frame to a csv file
        all_data.to_csv(
            f"simulations/{id + 1}/period{period + 1}/data_period{period + 1}.csv",
            index=False, na_rep="")

        # track variables for data agents in the same period
        data_period_all_agents = []
        info_agents = []

        # loop over all agents
        for agent in agents:

            # makes data frame of data agent for the given period
            data_agent = pd.DataFrame(agent.data[period])

            # appen dataframe and corresponding info to a list
            data_period_all_agents.append(data_agent)
            info_agents.append(f"{agent.name} {agent.type} {agent.id}")

        # concat all dataframes together, index is the agent's strategy,
        # market side and id
        data_agents = pd.concat(data_period_all_agents, keys=info_agents)

        # write dataframe to csv file
        data_agents.to_csv(
            f"simulations/{id + 1}/period{period + 1}/data_agents{period + 1}.csv")


if __name__ == "__main__":

    # reads the valuations from csv
    # and stores redemptions and costs in seperate list
    valuations = pd.read_csv("../data/valuations.csv")
    redemptions = valuations["redemptions"].tolist()
    costs = valuations["costs"].tolist()

    # ensures proper value for minimum shout price
    min_price = ""
    while not min_price.isdigit() or int(min_price) >= min(costs) or int(min_price) < 0:
        min_price = input("Enter the minimum price that a trader can shout: ")

    min_price = int(min_price)

    # ensures proper value for maximum shout price
    max_price = ""
    while not max_price.isdigit() or int(max_price) <= max(redemptions):
        max_price = input("Enter the maximum price that a trader can shout: ")

    max_price = int(max_price)

    # ensures proper value for amount of simulations
    simulations = ""
    while not simulations.isdigit() or int(simulations) <= 0:
        simulations = input("Enter the amount of simulations: ")

    simulations = int(simulations)

    # ensures propor value for amount of periods
    periods = ""
    while not periods.isdigit() or int(periods) <= 0:
        periods = input("Enter the amount of transaction periods: ")

    periods = int(periods)

    # ensures propor value for amount of time steps
    time_steps = ""
    while not time_steps.isdigit() or int(time_steps) <= 0:
        time_steps = input(
            "Enter the amount of time steps for each transaction period: ")

    time_steps = int(time_steps)

    # ensures proper value for time fraction Kaplan agents
    time_frac = ""
    while ("." not in time_frac or round(float(time_frac), 2) <= 0
           or round(float(time_frac), 2) > 1):

        time_frac = input("Enter time fraction Kaplan agents: ")

    time_frac = round(float(time_frac), 2)

    # ensures proper value for spread_ratio Kaplan agents
    spread_ratio = ""
    while ("." not in spread_ratio or round(float(spread_ratio), 2) <= 0
           or round(float(spread_ratio), 2) > 1):

        spread_ratio = input("Enter spread ratio Kaplan agents: ")

    spread_ratio = round(float(spread_ratio), 2)

    # ensures proper value for profit_perc Kaplan agents
    profit_perc = ""
    while ("." not in profit_perc or round(float(profit_perc), 2) <= 0
           or round(float(profit_perc), 2) > 1):

        profit_perc = input("Enter profit percentage Kaplan agents: ")

    profit_perc = round(float(profit_perc), 2)

    prop_buy = ""
    while ("." not in prop_buy or round(float(prop_buy), 1) < 0.5
           or round(float(prop_buy), 1) > 0.7):

        prop_buy = input(
            "Enter the proportion of Kaplan agents on the demand side: ")

    prop_buy = round(float(prop_buy), 1)

    prop_sel = ""
    while ("." not in prop_sel or round(float(prop_sel), 1) < 0.5
           or round(float(prop_sel), 1) > 0.7):

        prop_sel = input(
            "Enter the proportion of Kaplan agents on the supply side: ")

    prop_sel = round(float(prop_sel))

    traders = ""

    while (not traders.isdigit() or int(traders) <= 0 or int(traders) % 2 > 0
    or (int(traders) / 2) % 2 > 0 or isinstance((int(traders) / 2) * prop_buy, int)
            or isinstance((int(traders) / 2) * prop_sel, int)):

        traders = input("Enter the total amount of traders: ")

    traders = int(traders)

    # collect all input (time_frac: 0.2, spread_ratio: 0.15 and profit_perc: 0.02)
    # doet het tot nu toe goed.
    info_traders = {"redemptions": redemptions,
                    "costs": costs,
                    "max_price": max_price,
                    "min_price": min_price,
                    "traders": traders,
                    "proportions": 0.5,
                    "proportions_sel": prop_sel,
                    "proportions_buy": prop_buy,
                    "time_frac": time_frac,
                    "spread_ratio": spread_ratio,
                    "profit_perc": profit_perc}

    simulation(redemptions, costs, info_traders,
               simulations, periods, time_steps)

<filename>fixed_strategies/test.py
import matplotlib.pylab as plt
import os
import pandas as pd
from random import choice
from math import inf
from agent_test import Agent, Agent_C, Agent_K
from period import Period


def simulation(redemptions, costs, info_traders, simulations, periods, time_steps):

    # sort valuations from highest to lowest, costs from lowest to highest
    redemptions.sort(reverse=True)
    costs.sort()

    # calculates maximum surplus
    maximum_surplus = max_surplus(redemptions, costs, info_traders["traders"])

    # run certain amount of simulations
    for sim in range(simulations):

        # divide the number of agents participating in auction
        agents_in_auction = divide_traders(info_traders)

        # creates transaction period object
        trans_period = Period(agents_in_auction, time_steps, info_traders["min_price"],
                              info_traders["max_price"])

        # starts loop for the total amount of transaction periods
        for period in range(periods):

            trans_period.period = period

            # loop for amount of time steps per period
            for time_step in range(time_steps):

                # set activity agents
                trans_period.set_activity_traders(time_step)

                # checks if agents that are willing to shout are found
                if trans_period.active_agents:

                    # random agent to shout bid or ask
                    trader = trans_period.shout_offer()

                    # checks if transactions is possible
                    if trans_period.check_transaction():

                        # chooses radomly a traders from the opposite market side to exchange
                        second_trader = trans_period.pick_agents_transactions(
                            trader)

                        # checks if traders that shouted is buyer
                        if trader.type == "buyer":

                            # check if buyer has enough budget
                            if trans_period.check_buyer(trader, second_trader.price):

                                # procces transactions between the two traders
                                trans_period.procces_transaction(trader, second_trader,
                                                                 second_trader.price,
                                                                 period, time_step)

                                # check if traders can still participate in auction,
                                trans_period.check_competing_agents(trader,
                                                                    second_trader,
                                                                    redemptions,
                                                                    costs)

                        # checks if trader that shouted is seller
                        else:

                            # checks if the buyer has enough budget
                            if trans_period.check_buyer(second_trader,
                                                        second_trader.price):

                                # procces transaction between the two traders
                                trans_period.procces_transaction(second_trader, trader,
                                                                 second_trader.price,
                                                                 period, time_step)

                                # check if traders can still participate in auction
                                trans_period.check_competing_agents(second_trader,
                                                                    trader,
                                                                    redemptions,
                                                                    costs)

                    # check if trades are still possible
                    if trans_period.check_end_period():
                        break

            # set all agents "reseted" in auction and keep track of min max trade price
            trans_period.update_min_max_trade(period)
            trans_period.reset_agents_new_round(redemptions, costs)

        all_data_simulation(sim, trans_period.data_surplus,
                            trans_period.data_transactions,
                            trans_period.agents_in_auction)


def max_surplus(redemptions, costs, traders):
    """
    Calculates the maximum possible surplus
    """

    surplus = 0
    transactions = 0.5 * traders

    for redemption, cost in zip(redemptions, costs):
        if redemption >= cost:
            surplus += ((redemption - cost) * transactions)

    return surplus


def divide_traders(info_traders):
    """
    Divide traders equally into buyers and sellers
    and set the right proportions of strategies '
    among the market sides
    """

    agents = []
    amount_side = info_traders["proportions"] * info_traders["traders"]
    flag = 1

    # divide the kaplan agents on the demand side
    for kaplan in range(int(info_traders["proportions_buy"] * amount_side)):
        agents.append(Agent_K(flag, "buyer", info_traders["redemptions"],
                              info_traders["time_frac"],
                              info_traders["spread_ratio"],
                              info_traders["profit_perc"]))
        flag += 1

    # divide ZI_C agents on the demand side
    for zi in range(int((1 - info_traders["proportions_buy"]) * amount_side)):
        agents.append(Agent_C(flag, "buyer", info_traders["redemptions"]))
        flag += 1

    # divide Kaplan agents on the supply side
    for kaplan in range(int(info_traders["proportions_sel"] * amount_side)):
        agents.append(Agent_K(flag, "seller", info_traders["costs"],
                              info_traders["time_frac"],
                              info_traders["spread_ratio"],
                              info_traders["profit_perc"]))
        flag += 1

    # divide ZI_C agents on the supply side
    for zi in range(int((1 - info_traders["proportions_sel"]) * amount_side)):
        agents.append(Agent_C(flag, "seller", info_traders["costs"]))
        flag += 1

    return agents


def all_data_simulation(id, surplus_periods, prices_periods, agents):
    """
    Writes all collected data to a csv file
    """

    # makes folder for simulations, if it does not yet exist
    if not os.path.exists(f"simulations/{id + 1}"):
        os.mkdir(f"simulations/{id + 1}")

    # loop for all the data collectied in transaction periods
    for period, data in enumerate(prices_periods):

        # makes folder for every period, if it does not yet exist
        if not os.path.exists(f"simulations/{id + 1}/period{period + 1}"):
            os.mkdir(f"simulations/{id + 1}/period{period + 1}")

        # makes data frame from transaction prices, surplus and quantity
        dataframe_prices = pd.DataFrame(data)
        dataframe_surplus = pd.DataFrame(surplus_periods[period])
        all_data = pd.concat([dataframe_prices, dataframe_surplus], axis=1)

        # writes the data frame to a csv file
        all_data.to_csv(
            f"simulations/{id + 1}/period{period + 1}/data_period{period + 1}.csv",
            index=False, na_rep="")

        # track variables for data agents in the same period
        data_period_all_agents = []
        info_agents = []

        # loop over all agents
        for agent in agents:

            # makes data frame of data agent for the given period
            data_agent = pd.DataFrame(agent.data[period])

            # appen dataframe and corresponding info to a list
            data_period_all_agents.append(data_agent)
            info_agents.append(f"{agent.name} {agent.type} {agent.id}")

        # concat all dataframes together, index is the agent's strategy,
        # market side and id
        data_agents = pd.concat(data_period_all_agents, keys=info_agents)

        # write dataframe to csv file
        data_agents.to_csv(
            f"simulations/{id + 1}/period{period + 1}/data_agents{period + 1}.csv")


if __name__ == "__main__":

    # reads the valuations from csv
    # and stores redemptions and costs in seperate list
    valuations = pd.read_csv("../data/valuations.csv")
    redemptions = valuations["redemptions"].tolist()
    costs = valuations["costs"].tolist()

    # ensures proper value for minimum shout price
    min_price = ""
    while not min_price.isdigit() or int(min_price) >= min(costs) or int(min_price) < 0:
        min_price = input("Enter the minimum price that a trader can shout: ")

    min_price = int(min_price)

    # ensures proper value for maximum shout price
    max_price = ""
    while not max_price.isdigit() or int(max_price) <= max(redemptions):
        max_price = input("Enter the maximum price that a trader can shout: ")

    max_price = int(max_price)

    # ensures proper value for amount of simulations
    simulations = ""
    while not simulations.isdigit() or int(simulations) <= 0:
        simulations = input("Enter the amount of simulations: ")

    simulations = int(simulations)

    # ensures propor value for amount of periods
    periods = ""
    while not periods.isdigit() or int(periods) <= 0:
        periods = input("Enter the amount of transaction periods: ")

    periods = int(periods)

    # ensures propor value for amount of time steps
    time_steps = ""
    while not time_steps.isdigit() or int(time_steps) <= 0:
        time_steps = input(
            "Enter the amount of time steps for each transaction period: ")

    time_steps = int(time_steps)

    # ensures proper value for time fraction Kaplan agents
    time_frac = ""
    while ("." not in time_frac or round(float(time_frac), 2) <= 0
           or round(float(time_frac), 2) > 1):

        time_frac = input("Enter time fraction Kaplan agents: ")

    time_frac = round(float(time_frac), 2)

    # ensures proper value for spread_ratio Kaplan agents
    spread_ratio = ""
    while ("." not in spread_ratio or round(float(spread_ratio), 2) <= 0
           or round(float(spread_ratio), 2) > 1):

        spread_ratio = input("Enter spread ratio Kaplan agents: ")

    spread_ratio = round(float(spread_ratio), 2)

    # ensures proper value for profit_perc Kaplan agents
    profit_perc = ""
    while ("." not in profit_perc or round(float(profit_perc), 2) <= 0
           or round(float(profit_perc), 2) > 1):

        profit_perc = input("Enter profit percentage Kaplan agents: ")

    profit_perc = round(float(profit_perc), 2)

    prop_buy = ""
    while ("." not in prop_buy or round(float(prop_buy), 1) < 0.5
           or round(float(prop_buy), 1) > 0.7):

        prop_buy = input(
            "Enter the proportion of Kaplan agents on the demand side: ")

    prop_buy = round(float(prop_buy), 1)

    prop_sel = ""
    while ("." not in prop_sel or round(float(prop_sel), 1) < 0.5
           or round(float(prop_sel), 1) > 0.7):

        prop_sel = input(
            "Enter the proportion of Kaplan agents on the supply side: ")

    prop_sel = round(float(prop_sel))

    traders = ""

    while (not traders.isdigit() or int(traders) <= 0 or int(traders) % 2 > 0
    or (int(traders) / 2) % 2 > 0 or isinstance((int(traders) / 2) * prop_buy, int)
            or isinstance((int(traders) / 2) * prop_sel, int)):

        traders = input("Enter the total amount of traders: ")

    traders = int(traders)

    # collect all input (time_frac: 0.2, spread_ratio: 0.15 and profit_perc: 0.02)
    # doet het tot nu toe goed.
    info_traders = {"redemptions": redemptions,
                    "costs": costs,
                    "max_price": max_price,
                    "min_price": min_price,
                    "traders": traders,
                    "proportions": 0.5,
                    "proportions_sel": prop_sel,
                    "proportions_buy": prop_buy,
                    "time_frac": time_frac,
                    "spread_ratio": spread_ratio,
                    "profit_perc": profit_perc}

    simulation(redemptions, costs, info_traders,
               simulations, periods, time_steps)

# sort valuations from highest to lowest, costs from lowest to highest # calculates maximum surplus # run certain amount of simulations # divide the number of agents participating in auction # creates transaction period object # starts loop for the total amount of transaction periods # loop for amount of time steps per period # set activity agents # checks if agents that are willing to shout are found # random agent to shout bid or ask # checks if transactions is possible # chooses radomly a traders from the opposite market side to exchange # checks if traders that shouted is buyer # check if buyer has enough budget # procces transactions between the two traders # check if traders can still participate in auction, # checks if trader that shouted is seller # checks if the buyer has enough budget # procces transaction between the two traders # check if traders can still participate in auction # check if trades are still possible # set all agents "reseted" in auction and keep track of min max trade price Calculates the maximum possible surplus Divide traders equally into buyers and sellers     and set the right proportions of strategies '     among the market sides # divide the kaplan agents on the demand side # divide ZI_C agents on the demand side # divide Kaplan agents on the supply side # divide ZI_C agents on the supply side Writes all collected data to a csv file # makes folder for simulations, if it does not yet exist # loop for all the data collectied in transaction periods # makes folder for every period, if it does not yet exist # makes data frame from transaction prices, surplus and quantity # writes the data frame to a csv file # track variables for data agents in the same period # loop over all agents # makes data frame of data agent for the given period # appen dataframe and corresponding info to a list # concat all dataframes together, index is the agent's strategy, # market side and id # write dataframe to csv file # reads the valuations from csv # and stores redemptions and costs in seperate list # ensures proper value for minimum shout price # ensures proper value for maximum shout price # ensures proper value for amount of simulations # ensures propor value for amount of periods # ensures propor value for amount of time steps # ensures proper value for time fraction Kaplan agents # ensures proper value for spread_ratio Kaplan agents # ensures proper value for profit_perc Kaplan agents # collect all input (time_frac: 0.2, spread_ratio: 0.15 and profit_perc: 0.02) # doet het tot nu toe goed.