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
name | type |
---|---|
type | array of { class: string, address: string, models?: array of strings, holdings?: { token: string, amount: int, mint: boolean } } |
required | true |
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)