Skip to content

Commit

Permalink
ABIDES v1.1 release (abides-sim#2)
Browse files Browse the repository at this point in the history
Example script and config to run multiple ABIDES simulations in parallel.

Improvements to execution agents.

New utilities to support more types of experiments.

New plotting utilities for market impact and other A/B experiments.

New plotting utilities for various features and logs from a single ABIDES run.

New plotting utilities for recent paper submissions.

Improvements to market maker agents (adaptive, etc).

New cubic network jitter model for message latency.
  • Loading branch information
davebyrd authored Mar 15, 2020
1 parent 296a1cd commit 921d6d3
Show file tree
Hide file tree
Showing 111 changed files with 50,764 additions and 394 deletions.
42 changes: 33 additions & 9 deletions Kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ def __init__(self, kernel_name, random_state = None):
def runner(self, agents = [], startTime = None, stopTime = None,
num_simulations = 1, defaultComputationDelay = 1,
defaultLatency = 1, agentLatency = None, latencyNoise = [ 1.0 ],
agentLatencyModel = None,
seed = None, oracle = None, log_dir = None):

# agents must be a list of agents for the simulation,
# based on class agent.Agent
self.agents = agents
self.agent_saved_states = [None] * len(self.agents)

# The kernel start and stop time (first and last timestamp in
# the simulation, separate from anything like exchange open/close).
Expand Down Expand Up @@ -93,6 +95,14 @@ def runner(self, agents = [], startTime = None, stopTime = None,
# TODO: this might someday change to pd.Timedelta objects.
self.agentComputationDelays = [defaultComputationDelay] * len(agents)

# If an agentLatencyModel is defined, it will be used instead of
# the older, non-model-based attributes.
self.agentLatencyModel = agentLatencyModel

# If an agentLatencyModel is NOT defined, the older parameters:
# agentLatency (or defaultLatency) and latencyNoise should be specified.
# These should be considered deprecated and will be removed in the future.

# If agentLatency is not defined, define it using the defaultLatency.
# This matrix defines the communication delay between every pair of
# agents.
Expand All @@ -105,9 +115,6 @@ def runner(self, agents = [], startTime = None, stopTime = None,
# distribution with the peak at zero. By default there is no noise
# (100% chance to add zero ns extra delay). Format is a list with
# list index = ns extra delay, value = probability of this delay.
# TODO: This should probably become more sophisticated. If not
# continuous, then at least a dictionary with key=delay and
# value=probability in case we want a more sparse delay function.
self.latencyNoise = latencyNoise

# The kernel maintains an accumulating additional delay parameter
Expand Down Expand Up @@ -301,6 +308,8 @@ def runner(self, agents = [], startTime = None, stopTime = None,

print ("Simulation ending!")

return self.agent_saved_states


def sendMessage(self, sender = None, recipient = None, msg = None, delay = 0):
# Called by an agent to send a message to another agent. The kernel
Expand Down Expand Up @@ -343,19 +352,30 @@ def sendMessage(self, sender = None, recipient = None, msg = None, delay = 0):
sentTime = self.currentTime + pd.Timedelta(self.agentComputationDelays[sender] +
self.currentAgentAdditionalDelay + delay)

# Apply communication delay per the agentLatency matrix [sender][recipient].
latency = self.agentLatency[sender][recipient]
noise = self.random_state.choice(len(self.latencyNoise), 1, self.latencyNoise)[0]
deliverAt = sentTime + pd.Timedelta(latency + noise)
# Apply communication delay per the agentLatencyModel, if defined, or the
# agentLatency matrix [sender][recipient] otherwise.
if self.agentLatencyModel is not None:
latency = self.agentLatencyModel.get_latency(sender_id = sender, recipient_id = recipient)
deliverAt = sentTime + pd.Timedelta(latency)
log_print ("Kernel applied latency {}, accumulated delay {}, one-time delay {} on sendMessage from: {} to {}, scheduled for {}",
latency, self.currentAgentAdditionalDelay, delay, self.agents[sender].name, self.agents[recipient].name,
self.fmtTime(deliverAt))
else:
latency = self.agentLatency[sender][recipient]
noise = self.random_state.choice(len(self.latencyNoise), 1, self.latencyNoise)[0]
deliverAt = sentTime + pd.Timedelta(latency + noise)
log_print ("Kernel applied latency {}, noise {}, accumulated delay {}, one-time delay {} on sendMessage from: {} to {}, scheduled for {}",
latency, noise, self.currentAgentAdditionalDelay, delay, self.agents[sender].name, self.agents[recipient].name,
self.fmtTime(deliverAt))

# Finally drop the message in the queue with priority == delivery time.
self.messages.put((deliverAt, (recipient, MessageType.MESSAGE, msg)))

log_print ("Kernel applied latency {}, noise {}, accumulated delay {}, one-time delay {} on sendMessage from: {} to {}, scheduled for {}",
latency, noise, self.currentAgentAdditionalDelay, delay, self.agents[sender].name, self.agents[recipient].name, self.fmtTime(deliverAt))
log_print ("Sent time: {}, current time {}, computation delay {}", sentTime, self.currentTime, self.agentComputationDelays[sender])
log_print ("Message queued: {}", msg)



def setWakeup(self, sender = None, requestedTime = None):
# Called by an agent to receive a "wakeup call" from the kernel
# at some requested future time. Defaults to the next possible
Expand Down Expand Up @@ -494,6 +514,10 @@ def writeSummaryLog (self):

dfLog.to_pickle(os.path.join(path, file), compression='bz2')


def saveState (self, agent_id, state):
self.agent_saved_states[agent_id] = state


@staticmethod
def fmtTime(simulationTime):
Expand Down
2 changes: 2 additions & 0 deletions agent/Agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ def delay (self, additionalDelay):
def writeLog (self, dfLog, filename=None):
self.kernel.writeLog(self.id, dfLog, filename)

def saveState (self, state):
self.kernel.saveState(self.id, state)

### Internal methods that should not be modified without a very good reason.

Expand Down
Loading

0 comments on commit 921d6d3

Please sign in to comment.