def test_algo_with_rl_violation(self): sim_params = factory.create_simulation_parameters(start=list( LEVERAGED_ETFS.keys())[0], num_days=4) trade_history = factory.create_trade_history('BZQ', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='BZQ', sim_params=sim_params) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0) # repeat with a symbol from a different lookup date trade_history = factory.create_trade_history('JFT', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='JFT', sim_params=sim_params) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0)
def test_algo_with_rl_violation(self): sim_params = factory.create_simulation_parameters( start=list(LEVERAGED_ETFS.keys())[0], num_days=4) trade_history = factory.create_trade_history( 'BZQ', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='BZQ', sim_params=sim_params) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0) # repeat with a symbol from a different lookup date trade_history = factory.create_trade_history( 'JFT', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='JFT', sim_params=sim_params) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0)
def test_tracker(self): trade_count = 100 sid = 133 price = 10.1 price_list = [price] * trade_count volume = [100] * trade_count trade_time_increment = datetime.timedelta(days=1) trade_history = factory.create_trade_history(sid, price_list, volume, trade_time_increment, self.trading_environment) sid2 = 134 price2 = 12.12 price2_list = [price2] * trade_count trade_history2 = factory.create_trade_history(sid2, price2_list, volume, trade_time_increment, self.trading_environment) trade_history.extend(trade_history2) self.trading_environment.period_start = trade_history[0].dt self.trading_environment.period_end = trade_history[-1].dt self.trading_environment.capital_base = 1000.0 self.trading_environment.frame_index = [ 'sid', 'volume', 'dt', 'price', 'changed' ] perf_tracker = perf.PerformanceTracker(self.trading_environment) for event in trade_history: #create a transaction for all but #first trade in each sid, to simulate None transaction if (event.dt != self.trading_environment.period_start): txn = ndict({ 'sid': event.sid, 'amount': -25, 'dt': event.dt, 'price': 10.0, 'commission': 0.50 }) else: txn = None event['TRANSACTION'] = txn perf_tracker.process_event(event) #we skip two trades, to test case of None transaction txn_count = len(trade_history) - 2 self.assertEqual(perf_tracker.txn_count, txn_count) cumulative_pos = perf_tracker.cumulative_performance.positions[sid] expected_size = txn_count / 2 * -25 self.assertEqual(cumulative_pos.amount, expected_size) self.assertEqual( perf_tracker.period_end.replace(hour=0, minute=0, second=0), perf_tracker.cumulative_risk_metrics.end_date)
def test_ending_before_pay_date(self): # post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) pay_date = self.sim_params.first_open # find pay date that is much later. for i in xrange(30): pay_date = factory.get_next_trading_dt(pay_date, oneday) dividend = factory.create_dividend(1, 10.00, events[0].dt, events[1].dt, pay_date) buy_txn = create_txn(1, 10.0, 100, events[1].dt) events.insert(2, buy_txn) events.insert(1, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = [event["cumulative_perf"]["returns"] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0.0, 0.0]) daily_returns = [event["daily_perf"]["returns"] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0, 0]) cash_flows = [event["daily_perf"]["capital_used"] for event in results] self.assertEqual(cash_flows, [0, -1000, 0, 0, 0]) cumulative_cash_flows = [event["cumulative_perf"]["capital_used"] for event in results] self.assertEqual(cumulative_cash_flows, [0, -1000, -1000, -1000, -1000])
def test_returns(self): # Daily returns. returns = Returns(1) transformed = list(returns.transform(self.source)) tnfm_vals = [message.tnfm_value for message in transformed] # No returns for the first event because we don't have a # previous close. expected = [0.0, 0.0, 0.1, 0.0] assert tnfm_vals == expected # Two-day returns. An extra kink here is that the # factory will automatically skip a weekend for the # last event. Results shouldn't notice this blip. trade_history = factory.create_trade_history( 133, [10.0, 15.0, 13.0, 12.0, 13.0], [100, 100, 100, 300, 100], timedelta(days=1), self.trading_environment) self.source = SpecificEquityTrades(event_list=trade_history) returns = StatefulTransform(Returns, 2) transformed = list(returns.transform(self.source)) tnfm_vals = [message.tnfm_value for message in transformed] expected = [ 0.0, 0.0, (13.0 - 10.0) / 10.0, (12.0 - 15.0) / 15.0, (13.0 - 13.0) / 13.0 ] assert tnfm_vals == expected
def test_buy_and_sell_before_ex(self): # post some trades in the market events = factory.create_trade_history(1, [10, 10, 10, 10, 10, 10], [100, 100, 100, 100, 100, 100], oneday, self.sim_params) dividend = factory.create_dividend(1, 10.00, events[3].dt, events[4].dt, events[5].dt) buy_txn = create_txn(events[1], 10.0, 100) events.insert(1, buy_txn) sell_txn = create_txn(events[3], 10.0, -100) events.insert(3, sell_txn) events.insert(1, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 6) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0, 0, 0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0, 0, 0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, -1000, 1000, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, -1000, 0, 0, 0, 0])
def test_short_position_pays_dividend(self): # post some trades in the market events = factory.create_trade_history(1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) dividend = factory.create_dividend( 1, 10.00, # declare at open of test events[0].dt, # ex_date same as trade 2 events[2].dt, events[3].dt) txn = create_txn(events[1], 10.0, -100) events.insert(1, txn) events.insert(0, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, -0.1, -0.1]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.0, -0.1, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, 1000, 0, -1000, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, 1000, 1000, 0, 0])
def test_algo_with_rl_violation_cumulative(self): """ Add a new restriction, run a test long after both knowledge dates, make sure stock from original restriction set is still disallowed. """ sim_params = factory.create_simulation_parameters( start=list( LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=4) with security_list_copy(): add_security_data(['AAPL'], []) trade_history = factory.create_trade_history( 'BZQ', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params, env=self.env, ) self.source = SpecificEquityTrades(event_list=trade_history, env=self.env) algo = RestrictedAlgoWithoutCheck( symbol='BZQ', sim_params=sim_params, env=self.env) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0)
def test_no_position_receives_no_dividend(self): #post some trades in the market events = factory.create_trade_history(1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) dividend = factory.create_dividend(1, 10.00, events[0].dt, events[1].dt, events[2].dt) events.insert(1, dividend) perf_tracker = perf.PerformanceTracker(self.sim_params) transformed_events = list( perf_tracker.transform(((event.dt, [event]) for event in events))) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, 0, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, 0, 0, 0, 0])
def test_cost_basis_calc_close_pos(self): history_args = ( 1, [10, 9, 11, 8, 9, 12, 13, 14], [200, -100, -100, 100, -300, 100, 500, 400], onesec, self.sim_params ) cost_bases = [10, 10, 0, 8, 9, 9, 13, 13.5] trades = factory.create_trade_history(*history_args) transactions = factory.create_txn_history(*history_args) pp = perf.PerformancePeriod(1000.0) for txn, cb in zip(transactions, cost_bases): pp.execute_transaction(txn) self.assertEqual(pp.positions[1].cost_basis, cb) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() self.assertEqual(pp.positions[1].cost_basis, cost_bases[-1])
def test_commission_zero_position(self): """ Ensure no div-by-zero errors. """ events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) # Buy and sell the same sid so that we have a zero position by the # time of events[3]. txns = [ create_txn(events[0], 20, 1), create_txn(events[1], 20, -1), ] # Add a cash adjustment at the time of event[3]. cash_adj_dt = events[3].dt cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) events.append(cash_adjustment) results = calculate_results(self, events, txns=txns) # Validate that we lost 300 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9700)
def test_no_position_receives_no_dividend(self): # post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, events[0].dt, events[1].dt, events[2].dt ) results = calculate_results( self, events, dividend_events=[dividend], ) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, 0, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, 0, 0, 0, 0])
def test_short_position_pays_dividend(self): # post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, # declare at open of test events[0].dt, # ex_date same as trade 2 events[2].dt, events[3].dt, ) txn = create_txn(1, 10.0, -100, events[1].dt) events.insert(1, txn) events.insert(0, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = [event["cumulative_perf"]["returns"] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, -0.1, -0.1]) daily_returns = [event["daily_perf"]["returns"] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.0, -0.1, 0.0]) cash_flows = [event["daily_perf"]["capital_used"] for event in results] self.assertEqual(cash_flows, [0, 1000, 0, -1000, 0]) cumulative_cash_flows = [event["cumulative_perf"]["capital_used"] for event in results] self.assertEqual(cumulative_cash_flows, [0, 1000, 1000, 0, 0])
def test_algo_with_rl_violation_cumulative(self): """ Add a new restriction, run a test long after both knowledge dates, make sure stock from original restriction set is still disallowed. """ sim_params = factory.create_simulation_parameters( start=list(LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=4) with security_list_copy(): add_security_data(['AAPL'], []) trade_history = factory.create_trade_history( 'BZQ', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params, env=self.env, ) self.source = SpecificEquityTrades(event_list=trade_history, env=self.env) algo = RestrictedAlgoWithoutCheck(symbol='BZQ', sim_params=sim_params, env=self.env) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 0)
def test_set_max_order_count(self): # Override the default setUp to use six-hour intervals instead of full # days so we can exercise trading-session rollover logic. trade_history = factory.create_trade_history( self.sid, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(hours=6), self.sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) def handle_data(algo, data): for i in range(5): algo.order(self.sid, 1) algo.order_count += 1 algo = SetMaxOrderCountAlgorithm(3) self.check_algo_fails(algo, handle_data, 3) # Second call to handle_data is the same day as the first, so the last # order of the second call should fail. algo = SetMaxOrderCountAlgorithm(9) self.check_algo_fails(algo, handle_data, 9) # Only ten orders are placed per day, so this should pass even though # in total more than 20 orders are placed. algo = SetMaxOrderCountAlgorithm(10) self.check_algo_succeeds(algo, handle_data, order_count=20)
def test_no_position_receives_no_dividend(self): # post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, events[0].dt, events[1].dt, events[2].dt ) events.insert(1, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, 0, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, 0, 0, 0, 0])
def test_commission_zero_position(self): """ Ensure no div-by-zero errors. """ with trading.TradingEnvironment(): events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) cash_adj_dt = self.sim_params.first_open \ + datetime.timedelta(hours=3) cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) # Insert a purchase order. events.insert(0, create_txn(events[0], 20, 1)) # Sell that order. events.insert(1, create_txn(events[1], 20, -1)) events.insert(2, cash_adjustment) results = calculate_results(self, events) # Validate that we lost 300 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9700)
def test_moving_stddev(self): trade_history = factory.create_trade_history( 133, [10.0, 15.0, 13.0, 12.0], [100, 100, 100, 100], timedelta(days=1), self.sim_params ) stddev = MovingStandardDev( market_aware=True, window_length=3, ) self.source = SpecificEquityTrades(event_list=trade_history) transformed = list(stddev.transform(self.source)) vals = [message[stddev.get_hash()] for message in transformed] expected = [ None, np.std([10.0, 15.0], ddof=1), np.std([10.0, 15.0, 13.0], ddof=1), np.std([15.0, 13.0, 12.0], ddof=1), ] # np has odd rounding behavior, cf. # http://docs.scipy.org/doc/np/reference/generated/np.std.html for v1, v2 in zip(vals, expected): if v1 is None: self.assertIsNone(v2) continue self.assertEquals(round(v1, 5), round(v2, 5))
def test_commission_event(self): with trading.TradingEnvironment(): events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) cash_adj_dt = self.sim_params.first_open \ + datetime.timedelta(hours=3) cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) # Insert a purchase order. events.insert(0, create_txn(events[0], 20, 1)) events.insert(1, cash_adjustment) results = calculate_results(self, events) # Validate that we lost 320 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9680) # Validate that the cost basis of our position changed. self.assertEqual(results[-1]['daily_perf']['positions'] [0]['cost_basis'], 320.0)
def test_ending_before_pay_date(self): # post some trades in the market events = factory.create_trade_history(1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) pay_date = self.sim_params.first_open # find pay date that is much later. for i in xrange(30): pay_date = factory.get_next_trading_dt(pay_date, oneday) dividend = factory.create_dividend(1, 10.00, events[0].dt, events[1].dt, pay_date) buy_txn = create_txn(events[1], 10.0, 100) events.insert(2, buy_txn) events.insert(1, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0.0, 0.0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0, 0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, -1000, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, -1000, -1000, -1000, -1000])
def test_moving_stddev(self): trade_history = factory.create_trade_history( 133, [10.0, 15.0, 13.0, 12.0], [100, 100, 100, 100], timedelta(hours=1), self.trading_environment ) stddev = MovingStandardDev( market_aware=False, delta=timedelta(minutes=150), ) self.source = SpecificEquityTrades(event_list=trade_history) transformed = list(stddev.transform(self.source)) vals = [message.tnfm_value for message in transformed] expected = [ None, np.std([10.0, 15.0], ddof=1), np.std([10.0, 15.0, 13.0], ddof=1), np.std([15.0, 13.0, 12.0], ddof=1), ] # np has odd rounding behavior, cf. # http://docs.scipy.org/doc/np/reference/generated/np.std.html for v1, v2 in zip(vals, expected): if v1 is None: assert v2 is None continue assert round(v1, 5) == round(v2, 5)
def test_moving_stddev(self): trade_history = factory.create_trade_history(133, [10.0, 15.0, 13.0, 12.0], [100, 100, 100, 100], timedelta(hours=1), self.trading_environment) stddev = MovingStandardDev( market_aware=False, delta=timedelta(minutes=150), ) self.source = SpecificEquityTrades(event_list=trade_history) transformed = list(stddev.transform(self.source)) vals = [message.tnfm_value for message in transformed] expected = [ None, np.std([10.0, 15.0], ddof=1), np.std([10.0, 15.0, 13.0], ddof=1), np.std([15.0, 13.0, 12.0], ddof=1), ] # np has odd rounding behavior, cf. # http://docs.scipy.org/doc/np/reference/generated/np.std.html for v1, v2 in zip(vals, expected): if v1 is None: assert v2 is None continue assert round(v1, 5) == round(v2, 5)
def test_commission_event(self): with trading.TradingEnvironment(): events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) cash_adj_dt = self.sim_params.period_start \ + datetime.timedelta(hours=3) cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) # Insert a purchase order. events.insert(0, create_txn(events[0], 20, 1)) events.insert(1, cash_adjustment) results = calculate_results(self, events) # Validate that we lost 320 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9680) # Validate that the cost basis of our position changed. self.assertEqual(results[-1]['daily_perf']['positions'] [0]['cost_basis'], 320.0)
def test_returns(self): # Daily returns. returns = Returns(1) transformed = list(returns.transform(self.source)) tnfm_vals = [message[returns.get_hash()] for message in transformed] # No returns for the first event because we don't have a # previous close. expected = [0.0, 0.0, 0.1, 0.0] self.assertEquals(tnfm_vals, expected) # Two-day returns. An extra kink here is that the # factory will automatically skip a weekend for the # last event. Results shouldn't notice this blip. trade_history = factory.create_trade_history( 133, [10.0, 15.0, 13.0, 12.0, 13.0], [100, 100, 100, 300, 100], timedelta(days=1), self.trading_environment ) self.source = SpecificEquityTrades(event_list=trade_history) returns = StatefulTransform(Returns, 2) transformed = list(returns.transform(self.source)) tnfm_vals = [message[returns.get_hash()] for message in transformed] expected = [0.0, 0.0, (13.0 - 10.0) / 10.0, (12.0 - 15.0) / 15.0, (13.0 - 13.0) / 13.0] self.assertEquals(tnfm_vals, expected)
def test_long_position_receives_dividend(self): # post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, # declared date, when the algorithm finds out about # the dividend events[1].dt, # ex_date, when the algorithm is credited with the # dividend events[1].dt, # pay date, when the algorithm receives the dividend. events[2].dt, ) txn = create_txn(1, 10.0, 100, events[0].dt) events.insert(0, txn) events.insert(1, dividend) results = calculate_results(self, events) self.assertEqual(len(results), 5) cumulative_returns = [event["cumulative_perf"]["returns"] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.1, 0.1, 0.1]) daily_returns = [event["daily_perf"]["returns"] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.10, 0.0, 0.0]) cash_flows = [event["daily_perf"]["capital_used"] for event in results] self.assertEqual(cash_flows, [-1000, 0, 1000, 0, 0]) cumulative_cash_flows = [event["cumulative_perf"]["capital_used"] for event in results] self.assertEqual(cumulative_cash_flows, [-1000, -1000, 0, 0, 0]) cash_pos = [event["cumulative_perf"]["ending_cash"] for event in results] self.assertEqual(cash_pos, [9000, 9000, 10000, 10000, 10000])
def setUp(self): self.sim_params = factory.create_simulation_parameters() setup_logger(self) trade_history = factory.create_trade_history( 133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params ) self.source = SpecificEquityTrades(event_list=trade_history)
def setUp(self): self.sim_params = factory.create_simulation_parameters(num_days=4) trade_history = factory.create_trade_history( 133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) self.df_source, self.df = factory.create_test_df_source(self.sim_params)
def setUp(self): self.sim_params = factory.create_simulation_parameters(num_days=4) self.sid = 133 self.trade_history = factory.create_trade_history( self.sid, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params) self.source = SpecificEquityTrades(event_list=self.trade_history)
def setUp(self): self.trading_environment = factory.create_trading_environment() setup_logger(self) trade_history = factory.create_trade_history( 133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.trading_environment ) self.source = SpecificEquityTrades(event_list=trade_history)
def test_split_long_position(self): events = factory.create_trade_history(1, [20, 20], [100, 100], oneday, self.sim_params) # set up a long position in sid 1 # 100 shares at $20 apiece = $2000 position txns = [create_txn(events[0], 20, 100)] # set up a split with ratio 3 occurring at the start of the second # day. splits = [ factory.create_split( 1, 3, events[1].dt, ), ] results = calculate_results(self, events, txns=txns, splits=splits) # should have 33 shares (at $60 apiece) and $20 in cash self.assertEqual(2, len(results)) latest_positions = results[1]['daily_perf']['positions'] self.assertEqual(1, len(latest_positions)) # check the last position to make sure it's been updated position = latest_positions[0] self.assertEqual(1, position['sid']) self.assertEqual(33, position['amount']) self.assertEqual(60, position['cost_basis']) self.assertEqual(60, position['last_sale_price']) # since we started with $10000, and we spent $2000 on the # position, but then got $20 back, we should have $8020 # (or close to it) in cash. # we won't get exactly 8020 because sometimes a split is # denoted as a ratio like 0.3333, and we lose some digits # of precision. thus, make sure we're pretty close. daily_perf = results[1]['daily_perf'] self.assertTrue( zp_math.tolerant_equals(8020, daily_perf['ending_cash'], 1)) for i, result in enumerate(results): for perf_kind in ('daily_perf', 'cumulative_perf'): perf_result = result[perf_kind] # prices aren't changing, so pnl and returns should be 0.0 self.assertEqual( 0.0, perf_result['pnl'], "day %s %s pnl %s instead of 0.0" % (i, perf_kind, perf_result['pnl'])) self.assertEqual( 0.0, perf_result['returns'], "day %s %s returns %s instead of 0.0" % (i, perf_kind, perf_result['returns']))
def test_split_long_position(self): with trading.TradingEnvironment() as env: events = factory.create_trade_history( 1, [20, 20], [100, 100], oneday, self.sim_params ) # set up a long position in sid 1 # 100 shares at $20 apiece = $2000 position events.insert(0, create_txn(events[0], 20, 100)) # set up a split with ratio 3 events.append(factory.create_split(1, 3, env.next_trading_day(events[1].dt))) results = calculate_results(self, events) # should have 33 shares (at $60 apiece) and $20 in cash self.assertEqual(2, len(results)) latest_positions = results[1]['daily_perf']['positions'] self.assertEqual(1, len(latest_positions)) # check the last position to make sure it's been updated position = latest_positions[0] self.assertEqual(1, position['sid']) self.assertEqual(33, position['amount']) self.assertEqual(60, position['cost_basis']) self.assertEqual(60, position['last_sale_price']) # since we started with $10000, and we spent $2000 on the # position, but then got $20 back, we should have $8020 # (or close to it) in cash. # we won't get exactly 8020 because sometimes a split is # denoted as a ratio like 0.3333, and we lose some digits # of precision. thus, make sure we're pretty close. daily_perf = results[1]['daily_perf'] self.assertTrue( zp_math.tolerant_equals(8020, daily_perf['ending_cash'], 1)) for i, result in enumerate(results): for perf_kind in ('daily_perf', 'cumulative_perf'): perf_result = result[perf_kind] # prices aren't changing, so pnl and returns should be 0.0 self.assertEqual(0.0, perf_result['pnl'], "day %s %s pnl %s instead of 0.0" % (i, perf_kind, perf_result['pnl'])) self.assertEqual(0.0, perf_result['returns'], "day %s %s returns %s instead of 0.0" % (i, perf_kind, perf_result['returns']))
def test_long_position(self): """ verify that the performance period calculates properly for a single buy transaction """ # post some trades in the market trades = factory.create_trade_history(1, [10, 10, 10, 11], [100, 100, 100, 100], onesec, self.sim_params) txn = create_txn(trades[1], 10.0, 100) pp = perf.PerformancePeriod(1000.0) pp.execute_transaction(txn) # This verifies that the last sale price is being correctly # set in the positions. If this is not the case then returns can # incorrectly show as sharply dipping if a transaction arrives # before a trade. This is caused by returns being based on holding # stocks with a last sale price of 0. self.assertEqual(pp.positions[1].last_sale_price, 10.0) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() self.assertEqual( pp.period_cash_flow, -1 * txn.price * txn.amount, "capital used should be equal to the opposite of the transaction \ cost of sole txn in test") self.assertEqual(len(pp.positions), 1, "should be just one position") self.assertEqual(pp.positions[1].sid, txn.sid, "position should be in security with id 1") self.assertEqual( pp.positions[1].amount, txn.amount, "should have a position of {sharecount} shares".format( sharecount=txn.amount)) self.assertEqual(pp.positions[1].cost_basis, txn.price, "should have a cost basis of 10") self.assertEqual( pp.positions[1].last_sale_price, trades[-1]['price'], "last sale should be same as last trade. \ expected {exp} actual {act}".format( exp=trades[-1]['price'], act=pp.positions[1].last_sale_price)) self.assertEqual( pp.ending_value, 1100, "ending value should be price of last trade times number of \ shares in position") self.assertEqual(pp.pnl, 100, "gain of 1 on 100 shares should be 100")
def setUp(self): self.trading_environment = factory.create_trading_environment() setup_logger(self) trade_history = factory.create_trade_history(133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.trading_environment) self.source = SpecificEquityTrades(event_list=trade_history)
def setUp(self): self.sim_params = factory.create_simulation_parameters() trade_history = factory.create_trade_history(133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params) self.source = SpecificEquityTrades(event_list=trade_history) self.df_source, self.df = \ factory.create_test_df_source(self.sim_params)
def setUp(self): self.sim_params = factory.create_simulation_parameters() setup_logger(self) trade_history = factory.create_trade_history(133, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params) self.source = trade_history
def test_covering_short(self): """verify performance where short is bought and covered, and shares \ trade after cover""" trades = factory.create_trade_history( 1, [10, 10, 10, 11, 9, 8, 7, 8, 9, 10], [100, 100, 100, 100, 100, 100, 100, 100, 100, 100], onesec, self.sim_params) short_txn = create_txn( trades[1], 10.0, -100, ) cover_txn = create_txn(trades[6], 7.0, 100) pp = perf.PerformancePeriod(1000.0) pp.execute_transaction(short_txn) pp.execute_transaction(cover_txn) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() short_txn_cost = short_txn.price * short_txn.amount cover_txn_cost = cover_txn.price * cover_txn.amount self.assertEqual( pp.period_cash_flow, -1 * short_txn_cost - cover_txn_cost, "capital used should be equal to the net transaction costs") self.assertEqual(len(pp.positions), 1, "should be just one position") self.assertEqual( pp.positions[1].sid, short_txn.sid, "position should be in security from the transaction") self.assertEqual(pp.positions[1].amount, 0, "should have a position of -100 shares") self.assertEqual(pp.positions[1].cost_basis, 0, "a covered position should have a cost basis of 0") self.assertEqual(pp.positions[1].last_sale_price, trades[-1].price, "last sale should be price of last trade") self.assertEqual( pp.ending_value, 0, "ending value should be price of last trade times number of \ shares in position") self.assertEqual(pp.pnl, 300, "gain of 1 on 100 shares should be 300")
def test_ending_before_pay_date(self): #post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, events[0].dt, events[1].dt, events[-1].dt + 10 * oneday ) buy_txn = create_txn(1, 10.0, 100, events[1].dt) events.insert(2, buy_txn) events.insert(1, dividend) perf_tracker = perf.PerformanceTracker(self.sim_params) all_events = (msg[1] for msg in heapq.merge( ((event.dt, event) for event in events), ((event.dt, event) for event in self.benchmark_events))) transformed_events = list(perf_tracker.transform( itertools.groupby(all_events, attrgetter('dt')))) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0.0, 0.0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0, 0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, -1000, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual( cumulative_cash_flows, [0, -1000, -1000, -1000, -1000] )
def test_long_position_receives_dividend(self): #post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.trading_environment ) dividend = factory.create_dividend( 1, 10.00, events[0].dt, events[1].dt, events[2].dt ) events.insert(1, dividend) txn = factory.create_txn(1, 10.0, 100, self.dt+oneday) events[2].TRANSACTION = txn perf_tracker = perf.PerformanceTracker(self.trading_environment) transformed_events = list(perf_tracker.transform( ((event.dt, [event]) for event in events)) ) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(results[0]['daily_perf']['period_open'], events[0].dt) self.assertEqual( results[-1]['daily_perf']['period_open'], events[-1].dt ) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.1, 0.1, 0.1]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.10, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, -1000, 1000, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, -1000, 0, 0, 0])
def test_long_position_receives_dividend(self): #post some trades in the market events = factory.create_trade_history(1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) dividend = factory.create_dividend( 1, 10.00, # declared date, when the algorithm finds out about # the dividend events[1].dt, # ex_date, when the algorithm is credited with the # dividend events[1].dt, # pay date, when the algorithm receives the dividend. events[2].dt) txn = factory.create_txn(1, 10.0, 100, events[0].dt) events[0].TRANSACTION = txn events.insert(1, dividend) perf_tracker = perf.PerformanceTracker(self.sim_params) transformed_events = list( perf_tracker.transform(((event.dt, [event]) for event in events))) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(results[0]['daily_perf']['period_open'], events[0].dt) self.assertEqual(results[-1]['daily_perf']['period_open'], events[-1].dt) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.1, 0.1, 0.1]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.10, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [-1000, 0, 1000, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [-1000, -1000, 0, 0, 0]) cash_pos = \ [event['cumulative_perf']['ending_cash'] for event in results] self.assertEqual(cash_pos, [9000, 9000, 10000, 10000, 10000])
def test_buy_and_sell_before_ex(self): #post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10, 10], [100, 100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, events[3].dt, events[4].dt, events[5].dt ) buy_txn = create_txn(1, 10.0, 100, events[1].dt) events.insert(2, buy_txn) sell_txn = create_txn(1, 10.0, -100, events[3].dt) events.insert(4, sell_txn) events.insert(1, dividend) perf_tracker = perf.PerformanceTracker(self.sim_params) all_events = heapq.merge( ((event.dt, event) for event in events), ((event.dt, event) for event in self.benchmark_events)) transformed_events = list(perf_tracker.transform( (event[0], [event[1]]) for event in all_events)) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(len(results), 6) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0, 0, 0]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0, 0, 0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [0, -1000, 1000, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, -1000, 0, 0, 0, 0])
def test_long_position_receives_stock_dividend(self): with trading.TradingEnvironment(): # post some trades in the market events = [] for sid in (1, 2): events.extend( factory.create_trade_history( sid, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) ) dividend = factory.create_stock_dividend( 1, payment_sid=2, ratio=2, # declared date, when the algorithm finds out about # the dividend declared_date=events[0].dt, # ex_date, the date before which the algorithm must hold stock # to receive the dividend ex_date=events[1].dt, # pay date, when the algorithm receives the dividend. pay_date=events[2].dt ) txns = [create_txn(events[0], 10.0, 100)] results = calculate_results( self, events, dividend_events=[dividend], txns=txns, ) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.2, 0.2, 0.2]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0.0, 0.0, 0.2, 0.0, 0.0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [-1000, 0, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [-1000] * 5) cash_pos = \ [event['cumulative_perf']['ending_cash'] for event in results] self.assertEqual(cash_pos, [9000] * 5)
def setUp(self): self.sim_params = factory.create_simulation_parameters(num_days=4) self.sidint = 133 self.trade_history = factory.create_trade_history( self.sidint, [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), self.sim_params ) self.source = SpecificEquityTrades(event_list=self.trade_history)
def test_long_position(self): """ verify that the performance period calculates properly for a single buy transaction """ # post some trades in the market trades = factory.create_trade_history(1, [10, 10, 10, 11], [100, 100, 100, 100], onesec, self.sim_params) txn = create_txn(1, 10.0, 100, self.dt + onesec) pp = perf.PerformancePeriod(1000.0) pp.execute_transaction(txn) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() self.assertEqual( pp.period_cash_flow, -1 * txn.price * txn.amount, "capital used should be equal to the opposite of the transaction \ cost of sole txn in test", ) self.assertEqual(len(pp.positions), 1, "should be just one position") self.assertEqual(pp.positions[1].sid, txn.sid, "position should be in security with id 1") self.assertEqual( pp.positions[1].amount, txn.amount, "should have a position of {sharecount} shares".format(sharecount=txn.amount), ) self.assertEqual(pp.positions[1].cost_basis, txn.price, "should have a cost basis of 10") self.assertEqual( pp.positions[1].last_sale_price, trades[-1]["price"], "last sale should be same as last trade. \ expected {exp} actual {act}".format( exp=trades[-1]["price"], act=pp.positions[1].last_sale_price ), ) self.assertEqual( pp.ending_value, 1100, "ending value should be price of last trade times number of \ shares in position", ) self.assertEqual(pp.pnl, 100, "gain of 1 on 100 shares should be 100")
def test_covering_short(self): """verify performance where short is bought and covered, and shares \ trade after cover""" trades = factory.create_trade_history( 1, [10, 10, 10, 11, 9, 8, 7, 8, 9, 10], [100, 100, 100, 100, 100, 100, 100, 100, 100, 100], onesec, self.sim_params, ) short_txn = create_txn(1, 10.0, -100, self.dt + onesec) cover_txn = create_txn(1, 7.0, 100, self.dt + onesec * 6) pp = perf.PerformancePeriod(1000.0) pp.execute_transaction(short_txn) pp.execute_transaction(cover_txn) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() short_txn_cost = short_txn.price * short_txn.amount cover_txn_cost = cover_txn.price * cover_txn.amount self.assertEqual( pp.period_cash_flow, -1 * short_txn_cost - cover_txn_cost, "capital used should be equal to the net transaction costs", ) self.assertEqual(len(pp.positions), 1, "should be just one position") self.assertEqual(pp.positions[1].sid, short_txn.sid, "position should be in security from the transaction") self.assertEqual(pp.positions[1].amount, 0, "should have a position of -100 shares") self.assertEqual(pp.positions[1].cost_basis, 0, "a covered position should have a cost basis of 0") self.assertEqual(pp.positions[1].last_sale_price, trades[-1].price, "last sale should be price of last trade") self.assertEqual( pp.ending_value, 0, "ending value should be price of last trade times number of \ shares in position", ) self.assertEqual(pp.pnl, 300, "gain of 1 on 100 shares should be 300")
def test_algo_without_rl_violation(self): sim_params = factory.create_simulation_parameters(start=list( LEVERAGED_ETFS.keys())[0], num_days=4) trade_history = factory.create_trade_history('AAPL', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='AAPL', sim_params=sim_params) algo.run(self.source)
def setUp(self): days = 251 self.sim_params = factory.create_simulation_parameters(num_days=days) setup_logger(self) trade_history = factory.create_trade_history( 133, [10.0] * days, [100] * days, timedelta(days=1), self.sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) self.df_source, self.df = factory.create_test_df_source(self.sim_params) self.zipline_test_config = {"sid": 0}
def test_long_position_receives_stock_dividend(self): with trading.TradingEnvironment(): # post some trades in the market events = [] for sid in (1, 2): events.extend( factory.create_trade_history(sid, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params)) dividend = factory.create_stock_dividend( 1, payment_sid=2, ratio=2, # declared date, when the algorithm finds out about # the dividend declared_date=events[0].dt, # ex_date, the date before which the algorithm must hold stock # to receive the dividend ex_date=events[1].dt, # pay date, when the algorithm receives the dividend. pay_date=events[2].dt) txns = [create_txn(events[0], 10.0, 100)] results = calculate_results( self, events, dividend_events=[dividend], txns=txns, ) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0.0, 0.0, 0.2, 0.2, 0.2]) daily_returns = [ event['daily_perf']['returns'] for event in results ] self.assertEqual(daily_returns, [0.0, 0.0, 0.2, 0.0, 0.0]) cash_flows = [ event['daily_perf']['capital_used'] for event in results ] self.assertEqual(cash_flows, [-1000, 0, 0, 0, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [-1000] * 5) cash_pos = \ [event['cumulative_perf']['ending_cash'] for event in results] self.assertEqual(cash_pos, [9000] * 5)
def test_long_position(self): """ verify that the performance period calculates properly for a single buy transaction """ #post some trades in the market trades = factory.create_trade_history(1, [10, 10, 10, 11], [100, 100, 100, 100], self.onesec, self.trading_environment) txn = factory.create_txn(1, 10.0, 100, self.dt + self.onesec) pp = perf.PerformancePeriod({}, 0.0, 1000.0) pp.execute_transaction(txn) for trade in trades: pp.update_last_sale(trade) pp.calculate_performance() self.assertEqual( pp.period_capital_used, -1 * txn.price * txn.amount, "capital used should be equal to the opposite of the transaction \ cost of sole txn in test") self.assertEqual(len(pp.positions), 1, "should be just one position") self.assertEqual(pp.positions[1].sid, txn.sid, "position should be in security with id 1") self.assertEqual( pp.positions[1].amount, txn.amount, "should have a position of {sharecount} shares".format( sharecount=txn.amount)) self.assertEqual(pp.positions[1].cost_basis, txn.price, "should have a cost basis of 10") self.assertEqual( pp.positions[1].last_sale_price, trades[-1]['price'], "last sale should be same as last trade. \ expected {exp} actual {act}".format( exp=trades[-1]['price'], act=pp.positions[1].last_sale_price)) self.assertEqual( pp.ending_value, 1100, "ending value should be price of last trade times number of \ shares in position") self.assertEqual(pp.pnl, 100, "gain of 1 on 100 shares should be 100")
def test_commission_event(self): with trading.TradingEnvironment(): events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) # Test commission models and validate result # Expected commission amounts: # PerShare commission: 1.00, 1.00, 1.50 = $3.50 # PerTrade commission: 5.00, 5.00, 5.00 = $15.00 # PerDollar commission: 1.50, 3.00, 4.50 = $9.00 # Total commission = $3.50 + $15.00 + $9.00 = $27.50 # Create 3 transactions: 50, 100, 150 shares traded @ $20 transactions = [create_txn(events[0], 20, i) for i in [50, 100, 150]] # Create commission models and validate that produce expected # commissions. models = [PerShare(cost=0.01, min_trade_cost=1.00), PerTrade(cost=5.00), PerDollar(cost=0.0015)] expected_results = [3.50, 15.0, 9.0] for model, expected in zip(models, expected_results): total_commission = 0 for trade in transactions: total_commission += model.calculate(trade)[1] self.assertEqual(total_commission, expected) # Verify that commission events are handled correctly by # PerformanceTracker. cash_adj_dt = events[0].dt cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) events.append(cash_adjustment) # Insert a purchase order. txns = [create_txn(events[0], 20, 1)] results = calculate_results(self, events, txns=txns) # Validate that we lost 320 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9680) # Validate that the cost basis of our position changed. self.assertEqual(results[-1]['daily_perf']['positions'] [0]['cost_basis'], 320.0)
def test_algo_without_rl_violation(self): sim_params = factory.create_simulation_parameters( start=list(LEVERAGED_ETFS.keys())[0], num_days=4) trade_history = factory.create_trade_history( 'AAPL', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params ) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(sid='AAPL', sim_params=sim_params) algo.run(self.source)
def test_iterate_over_rl(self): sim_params = factory.create_simulation_parameters(start=list( LEVERAGED_ETFS.keys())[0], num_days=4) trade_history = factory.create_trade_history('BZQ', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params) self.source = SpecificEquityTrades(event_list=trade_history) algo = IterateRLAlgo(symbol='BZQ', sim_params=sim_params) algo.run(self.source) self.assertTrue(algo.found)
def test_commission_event(self): with trading.TradingEnvironment(): events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) # Test commission models and validate result # Expected commission amounts: # PerShare commission: 1.00, 1.00, 1.50 = $3.50 # PerTrade commission: 5.00, 5.00, 5.00 = $15.00 # PerDollar commission: 1.50, 3.00, 4.50 = $9.00 # Total commission = $3.50 + $15.00 + $9.00 = $27.50 # Create 3 transactions: 50, 100, 150 shares traded @ $20 transactions = [create_txn(events[0], 20, i) for i in [50, 100, 150]] # Create commission models models = [PerShare(cost=0.01, min_trade_cost=1.00), PerTrade(cost=5.00), PerDollar(cost=0.0015)] # Aggregate commission amounts total_commission = 0 for model in models: for trade in transactions: total_commission += model.calculate(trade)[1] self.assertEqual(total_commission, 27.5) cash_adj_dt = self.sim_params.first_open \ + datetime.timedelta(hours=3) cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) # Insert a purchase order. events.insert(0, create_txn(events[0], 20, 1)) events.insert(1, cash_adjustment) results = calculate_results(self, events) # Validate that we lost 320 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9680) # Validate that the cost basis of our position changed. self.assertEqual(results[-1]['daily_perf']['positions'] [0]['cost_basis'], 320.0)
def test_commission_event(self): with trading.TradingEnvironment(): events = factory.create_trade_history(1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params) # Test commission models and validate result # Expected commission amounts: # PerShare commission: 1.00, 1.00, 1.50 = $3.50 # PerTrade commission: 5.00, 5.00, 5.00 = $15.00 # PerDollar commission: 1.50, 3.00, 4.50 = $9.00 # Total commission = $3.50 + $15.00 + $9.00 = $27.50 # Create 3 transactions: 50, 100, 150 shares traded @ $20 transactions = [ create_txn(events[0], 20, i) for i in [50, 100, 150] ] # Create commission models and validate that produce expected # commissions. models = [ PerShare(cost=0.01, min_trade_cost=1.00), PerTrade(cost=5.00), PerDollar(cost=0.0015) ] expected_results = [3.50, 15.0, 9.0] for model, expected in zip(models, expected_results): total_commission = 0 for trade in transactions: total_commission += model.calculate(trade)[1] self.assertEqual(total_commission, expected) # Verify that commission events are handled correctly by # PerformanceTracker. cash_adj_dt = events[0].dt cash_adjustment = factory.create_commission(1, 300.0, cash_adj_dt) events.append(cash_adjustment) # Insert a purchase order. txns = [create_txn(events[0], 20, 1)] results = calculate_results(self, events, txns=txns) # Validate that we lost 320 dollars from our cash pool. self.assertEqual(results[-1]['cumulative_perf']['ending_cash'], 9680) # Validate that the cost basis of our position changed. self.assertEqual( results[-1]['daily_perf']['positions'][0]['cost_basis'], 320.0)
def test_selling_before_dividend_payment_still_gets_paid(self): #post some trades in the market events = factory.create_trade_history( 1, [10, 10, 10, 10, 10], [100, 100, 100, 100, 100], oneday, self.sim_params ) dividend = factory.create_dividend( 1, 10.00, events[0].dt, events[1].dt, events[3].dt ) buy_txn = factory.create_txn(1, 10.0, 100, events[0].dt) events[0].TRANSACTION = buy_txn sell_txn = factory.create_txn(1, 10.0, -100, events[2].dt) events[2].TRANSACTION = sell_txn events.insert(1, dividend) perf_tracker = perf.PerformanceTracker(self.sim_params) transformed_events = list(perf_tracker.transform( ((event.dt, [event]) for event in events)) ) #flatten the list of events results = [] for te in transformed_events: for event in te[1]: for message in event.perf_messages: results.append(message) perf_messages, risk = perf_tracker.handle_simulation_end() results.append(perf_messages[0]) self.assertEqual(len(results), 5) cumulative_returns = \ [event['cumulative_perf']['returns'] for event in results] self.assertEqual(cumulative_returns, [0, 0, 0, 0.1, 0.1]) daily_returns = [event['daily_perf']['returns'] for event in results] self.assertEqual(daily_returns, [0, 0, 0, 0.1, 0]) cash_flows = [event['daily_perf']['capital_used'] for event in results] self.assertEqual(cash_flows, [-1000, 0, 1000, 1000, 0]) cumulative_cash_flows = \ [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [-1000, -1000, 0, 1000, 1000])
def test_algo_with_rl_violation_after_add(self): with security_list_copy(): add_security_data(['AAPL'], []) sim_params = factory.create_simulation_parameters( start=self.trading_day_before_first_kd, num_days=4) trade_history = factory.create_trade_history( 'AAPL', [10.0, 10.0, 11.0, 11.0], [100, 100, 100, 300], timedelta(days=1), sim_params) self.source = SpecificEquityTrades(event_list=trade_history) algo = RestrictedAlgoWithoutCheck(symbol='AAPL', sim_params=sim_params) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.source) self.check_algo_exception(algo, ctx, 2)