def __init__(self, algo, environment): self.algo = algo self.environment = environment self.ordering_client = TransactionSimulator() self.perf_tracker = PerformanceTracker(self.environment) self.algo_start = self.environment.first_open self.algo_sim = AlgorithmSimulator(self.ordering_client, self.algo, self.algo_start)
def __init__(self, algo, sim_params): self.algo = algo self.sim_params = sim_params self.ordering_client = TransactionSimulator() self.perf_tracker = PerformanceTracker(self.sim_params) self.algo_start = self.sim_params.first_open self.algo_sim = AlgorithmSimulator(self.ordering_client, self.perf_tracker, self.algo, self.algo_start)
def __init__(self, algo, sim_params): self.algo = algo self.sim_params = sim_params self.ordering_client = TransactionSimulator() self.perf_tracker = PerformanceTracker(self.sim_params) self.algo_start = self.sim_params.first_open self.algo_sim = AlgorithmSimulator( self.ordering_client, self.perf_tracker, self.algo, self.algo_start )
class TradeSimulationClient(object): """ Generator-style class that takes the expected output of a merge, a user algorithm, a trading environment, and a simulator slippage as arguments. Pipes the merge stream through a TransactionSimulator and a PerformanceTracker, which keep track of the current state of our algorithm's simulated universe. Results are fed to the user's algorithm, which directly inserts transactions into the TransactionSimulator's order book. TransactionSimulator maintains a dictionary from sids to the as-yet unfilled orders placed by the user's algorithm. As trade events arrive, if the algorithm has open orders against the trade's sid, the simulator will fill orders up to 25% of market cap. Applied transactions are added to a txn field on the event and forwarded to PerformanceTracker. The txn field is set to None on non-trade events and events that do not match any open orders. PerformanceTracker receives the updated event messages from TransactionSimulator, maintaining a set of daily and cumulative performance metrics for the algorithm. The tracker removes the txn field from each event it receives, replacing it with a portfolio field to be fed into the user algo. At the end of each trading day, the PerformanceTracker also generates a daily performance report, which is appended to event's perf_report field. Fully processed events are fed to AlgorithmSimulator, which batches together events with the same dt field into a single snapshot to be fed to the algo. The portfolio object is repeatedly overwritten so that only the most recent snapshot of the universe is sent to the algo. """ def __init__(self, algo, environment): self.algo = algo self.environment = environment self.ordering_client = TransactionSimulator() self.perf_tracker = PerformanceTracker(self.environment) self.algo_start = self.environment.first_open self.algo_sim = AlgorithmSimulator( self.ordering_client, self.perf_tracker, self.algo, self.algo_start ) def get_hash(self): """ There should only ever be one TSC in the system, so we don't bother passing args into the hash. """ return self.__class__.__name__ + hash_args() def simulate(self, stream_in): """ Main generator work loop. """ # Simulate filling any open orders made by the previous run of # the user's algorithm. Fills the Transaction field on any # event that results in a filled order. with_filled_orders = self.ordering_client.transform(stream_in) # Pipe the events with transactions to perf. This will remove # the TRANSACTION field added by TransactionSimulator and replace it # with a portfolio field to be passed to the user's # algorithm. Also adds a perf_messages field which is usually # empty, but contains update messages once per day. with_portfolio = self.perf_tracker.transform(with_filled_orders) # Pass the messages from perf to the user's algorithm for simulation. # Events are batched by dt so that the algo handles all events for a # given timestamp at one one go. performance_messages = self.algo_sim.transform(with_portfolio) # The algorithm will yield a daily_results message (as # calculated by the performance tracker) at the end of each # day. It will also yield a risk report at the end of the # simulation. for message in performance_messages: yield message
def transaction_sim(self, **params): """ This is a utility method that asserts expected results for conversion of orders to transactions given a trade history""" trade_count = params['trade_count'] trade_interval = params['trade_interval'] order_count = params['order_count'] order_amount = params['order_amount'] order_interval = params['order_interval'] expected_txn_count = params['expected_txn_count'] expected_txn_volume = params['expected_txn_volume'] # optional parameters # --------------------- # if present, alternate between long and short sales alternate = params.get('alternate') # if present, expect transaction amounts to match orders exactly. complete_fill = params.get('complete_fill') sid = 1 sim_params = factory.create_simulation_parameters() trade_sim = TransactionSimulator() price = [10.1] * trade_count volume = [100] * trade_count start_date = sim_params.first_open generated_trades = factory.create_trade_history( sid, price, volume, trade_interval, sim_params) if alternate: alternator = -1 else: alternator = 1 order_date = start_date for i in xrange(order_count): order = Order( **{ 'sid': sid, 'amount': order_amount * alternator**i, 'dt': order_date }) trade_sim.place_order(order) order_date = order_date + order_interval # move after market orders to just after market next # market open. if order_date.hour >= 21: if order_date.minute >= 00: order_date = order_date + timedelta(days=1) order_date = order_date.replace(hour=14, minute=30) # there should now be one open order list stored under the sid oo = trade_sim.open_orders self.assertEqual(len(oo), 1) self.assertTrue(sid in oo) order_list = oo[sid] self.assertEqual(order_count, len(order_list)) for i in xrange(order_count): order = order_list[i] self.assertEqual(order.sid, sid) self.assertEqual(order.amount, order_amount * alternator**i) tracker = PerformanceTracker(sim_params) # this approximates the loop inside TradingSimulationClient transactions = [] for dt, trades in itertools.groupby(generated_trades, operator.attrgetter('dt')): for trade in trades: trade_sim.update(trade) if trade.TRANSACTION: transactions.append(trade.TRANSACTION) tracker.process_event(trade) if complete_fill: self.assertEqual(len(transactions), len(order_list)) total_volume = 0 for i in xrange(len(transactions)): txn = transactions[i] total_volume += txn.amount if complete_fill: order = order_list[i] self.assertEqual(order.amount, txn.amount) self.assertEqual(total_volume, expected_txn_volume) self.assertEqual(len(transactions), expected_txn_count) cumulative_pos = tracker.cumulative_performance.positions[sid] self.assertEqual(total_volume, cumulative_pos.amount) # the open orders should now be empty oo = trade_sim.open_orders self.assertTrue(sid in oo) order_list = oo[sid] self.assertEqual(0, len(order_list))
class TradeSimulationClient(object): """ Generator-style class that takes the expected output of a merge, a user algorithm, a trading environment, and a simulator slippage as arguments. Pipes the merge stream through a TransactionSimulator and a PerformanceTracker, which keep track of the current state of our algorithm's simulated universe. Results are fed to the user's algorithm, which directly inserts transactions into the TransactionSimulator's order book. TransactionSimulator maintains a dictionary from sids to the as-yet unfilled orders placed by the user's algorithm. As trade events arrive, if the algorithm has open orders against the trade's sid, the simulator will fill orders up to 25% of market cap. Applied transactions are added to a txn field on the event and forwarded to PerformanceTracker. The txn field is set to None on non-trade events and events that do not match any open orders. PerformanceTracker receives the updated event messages from TransactionSimulator, maintaining a set of daily and cumulative performance metrics for the algorithm. The tracker removes the txn field from each event it receives, replacing it with a portfolio field to be fed into the user algo. At the end of each trading day, the PerformanceTracker also generates a daily performance report, which is appended to event's perf_report field. Fully processed events are fed to AlgorithmSimulator, which batches together events with the same dt field into a single snapshot to be fed to the algo. The portfolio object is repeatedly overwritten so that only the most recent snapshot of the universe is sent to the algo. """ def __init__(self, algo, environment): self.algo = algo self.environment = environment self.ordering_client = TransactionSimulator() self.perf_tracker = PerformanceTracker(self.environment) self.algo_start = self.environment.first_open self.algo_sim = AlgorithmSimulator(self.ordering_client, self.algo, self.algo_start) def get_hash(self): """ There should only ever be one TSC in the system, so we don't bother passing args into the hash. """ return self.__class__.__name__ + hash_args() def simulate(self, stream_in): """ Main generator work loop. """ # Simulate filling any open orders made by the previous run of # the user's algorithm. Fills the Transaction field on any # event that results in a filled order. with_filled_orders = self.ordering_client.transform(stream_in) # Pipe the events with transactions to perf. This will remove # the TRANSACTION field added by TransactionSimulator and replace it # with a portfolio field to be passed to the user's # algorithm. Also adds a perf_message field which is usually # none, but contains an update message once per day. with_portfolio = self.perf_tracker.transform(with_filled_orders) # Pass the messages from perf to the user's algorithm for simulation. # Events are batched by dt so that the algo handles all events for a # given timestamp at one one go. performance_messages = self.algo_sim.transform(with_portfolio) # The algorithm will yield a daily_results message (as # calculated by the performance tracker) at the end of each # day. It will also yield a risk report at the end of the # simulation. for message in performance_messages: yield message
def transaction_sim(self, **params): """ This is a utility method that asserts expected results for conversion of orders to transactions given a trade history""" trade_count = params['trade_count'] trade_interval = params['trade_interval'] trade_delay = params.get('trade_delay') order_count = params['order_count'] order_amount = params['order_amount'] order_interval = params['order_interval'] expected_txn_count = params['expected_txn_count'] expected_txn_volume = params['expected_txn_volume'] # optional parameters # --------------------- # if present, alternate between long and short sales alternate = params.get('alternate') # if present, expect transaction amounts to match orders exactly. complete_fill = params.get('complete_fill') sid = 1 sim_params = factory.create_simulation_parameters() trade_sim = TransactionSimulator() price = [10.1] * trade_count volume = [100] * trade_count start_date = sim_params.first_open generated_trades = factory.create_trade_history( sid, price, volume, trade_interval, sim_params ) if alternate: alternator = -1 else: alternator = 1 order_date = start_date for i in xrange(order_count): order = ndict({ 'sid': sid, 'amount': order_amount * alternator ** i, 'dt': order_date }) trade_sim.place_order(order) order_date = order_date + order_interval # move after market orders to just after market next # market open. if order_date.hour >= 21: if order_date.minute >= 00: order_date = order_date + timedelta(days=1) order_date = order_date.replace(hour=14, minute=30) # there should now be one open order list stored under the sid oo = trade_sim.open_orders self.assertEqual(len(oo), 1) self.assertTrue(sid in oo) order_list = oo[sid] self.assertEqual(order_count, len(order_list)) for i in xrange(order_count): order = order_list[i] self.assertEqual(order.sid, sid) self.assertEqual(order.amount, order_amount * alternator ** i) tracker = PerformanceTracker(sim_params) # this approximates the loop inside TradingSimulationClient transactions = [] for trade in generated_trades: if trade_delay: trade.dt = trade.dt + trade_delay trade_sim.update(trade) if trade.TRANSACTION: transactions.append(trade.TRANSACTION) tracker.process_event(trade) if complete_fill: self.assertEqual(len(transactions), len(order_list)) total_volume = 0 for i in xrange(len(transactions)): txn = transactions[i] total_volume += txn.amount if complete_fill: order = order_list[i] self.assertEqual(order.amount, txn.amount) self.assertEqual(total_volume, expected_txn_volume) self.assertEqual(len(transactions), expected_txn_count) cumulative_pos = tracker.cumulative_performance.positions[sid] self.assertEqual(total_volume, cumulative_pos.amount) # the open orders should now be empty oo = trade_sim.open_orders self.assertTrue(sid in oo) order_list = oo[sid] self.assertEqual(0, len(order_list))