def test_calculate_impact_without_history(self): model = VolatilityVolumeShare(volume_limit=1) late_start_asset = self.asset_finder.retrieve_asset(1000) early_start_asset = self.asset_finder.retrieve_asset(1001) cases = [ # History will look for data before the start date. (pd.Timestamp('2006-01-05 11:35AM', tz='UTC'), early_start_asset), # Start day of the futures contract; no history yet. (pd.Timestamp('2006-02-10 11:35AM', tz='UTC'), late_start_asset), # Only a week's worth of history data. (pd.Timestamp('2006-02-17 11:35AM', tz='UTC'), late_start_asset), ] for minute, asset in cases: data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order(dt=data.current_dt, asset=asset, amount=10) price, amount = model.process_order(data, order) avg_price = (data.current(asset, 'high') + data.current(asset, 'low')) / 2 expected_price = \ avg_price * (1 + model.NO_DATA_VOLATILITY_SLIPPAGE_IMPACT) self.assertAlmostEqual(price, expected_price, delta=0.001) self.assertEqual(amount, 10)
def __init__(self, data_frequency, equity_slippage=None, future_slippage=None, equity_commission=None, future_commission=None, cancel_policy=None): # these orders are aggregated by asset self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # holding orders that have come in since the last event. self.new_orders = [] self.current_dt = None self.max_shares = int(1e+11) self.slippage_models = { Equity: equity_slippage or VolumeShareSlippage(), Future: future_slippage or VolatilityVolumeShare( volume_limit=DEFAULT_FUTURE_VOLUME_SLIPPAGE_BAR_LIMIT, ), } self.commission_models = { Equity: equity_commission or PerShare(), Future: future_commission or PerContract( cost=DEFAULT_PER_CONTRACT_COST, exchange_fee=FUTURE_EXCHANGE_FEES_BY_SYMBOL, ), } self.data_frequency = data_frequency self.cancel_policy = cancel_policy if cancel_policy else NeverCancel()
def test_low_transaction_volume(self): # With a volume limit of 0.001, and a bar volume of 100, we should # compute a transaction volume of 100 * 0.001 = 0.1, which gets rounded # down to zero. In this case we expect no amount to be transacted. model = VolatilityVolumeShare(volume_limit=0.001) minute = pd.Timestamp('2006-03-01 11:35AM', tz='UTC') data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order(dt=data.current_dt, asset=self.ASSET, amount=10) price, amount = model.process_order(data, order) self.assertIsNone(price) self.assertIsNone(amount)
def test_impacted_price_worse_than_limit(self): model = VolatilityVolumeShare(volume_limit=0.05) # Use all the same numbers from the 'calculate_impact' tests. Since the # impacted price is 59805.5, which is worse than the limit price of # 59800, the model should return None. minute = pd.Timestamp('2006-03-01 11:35AM', tz='UTC') data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order( dt=data.current_dt, asset=self.ASSET, amount=10, limit=59800, ) price, amount = model.process_order(data, order) self.assertIsNone(price) self.assertIsNone(amount)
def test_window_data(self): session = pd.Timestamp('2006-03-01') minute = self.trading_calendar.minutes_for_session(session)[1] data = self.create_bardata(simulation_dt_func=lambda: minute) asset = self.asset_finder.retrieve_asset(1) mean_volume, volatility = VolatilityVolumeShare(0.0)._get_window_data( data, asset, window_length=20, ) # close volume # 2006-01-31 00:00:00+00:00 29.0 119.0 # 2006-02-01 00:00:00+00:00 30.0 120.0 # 2006-02-02 00:00:00+00:00 31.0 121.0 # 2006-02-03 00:00:00+00:00 32.0 122.0 # 2006-02-06 00:00:00+00:00 33.0 123.0 # 2006-02-07 00:00:00+00:00 34.0 124.0 # 2006-02-08 00:00:00+00:00 35.0 125.0 # 2006-02-09 00:00:00+00:00 36.0 126.0 # 2006-02-10 00:00:00+00:00 37.0 127.0 # 2006-02-13 00:00:00+00:00 38.0 128.0 # 2006-02-14 00:00:00+00:00 39.0 129.0 # 2006-02-15 00:00:00+00:00 40.0 130.0 # 2006-02-16 00:00:00+00:00 41.0 131.0 # 2006-02-17 00:00:00+00:00 42.0 132.0 # 2006-02-21 00:00:00+00:00 43.0 133.0 # 2006-02-22 00:00:00+00:00 44.0 134.0 # 2006-02-23 00:00:00+00:00 45.0 135.0 # 2006-02-24 00:00:00+00:00 46.0 136.0 # 2006-02-27 00:00:00+00:00 47.0 137.0 # 2006-02-28 00:00:00+00:00 48.0 138.0 # Mean volume is (119 + 138) / 2 = 128.5 self.assertEqual(mean_volume, 128.5) # Volatility is closes.pct_change().std() * sqrt(252) reference_vol = pd.Series(range(29, 49)).pct_change().std() * sqrt(252) self.assertEqual(volatility, reference_vol)
def _calculate_impact(self, test_order, answer_key): model = VolatilityVolumeShare(volume_limit=0.05) first_minute = pd.Timestamp('2006-03-31 11:35AM', tz='UTC') next_3_minutes = self.trading_calendar.minutes_window(first_minute, 3) remaining_shares = test_order.open_amount for i, minute in enumerate(next_3_minutes): data = self.create_bardata(simulation_dt_func=lambda: minute) new_order = Order( dt=data.current_dt, asset=self.ASSET, amount=remaining_shares, ) price, amount = model.process_order(data, new_order) self.assertEqual(price, answer_key[i][0]) self.assertEqual(amount, answer_key[i][1]) amount = amount or 0 if remaining_shares < 0: remaining_shares = min(0, remaining_shares - amount) else: remaining_shares = max(0, remaining_shares - amount)