Skip to main content
Version: 1.3.0

Agents

The agent field allows you to create agents in the simulator and map them to an address on the chain. The agent has to be assigned a class which tells the simulator what kind of actions the agent will be performing.

Besides that you can also specify holdings for the agent. The holdings have to specify three fields:

  • token
  • amount
  • mint
  • settings

The token field has to be set to a string that maps to the name of an ERC20 token. This token has to also be specified in the tokens field.

An amount will tell the simulator how much this user is holding (if the mint field is set to False we assume the user already has this). Make sure the user has the specified amount of tokens available at the specified starting block.

When the mint function is set to true, this setting will tell the simulator that it needs to mint the token balance. If the user already has some tokens on the specified starting block, this on-chain value will be overwritten and the simulator will set the agents balance to the specified amount. When the mint function is set to false, the minting is not performed, and the agents balance will be the value that existed on-chain at the starting block.

Optionally, a models list may be defined. This is a list of strings whose values are equal to a model alias defined in the configuration. These models will be run only for this particular agent. If no list is defined, then the default class-level models list will be used instead.

Optionally, a settings object can be defined. This can be useful if specific agents need instance level settings. If no settings are provided, an empty dictionary will be returned.

Agents also support code blocks. The supported code blocks are initialization, preStep, featureVector, step, postStep, and teardown. These are configured at the top-level of the agent. So on the same level as holdings and address you can add an entry for these to overwrite the agent class and top level code blocks on an agent level. This can be useful for having one rogue agent in the Liquidity Provider class that does everything on an extreme and provides liquidity completely different from all the other Liquidity Providers. To see how to write these code blocks, please refer to the code page.

Format

nametype
typearray of
{
    class: string,
    address: string,
    models?: array of strings,
    holdings?: {
        token: string,
        amount: int,
        mint: boolean
    }
}
requiredtrue

Example

agents:
- class: "lp"
address: "0x6429FEe053768Ffa90a59cAfb98Ca9E8F6471211"
holdings:
- token: "bnWBTC"
amount: 4338109590
mint: false
- token: "ETH"
amount: 2847843290371928722
mint: true
- token: "DAI"
amount: 2847843290371928722
mint: true
agentInitialization:
code: |
def custom_agent_class_initialization(agent, environment, metric_collector):
agent.set_variable('withdrawal_request_ids_by_token', collections.defaultdict(list))

custom_agent_class_initialization(a, b, metric_collector)
agentPreStep:
code: |
def custom_agent_class_pre_step(agent, environment, metric_collector):
# A set of individual token names (e.g., {"ETH", "DAI", "LINK"})
current_tokens = set(agent.get_wallet().get_token_names())

# A list of TokenPair objects (e.g., [TokenPair("ETH", "USDT"), TokenPair("USDT", "DAI")])
simulated_tokens = list(environment.get_current_prices().keys())

step_list = []
for token in simulated_tokens:
if (token.get_a() in current_tokens or token.get_b() in current_tokens) and \
token.upper() != 'BNTUSDT':
step = AgentStep()
step.token = token
step_list.append(step)
agent.set_step_list(step_list)

custom_agent_class_pre_step(a, b, metric_collector)
agentFeatureVector:
code: |
def agent_feature_vector(agent, step, model_alias, environment, metric_collector):
token = step.token
non_usdt_token = token.get_a() if token.get_a() != 'USDT' else token.get_b()
coins_abr = {
'BNT': 0,
'LINK': 1,
'ETH': 2,
'DAI': 3,
'WBTC': 4
}

# same as for traders, calculate asset specific features
vol = environment.get_state().token_states[token].volatility
change = environment.get_state().token_states[token].price_change

# calculate asset share
share = agent.get_wallet().get_token_share(non_usdt_token)
return np.array([coins_abr[non_usdt_token], change, vol, share])
agentStep:
code: |
def custom_agent_class_step(agent, step, environment, metric_collector):
try:
model_output = step.get_model_output()
action = model_output['bancor_lp_action']['prediction'][0]
quantity = model_output['bancor_lp_volume']['prediction'][0][0]
token = step.token
non_usdt_token = token.get_a() if token.get_a() != 'USDT' else token.get_b()
token_address = get_token_address(environment, non_usdt_token)
quantity = int(quantity)
if action == 1:
agent.set_latest_action("deposit")
agent.get_client().bancor_network.deposit(token_address, quantity).transact(generate_tx_details(agent.get_address()))
agent.add_affected_token(token)
elif action == 2:
pending_withdrawals = agent.get_variable('withdrawal_request_ids_by_token')[non_usdt_token]

if len(pending_withdrawals) > 0:
agent.set_latest_action("withdrawal")
environment.get_client().bancor_network.withdraw(pending_withdrawals[0]).transact({'from': agent.get_address()})
else:
agent.set_latest_action("cooldown")
withdrawal_request_id = environment.get_client().bancor_network.initWithdrawal(
token_address, quantity).transact({'from': agent.get_address()})
agent.get_variable('withdrawal_request_ids_by_token')[non_usdt_token].append(withdrawal_request_id)
else:
agent.set_latest_action('nothing')
except Exception as e:
agent.set_latest_action('nothing')

custom_agent_class_step(a, b, c, metric_collector)
agentPostStep:
code: |
def custom_agent_class_post_step(agent, environment, metric_collector):
pass

custom_agent_class_post_step(a, b, metric_collector)