seed=np.random.randint(low=0, high=2**32))) for j in range(agent_count, agent_count + num_noise) ]) agent_count += num_noise agent_types.extend(['NoiseAgent']) # 3) Value Agents num_value = 100 agents.extend([ ValueAgent(id=j, name="ValueAgent_{}".format(j), type="ValueAgent", symbol=symbol, starting_cash=starting_cash, sigma_n=r_bar / 10, r_bar=r_bar, kappa=1.67e-15, lambda_a=7e-11, log_orders=False, log_to_file=False, random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32))) for j in range(agent_count, agent_count + num_value) ]) agent_count += num_value agent_types.extend(['ValueAgent']) # 4) Market Maker Agents """ window_size == Spread of market maker (in ticks) around the mid price pov == Percentage of transacted volume seen in previous `mm_wake_up_freq` that
random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64'))) for j in range(agent_count, agent_count + num_noise) ]) agent_count += num_noise agent_types.extend(['NoiseAgent']) # 3) Value Agents num_value = 100 agents.extend([ ValueAgent(id=j, name="Value Agent {}".format(j), type="ValueAgent", symbol=symbol, starting_cash=starting_cash, sigma_n=sigma_n, r_bar=r_bar, kappa=kappa, lambda_a=lambda_a, random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64'))) for j in range(agent_count, agent_count + num_value) ]) agent_count += num_value agent_types.extend(['ValueAgent']) # 4) Market Maker Agent num_mm_agents = 1 agents.extend([ MarketMakerAgent( id=j,
['NoiseAgent' for j in range(agent_count, agent_count + num_noise)]) # 100 agents num_value = num - num_noise # ZI strategy split. Note that agent arrival rates are quite small, because our minimum # time step is a nanosecond, and we want the agents to arrive more on the order of # minutes. agents.extend([ ValueAgent( j, "Value Agent {}".format(j), "ValueAgent {}".format(j), random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64')), log_orders=log_orders, symbol=symbol, # starting_cash=starting_cash, sigma_n=sigma_n, r_bar=s['r_bar'], kappa=s['agent_kappa'], sigma_s=s['fund_vol'], lambda_a=1e-12) for j in range(agent_count, agent_count + num_value) ]) agent_types.extend(["ValueAgent {}".format(j) for j in range(num_value)]) agent_count += num_value ### Configure a simple message latency matrix for the agents. Each entry is the minimum ### nanosecond delay on communication [from][to] agent ID. # Square numpy array with dimensions equal to total agent count. Most agents are handled # at init, drawn from a uniform distribution from:
seed=np.random.randint(low=0, high=2**32, dtype="uint64")), ) for j in range(agent_count, agent_count + num_noise) ]) agent_count += num_noise agent_types.extend(["NoiseAgent"]) # 3) Value Agents num_value = 100 agents.extend([ ValueAgent( id=j, name="Value Agent {}".format(j), type="ValueAgent", symbol=symbol, starting_cash=starting_cash, sigma_n=sigma_n, r_bar=r_bar, kappa=kappa, lambda_a=lambda_a, log_orders=log_orders, random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype="uint64")), ) for j in range(agent_count, agent_count + num_value) ]) agent_count += num_value agent_types.extend(["ValueAgent"]) # 4) Market Maker Agents """ window_size == Spread of market maker (in ticks) around the mid price pov == Percentage of transacted volume seen in previous `mm_wake_up_freq` that the market maker places at each level
symbol=symbol, starting_cash=starting_cash, wakeup_time=mkt_open + np.random.rand() * (mkt_close - mkt_open)) for j in range(agent_count, agent_count + num_noise) ]) agent_count += num_noise agent_types.extend(['NoiseAgent' for j in range(num_noise)]) # 3) Value Agents agents.extend([ ValueAgent( j, "ValueAgent {}".format(j), "ValueAgent {}".format(j), random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64')), r_bar=r_bar, lambda_a=1e-13, sigma_n=r_bar / 10, kappa=kappa, log_orders=log_orders, symbol=symbol) for j in range(agent_count, agent_count + num_value) ]) agent_types.extend(["ValueAgent {}".format(j) for j in range(num_value)]) agent_count += num_value #4) Market Maker Agent num_mm_agents = 1 agents.extend([ MarketMakerAgent( id=j, name="MarketMakerAgent {}".format(j),
symbol = 'IBM' s = symbols[symbol] # ZI strategy split. Note that agent arrival rates are quite small, because our minimum # time step is a nanosecond, and we want the agents to arrive more on the order of # minutes. for n, x in zip(zi, zi_strategy): strat_name = agent_strats[agent_id] while n > 0: agents.append(ZeroIntelligenceAgent(agent_id, "ZI Agent {}".format(agent_id), strat_name, random_state = get_rand_obj(agent_seeds[agent_id]), log_orders=log_orders, symbol=symbol, starting_cash=starting_cash, sigma_n=zi_obs_noise, r_bar=s['r_bar'], kappa=s['agent_kappa'], sigma_s=s['fund_vol'], q_max=10, sigma_pv=5e6, R_min=x[0], R_max=x[1], eta=x[2], lambda_a=1e-12)) agent_id += 1 n -= 1 # Add value agents. for i in range(num_val): agents.extend([ ValueAgent(agent_id, "Value Agent {}".format(agent_id), "ValueAgent", symbol = symbol, random_state = get_rand_obj(agent_seeds[agent_id]), log_orders=log_orders, starting_cash=starting_cash, sigma_n=zi_obs_noise, r_bar=s['r_bar'], kappa=s['agent_kappa'], sigma_s=s['fund_vol'], lambda_a=1e-12) ]) agent_id += 1 # Add an OBI agent to try to beat this market. for i in range(num_obi): random_state = get_rand_obj(agent_seeds[agent_id]) agents.extend([ OrderBookImbalanceAgent(agent_id, "OBI Agent {}".format(agent_id), "OrderBookImbalanceAgent", symbol = symbol, starting_cash = starting_cash, levels = levels, entry_threshold = entry_threshold, trail_dist = trail_dist, freq = obi_freq, random_state = random_state) ]) agent_id += 1 # Add market maker agents. for i in range(num_mm): random_state = get_rand_obj(agent_seeds[agent_id]) agents.extend([ MarketMakerAgent(agent_id, "Market Maker Agent {}".format(agent_id), "MarketMakerAgent", symbol=symbol, starting_cash=starting_cash, min_size=500, max_size=1000, subscribe=True, log_orders=False, random_state = random_state) ]) agent_id += 1
def generateMidPrices(self, sigma_n): # Set random seed if not self.seed: self.seed = int( pd.Timestamp.now().timestamp() * 1000000) % (2**32 - 1) np.random.seed(self.seed) # Note: sigma_s is no longer used by the agents or the fundamental (for sparse discrete simulation). symbols = { self.symbol: { 'r_bar': self.r_bar, 'kappa': self.kappa, 'agent_kappa': 1e-15, 'sigma_s': 0., 'fund_vol': self.sigma_s, 'megashock_lambda_a': 1e-15, 'megashock_mean': 0., 'megashock_var': 1e-15, "random_state": np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64')) } } util.silent_mode = True LimitOrder.silent_mode = True OrderBook.tqdm_used = False kernel = CalculationKernel( "Calculation Kernel", random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64'))) ### Configure the agents. When conducting "agent of change" experiments, the ### new agents should be added at the END only. agent_count = 0 agents = [] agent_types = [] # Let's open the exchange at 9:30 AM. mkt_open = self.midnight + pd.to_timedelta('09:30:00') # And close it at 4:00 PM. mkt_close = self.midnight + pd.to_timedelta('16:00:00') # Configure an appropriate oracle for all traded stocks. # All agents requiring the same type of Oracle will use the same oracle instance. oracle = SparseMeanRevertingOracle(mkt_open, mkt_close, symbols) # Create the exchange. num_exchanges = 1 agents.extend([ ExchangeAgent( j, "Exchange Agent {}".format(j), "ExchangeAgent", mkt_open, mkt_close, [s for s in symbols], log_orders=False, book_freq=self.freq, pipeline_delay=0, computation_delay=0, stream_history=10, random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64'))) for j in range(agent_count, agent_count + num_exchanges) ]) agent_types.extend(["ExchangeAgent" for j in range(num_exchanges)]) agent_count += num_exchanges symbol = self.symbol s = symbols[symbol] # Some value agents. agents.extend([ ValueAgent( j, "Value Agent {}".format(j), "ValueAgent {}".format(j), random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**32, dtype='uint64')), log_orders=False, symbol=symbol, starting_cash=self.starting_cash, sigma_n=sigma_n, r_bar=s['r_bar'], kappa=s['agent_kappa'], sigma_s=s['fund_vol'], lambda_a=self.lambda_a) for j in range(agent_count, agent_count + self.num_agents) ]) agent_types.extend( ["ValueAgent {}".format(j) for j in range(self.num_agents)]) agent_count += self.num_agents # Config the latency model latency = None noise = None latency_model = None USE_NEW_MODEL = True ### BEGIN OLD LATENCY ATTRIBUTE CONFIGURATION ### ### Configure a simple message latency matrix for the agents. Each entry is the minimum ### nanosecond delay on communication [from][to] agent ID. # Square numpy array with dimensions equal to total agent count. Most agents are handled # at init, drawn from a uniform distribution from: # Times Square (3.9 miles from NYSE, approx. 21 microseconds at the speed of light) to: # Pike Place Starbucks in Seattle, WA (2402 miles, approx. 13 ms at the speed of light). # Other agents can be explicitly set afterward (and the mirror half of the matrix is also). if not USE_NEW_MODEL: # This configures all agents to a starting latency as described above. latency = np.random.uniform(low=21000, high=13000000, size=(len(agent_types), len(agent_types))) # Overriding the latency for certain agent pairs happens below, as does forcing mirroring # of the matrix to be symmetric. for i, t1 in zip(range(latency.shape[0]), agent_types): for j, t2 in zip(range(latency.shape[1]), agent_types): # Three cases for symmetric array. Set latency when j > i, copy it when i > j, same agent when i == j. if j > i: # Presently, strategy agents shouldn't be talking to each other, so we set them to extremely high latency. if (t1 == "ZeroIntelligenceAgent" and t2 == "ZeroIntelligenceAgent"): latency[ i, j] = 1000000000 * 60 * 60 * 24 # Twenty-four hours. elif i > j: # This "bottom" half of the matrix simply mirrors the top. latency[i, j] = latency[j, i] else: # This is the same agent. How long does it take to reach localhost? In our data center, it actually # takes about 20 microseconds. latency[i, j] = 20000 # Configure a simple latency noise model for the agents. # Index is ns extra delay, value is probability of this delay being applied. noise = [0.25, 0.25, 0.20, 0.15, 0.10, 0.05] ### END OLD LATENCY ATTRIBUTE CONFIGURATION ### ### BEGIN NEW LATENCY MODEL CONFIGURATION ### else: # Get a new-style cubic LatencyModel from the networking literature. pairwise = (len(agent_types), len(agent_types)) model_args = { 'connected': True, # All in NYC. 'min_latency': np.random.uniform(low=21000, high=100000, size=pairwise), 'jitter': 0.3, 'jitter_clip': 0.05, 'jitter_unit': 5, } latency_model = LatencyModel( latency_model='cubic', random_state=np.random.RandomState( seed=np.random.randint(low=0, high=2**31)), kwargs=model_args) # Start the kernel running. with HiddenPrints(): midprices = kernel.runner( agents=agents, startTime=self.kernelStartTime, stopTime=self.kernelStopTime, agentLatencyModel=latency_model, agentLatency=latency, latencyNoise=noise, defaultComputationDelay=self.defaultComputationDelay, oracle=oracle, log_dir=None, return_value={self.symbol: "midprices"}) return midprices[self.symbol]