def test_set_notional(): algo = algos.SetNotional( 1000. ) s = bt.FixedIncomeStrategy('s') dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100) s.setup(data) algo(s) assert s.temp['notional_value'] == 1000
def test_rebalance_fixedincome(): algo = algos.Rebalance() c1 = bt.Security('c1') c2 = bt.CouponPayingSecurity('c2') s = bt.FixedIncomeStrategy('s', children = [c1, c2]) dts = pd.date_range('2010-01-01', periods=3) data = pd.DataFrame(index=dts, columns=['c1', 'c2'], data=100) coupons = pd.DataFrame(index=dts, columns=['c2'], data=0) s.setup(data, coupons=coupons) s.update(dts[0]) s.temp['notional_value'] = 1000 s.temp['weights'] = {'c1': 1} assert algo(s) assert s.value == 0. assert s.notional_value == 1000 assert s.capital == -1000 c1 = s['c1'] assert c1.value == 1000 assert c1.notional_value == 1000 assert c1.position == 10 assert c1.weight == 1. s.temp['weights'] = {'c2': 1} assert algo(s) assert s.value == 0. assert s.notional_value == 1000 assert s.capital == -1000*100 c2 = s['c2'] assert c1.value == 0 assert c1.notional_value == 0 assert c1.position == 0 assert c1.weight == 0 assert c2.value == 1000*100 assert c2.notional_value == 1000 assert c2.position == 1000 assert c2.weight == 1.
def benchmark_2(): x = np.random.randn(10000, 1000) * 0.01 idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0]) data = np.exp(pd.DataFrame(x, index=idx).cumsum()) bidoffer = data * 0.01 coupons = data * 0. s = bt.FixedIncomeStrategy( 's', algos=[ bt.algos.RunMonthly(), bt.algos.SelectRandomly(len(data.columns) / 2), bt.algos.WeighRandomly(), bt.algos.Rebalance() ], children=[bt.CouponPayingSecurity(c) for c in data]) t = bt.Backtest(s, data, additional_data={ 'bidoffer': bidoffer, 'coupons': coupons }) return bt.run(t)
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_Results_helper_functions_fi(): names = ['foo', 'bar'] dates = pd.date_range(start='2017-01-01', end='2017-12-31', freq=pd.tseries.offsets.BDay()) n = len(dates) rdf = pd.DataFrame(np.zeros((n, len(names))), index=dates, columns=names) np.random.seed(1) rdf[names[0]] = np.random.normal(loc=0.1 / n, scale=0.2 / np.sqrt(n), size=n) rdf[names[1]] = np.random.normal(loc=0.04 / n, scale=0.05 / np.sqrt(n), size=n) pdf = 100 * np.cumprod(1 + rdf) notional = pd.Series(1e6, index=pdf.index) # algo to fire on the beginning of every month and to run on the first date runDailyAlgo = bt.algos.RunDaily(run_on_first_date=True) # algo to select all securities selectAll = bt.algos.SelectAll() # algo to set the weights # it will only run when runMonthlyAlgo returns true # which only happens on the first of every month weighRandomly = bt.algos.WeighRandomly() # algo to set the notional of the fixed income strategy setNotional = bt.algos.SetNotional('notional') # algo to rebalance the current weights to weights set by weighSpecified # will only run when weighSpecifiedAlgo returns true # which happens every time it runs rebalAlgo = bt.algos.Rebalance() # a strategy that rebalances monthly to specified weights strat = bt.FixedIncomeStrategy( 'random', [runDailyAlgo, selectAll, weighRandomly, setNotional, rebalAlgo]) backtest = bt.Backtest(strat, pdf, initial_capital=0, integer_positions=False, progress_bar=False, additional_data={ 'mydata': pdf, 'notional': notional }) bidoffer = 1. backtest2 = bt.Backtest(strat, pdf, initial_capital=0, integer_positions=False, progress_bar=False, additional_data={ 'mydata': pdf, 'notional': notional, 'bidoffer': pd.DataFrame(bidoffer, pdf.index, pdf.columns) }) random.seed(1234) res = bt.run(backtest) random.seed(1234) res2 = bt.run(backtest2) assert (type(res.get_security_weights()) is pd.DataFrame) assert (type(res.get_transactions()) is pd.DataFrame) assert len(res.get_transactions()) > 0 assert (type(res.get_weights()) is pd.DataFrame) # Make sure the insertion of the first row applies to additional data as well assert backtest.data.index.equals(backtest.additional_data['mydata'].index) # Check that bid/offer is accounted for transactions = res.get_transactions() transactions['price'] = transactions['price'] + 0.5 * bidoffer assert (res2.get_transactions().price - res2.get_transactions().price).abs().sum() == 0