def test_weigh_inv_vol(): algo = algos.WeighInvVol(lookback=pd.DateOffset(days=5)) s = bt.Strategy('s') dts = pd.date_range('2010-01-01', periods=5) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100.) # high vol c1 data['c1'].ix[dts[1]] = 105 data['c1'].ix[dts[2]] = 95 data['c1'].ix[dts[3]] = 105 data['c1'].ix[dts[4]] = 95 # low vol c2 data['c2'].ix[dts[1]] = 100.1 data['c2'].ix[dts[2]] = 99.9 data['c2'].ix[dts[3]] = 100.1 data['c2'].ix[dts[4]] = 99.9 s.setup(data) s.update(dts[4]) s.temp['selected'] = ['c1', 'c2'] assert algo(s) weights = s.temp['weights'] assert len(weights) == 2 assert weights['c2'] > weights['c1'] aae(weights['c1'], 0.020, 3) aae(weights['c2'], 0.980, 3)
def test_weigh_inv_vol(): algo = algos.WeighInvVol(lookback=pd.DateOffset(days=5)) s = bt.Strategy("s") dts = pd.date_range("2010-01-01", periods=5) data = pd.DataFrame(index=dts, columns=["c1", "c2"], data=100.0) # high vol c1 data["c1"].ix[dts[1]] = 105 data["c1"].ix[dts[2]] = 95 data["c1"].ix[dts[3]] = 105 data["c1"].ix[dts[4]] = 95 # low vol c2 data["c2"].ix[dts[1]] = 100.1 data["c2"].ix[dts[2]] = 99.9 data["c2"].ix[dts[3]] = 100.1 data["c2"].ix[dts[4]] = 99.9 s.setup(data) s.update(dts[4]) s.temp["selected"] = ["c1", "c2"] assert algo(s) weights = s.temp["weights"] assert len(weights) == 2 assert weights["c2"] > weights["c1"] aae(weights["c1"], 0.020, 3) aae(weights["c2"], 0.980, 3)
def test_weigh_randomly(): s = bt.Strategy('s') s.temp['selected'] = ['c1', 'c2', 'c3'] algo = algos.WeighRandomly() assert algo(s) weights = s.temp['weights'] assert len( weights ) == 3 assert sum( weights.values() ) == 1. algo = algos.WeighRandomly( (0.3,0.5), 0.95) assert algo(s) weights = s.temp['weights'] assert len( weights ) == 3 aae( sum( weights.values() ), 0.95 ) for c in s.temp['selected']: assert weights[c] <= 0.5 assert weights[c] >= 0.3
def test_strategy_tree_paper(): dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['a'], data=100.) data['a'].ix[dts[1]] = 101 data['a'].ix[dts[2]] = 102 s = Strategy('s', [ bt.algos.SelectWhere(data > 100), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) m = Strategy('m', [], [s]) s = m['s'] m.setup(data) m.update(dts[0]) m.run() assert m.price == 100 assert s.price == 100 assert s._paper_trade assert s._paper.price == 100 s.update(dts[1]) m.run() assert m.price == 100 assert m.value == 0 assert s.value == 0 assert s.price == 99.9901 s.update(dts[2]) m.run() assert m.price == 100 assert m.value == 0 assert s.value == 0 aae(s.price, 100.9801, 4)
def test_strategy_tree_paper(): dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['a'], data=100.) data['a'].ix[dts[1]] = 101 data['a'].ix[dts[2]] = 102 s = Strategy('s', [bt.algos.SelectWhere(data > 100), bt.algos.WeighEqually(), bt.algos.Rebalance()]) m = Strategy('m', [], [s]) s = m['s'] m.setup(data) m.update(dts[0]) m.run() assert m.price == 100 assert s.price == 100 assert s._paper_trade assert s._paper.price == 100 s.update(dts[1]) m.run() assert m.price == 100 assert m.value == 0 assert s.value == 0 assert s.price == 99.9901 s.update(dts[2]) m.run() assert m.price == 100 assert m.value == 0 assert s.value == 0 aae(s.price, 100.9801, 4)
def test_strategybase_tree_decimal_position_rebalance(): c1 = SecurityBase('c1') c2 = SecurityBase('c2') s = StrategyBase('p', [c1, c2]) s.use_integer_positions(False) c1 = s['c1'] c2 = s['c2'] dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100) s.setup(data) i = 0 s.update(dts[i], data.ix[dts[i]]) s.adjust(1000.2) s.rebalance(0.42, 'c1') s.rebalance(0.58, 'c2') aae(c1.value, 420.084) aae(c2.value, 580.116) aae(c1.value + c2.value, 1000.2)
def test_strategybase_tree_rebalance_level2(): c1 = SecurityBase('c1') c12 = copy.deepcopy(c1) c2 = SecurityBase('c2') c22 = copy.deepcopy(c2) s1 = StrategyBase('s1', [c1, c2]) s2 = StrategyBase('s2', [c12, c22]) m = StrategyBase('m', [s1, s2]) s1 = m['s1'] s2 = m['s2'] c1 = s1['c1'] c2 = s1['c2'] c12 = s2['c1'] c22 = s2['c2'] dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100) data['c1'][dts[1]] = 105 data['c2'][dts[1]] = 95 m.setup(data) i = 0 m.update(dts[i], data.ix[dts[i]]) m.adjust(1000) assert m.value == 1000 assert m.capital == 1000 assert s1.value == 0 assert s2.value == 0 assert c1.value == 0 assert c2.value == 0 # now rebalance child s1 - since its children are 0, no waterfall alloc m.rebalance(0.5, 's1') assert s1.value == 500 assert m.capital == 1000 - 500 assert m.value == 1000 assert s1.weight == 500.0 / 1000 assert s2.weight == 0 # now allocate directly to child of child s1.rebalance(0.4, 'c1') assert s1.value == 499 assert s1.capital == 500 - 201 assert c1.value == 200 assert c1.weight == 200.0 / 499 assert c1.position == 2 assert m.capital == 1000 - 500 assert m.value == 999 assert s1.weight == 499.0 / 999 assert s2.weight == 0 assert c12.value == 0 # now rebalance child s1 again and make sure c1 also gets proportional # increase m.rebalance(0.8, 's1') assert s1.value == 798.2 aae(m.capital, 199.8, 1) assert m.value == 998 assert s1.weight == 798.2 / 998 assert s2.weight == 0 assert c1.value == 300.0 assert c1.weight == 300.0 / 798.2 assert c1.position == 3 # now rebalance child s1 to 0 - should close out s1 and c1 as well m.rebalance(0, 's1') assert s1.value == 0 assert m.capital == 997 assert m.value == 997 assert s1.weight == 0 assert s2.weight == 0 assert c1.weight == 0
def test_strategybase_prices(): dts = pd.date_range('2010-01-01', periods=21) rawd = [13.555, 13.75, 14.16, 13.915, 13.655, 13.765, 14.02, 13.465, 13.32, 14.65, 14.59, 14.175, 13.865, 13.865, 13.89, 13.85, 13.565, 13.47, 13.225, 13.385, 12.89] data = pd.DataFrame(index=dts, data=rawd, columns=['a']) s = StrategyBase('s') s.setup(data) # buy 100 shares on day 1 - hold until end # just enough to buy 100 shares + 1$ commission s.adjust(1356.50) s.update(dts[0]) # allocate all capital to child a # a should be dynamically created and should have # 100 shares allocated. s.capital should be 0 s.allocate(s.value, 'a') assert s.capital == 0 assert s.value == 1355.50 assert len(s.children) == 1 aae(s.price, 99.92628, 5) a = s['a'] assert a.position == 100 assert a.value == 1355.50 assert a.weight == 1 assert a.price == 13.555 assert len(a.prices) == 1 # update through all dates and make sure price is ok s.update(dts[1]) aae(s.price, 101.3638, 4) s.update(dts[2]) aae(s.price, 104.3863, 4) s.update(dts[3]) aae(s.price, 102.5802, 4) # finish updates and make sure ok at end for i in range(4, 21): s.update(dts[i]) assert len(s.prices) == 21 aae(s.prices[-1], 95.02396, 5) aae(s.prices[-2], 98.67306, 5)
def test_endpoints(self): self.check('/logviewer/') self.check('/logviewer/query/', code=404) # check query endpoints spec = self.get_keywith(conf.url, 'apps/logviewer/query-') base = '/logviewer/query/aggD' df = self.df df_user1 = df['user.id_1'].eq(1) df_uri1 = df['uri_1'].eq(1) # check filters for col in ['status', 'ip']: eq_(self.get('{}/filter{}/'.format(base, col)).json(), [{col: x} for x in sorted(df[col].unique())] ) eq_(self.get('{}/filter{}/'.format(base, 'users')).json(), [{'user.id': x} for x in sorted(df[df_user1]['user.id'].unique())] ) eq_(self.get('{}/filter{}/'.format(base, 'uri')).json(), (df[df_uri1]['uri'].value_counts() .astype(int) .rename_axis('uri').reset_index(name='views') .sort_values(by=['views', 'uri'], ascending=[False, True])[:100] .to_dict('r')) ) # check KPIs eq_(self.get('{}/kpi-{}/'.format(base, 'pageviews')).json(), [{'value': len(df[df_uri1].index)}] ) eq_(self.get('{}/kpi-{}/'.format(base, 'sessions')).json(), [{'value': df[df_user1]['new_session'].sum()}] ) eq_(self.get('{}/kpi-{}/'.format(base, 'users')).json(), [{'value': df[df_user1]['user.id'].nunique()}] ) eq_(self.get('{}/kpi-{}/'.format(base, 'urls')).json(), [{'value': df[df_uri1]['uri'].nunique()}] ) r = self.get('{}/kpi-{}/'.format(base, 'avgtimespent')).json() aae(r[0]['value'], df[df_user1]['session_time'].sum() / df[df_user1]['new_session'].sum(), 4) r = self.get('{}/kpi-{}/'.format(base, 'avgloadtime')).json() aae(r[0]['value'], df['duration'].mean(), 4) # check top10 topten = [{'col': 'user.id', 'url': 'users', 'values': 'views', 'flag': True}, {'col': 'ip', 'url': 'ip', 'values': 'requests'}, {'col': 'status', 'url': 'status', 'values': 'requests'}, {'col': 'uri', 'url': 'uri', 'values': 'views', 'flag': True}] for top in topten: cond = (df[top['col'] + '_1'].eq(1) if top.get('flag') else slice(None)) eq_(self.get('{}/topten{}/'.format(base, top['url'])).json(), (df[cond][top['col']].value_counts() .astype(int) .rename_axis(top['col']).reset_index(name=top['values']) .sort_values(by=[top['values'], top['col']], ascending=[False, True])[:10] .to_dict('r')) ) # check trend dff = logviewer.pdagg(df[df_uri1], [{'key': 'time', 'freq': 'D'}], {'duration': ['count']}) dff['time'] = dff['time'].dt.strftime('%Y-%m-%d 00:00:00') dff['pageviews'] = dff['duration_count'].astype(int) dff = dff[dff['pageviews'].ne(0)] eq_(self.get('{}/{}/'.format(base, 'pageviewstrend')).json(), dff.drop('duration_count', 1).to_dict('r') ) dff = logviewer.pdagg(df[df_user1], [{'key': 'time', 'freq': 'D'}], {'new_session': ['sum']}) dff['time'] = dff['time'].dt.strftime('%Y-%m-%d 00:00:00') dff['sessions'] = dff['new_session_sum'].astype(int) dff = dff[dff['sessions'].ne(0)] eq_(self.get('{}/{}/'.format(base, 'sessionstrend')).json(), dff.drop('new_session_sum', 1).query('sessions != 0').to_dict('r') ) # TODO trend queries for q in spec.kwargs.kwargs.queries.keys(): if q.endswith('trend'): self.check('{}/{}/'.format(base, q))
def test_RenomalizedFixedIncomeResult(): dts = pd.date_range('2010-01-01', periods=5) data = pd.DataFrame(index=dts, columns=['a'], data=1.) data['a'][dts[0]] = 0.99 data['a'][dts[1]] = 1.01 data['a'][dts[2]] = 0.99 data['a'][dts[3]] = 1.01 data['a'][dts[4]] = 0.99 weights = pd.DataFrame(index=dts, columns=['a'], data=1.) weights['a'][dts[0]] = 1. weights['a'][dts[1]] = 2. weights['a'][dts[2]] = 1. weights['a'][dts[3]] = 2. weights['a'][dts[4]] = 1. coupons = pd.DataFrame(index=dts, columns=['a'], data=0.) algos = [ bt.algos.SelectAll(), bt.algos.WeighTarget(weights), bt.algos.SetNotional('notional'), bt.algos.Rebalance() ] children = [bt.CouponPayingSecurity('a')] s = bt.FixedIncomeStrategy('s', algos, children=children) t = bt.Backtest(s, data, initial_capital=0, additional_data={ 'notional': pd.Series(1e6, dts), 'coupons': coupons }, progress_bar=False) res = bt.run(t) t = res.backtests['s'] # Due to the relationship between the time varying notional and the prices, # the strategy has lost money, but price == 100, so "total return" is zero assert t.strategy.value < 0. assert t.strategy.price == 100. assert res.stats['s'].total_return == 0 # Renormalizing results to a constant size "fixes" this norm_res = bt.backtest.RenormalizedFixedIncomeResult( 1e6, *res.backtest_list) aae(norm_res.stats['s'].total_return, t.strategy.value / 1e6, 16) # Check that using the lagged notional value series leads to the same results # as the original calculation. This proves that we can re-derive the price # series from the other data available on the strategy notl_values = t.strategy.notional_values.shift(1) notl_values[ dts[0]] = 1e6 # The notional value *before* any trades are put on norm_res = bt.backtest.RenormalizedFixedIncomeResult( notl_values, *res.backtest_list) assert norm_res.stats['s'].total_return == res.stats['s'].total_return assert norm_res.prices.equals(res.prices)
def test_strategybase_tree_rebalance_level2(): c1 = SecurityBase('c1') c12 = copy.deepcopy(c1) c2 = SecurityBase('c2') c22 = copy.deepcopy(c2) s1 = StrategyBase('s1', [c1, c2]) s2 = StrategyBase('s2', [c12, c22]) m = StrategyBase('m', [s1, s2]) s1 = m['s1'] s2 = m['s2'] c1 = s1['c1'] c2 = s1['c2'] c12 = s2['c1'] c22 = s2['c2'] dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100) data['c1'][dts[1]] = 105 data['c2'][dts[1]] = 95 m.setup(data) i = 0 m.update(dts[i], data.ix[dts[i]]) m.adjust(1000) assert m.value == 1000 assert m.capital == 1000 assert s1.value == 0 assert s2.value == 0 assert c1.value == 0 assert c2.value == 0 # now rebalance child s1 - since its children are 0, no waterfall alloc m.rebalance(0.5, 's1') assert s1.value == 500 assert m.capital == 1000 - 500 assert m.value == 1000 assert s1.weight == 500.0 / 1000 assert s2.weight == 0 # now allocate directly to child of child s1.rebalance(0.4, 'c1') assert s1.value == 500 assert s1.capital == 500 - 200 assert c1.value == 200 assert c1.weight == 200.0 / 500 assert c1.position == 2 assert m.capital == 1000 - 500 assert m.value == 1000 assert s1.weight == 500.0 / 1000 assert s2.weight == 0 assert c12.value == 0 # now rebalance child s1 again and make sure c1 also gets proportional # increase m.rebalance(0.8, 's1') assert s1.value == 800 aae(m.capital, 200, 1) assert m.value == 1000 assert s1.weight == 800 / 1000 assert s2.weight == 0 assert c1.value == 300.0 assert c1.weight == 300.0 / 800 assert c1.position == 3 # now rebalance child s1 to 0 - should close out s1 and c1 as well m.rebalance(0, 's1') assert s1.value == 0 assert m.capital == 1000 assert m.value == 1000 assert s1.weight == 0 assert s2.weight == 0 assert c1.weight == 0
def test_strategybase_prices(): dts = pd.date_range('2010-01-01', periods=21) rawd = [ 13.555, 13.75, 14.16, 13.915, 13.655, 13.765, 14.02, 13.465, 13.32, 14.65, 14.59, 14.175, 13.865, 13.865, 13.89, 13.85, 13.565, 13.47, 13.225, 13.385, 12.89 ] data = pd.DataFrame(index=dts, data=rawd, columns=['a']) s = StrategyBase('s') s.set_commissions(lambda q, p: 1) s.setup(data) # buy 100 shares on day 1 - hold until end # just enough to buy 100 shares + 1$ commission s.adjust(1356.50) s.update(dts[0]) # allocate all capital to child a # a should be dynamically created and should have # 100 shares allocated. s.capital should be 0 s.allocate(s.value, 'a') assert s.capital == 0 assert s.value == 1355.50 assert len(s.children) == 1 aae(s.price, 99.92628, 5) a = s['a'] assert a.position == 100 assert a.value == 1355.50 assert a.weight == 1 assert a.price == 13.555 assert len(a.prices) == 1 # update through all dates and make sure price is ok s.update(dts[1]) aae(s.price, 101.3638, 4) s.update(dts[2]) aae(s.price, 104.3863, 4) s.update(dts[3]) aae(s.price, 102.5802, 4) # finish updates and make sure ok at end for i in range(4, 21): s.update(dts[i]) assert len(s.prices) == 21 aae(s.prices[-1], 95.02396, 5) aae(s.prices[-2], 98.67306, 5)