def test__produce_trades_list(self): acc = Account(buffer_len=5) acc._transactions = self.transactions df_trades = Report._produce_trades_list(acc) self.assertEqual(2, len(df_trades)) self.assertEqual(True, isinstance(df_trades, pd.DataFrame))
def test_builtins(self): acc = Account(buffer_len=6, name='test') acc2 = Account(buffer_len=6, name='test') acc3 = Account(buffer_len=6, name='test3') self.assertEqual(str(acc), 'test') self.assertEqual(hash(acc), hash('test')) self.assertEqual(True, acc == acc2) self.assertEqual(True, acc != acc3) self.assertEqual(True, acc == 'test') self.assertEqual(False, acc == None)
def test_public_properties(self): acc = Account(buffer_len=6, name='test') acc._equity_close = 100 acc._capital_invested = 200 acc._margin = 25 self.assertEqual(100, acc.capital_equity) self.assertEqual(200, acc.capital_invested) self.assertEqual(25, acc.margin) self.assertEqual(75, acc.capital_available) self.assertEqual('test', acc.name)
def test_calc_account_nan_case(self): acc = Account(buffer_len=6, kw=True) asset1 = mock.MagicMock(Asset) asset2 = mock.MagicMock(Asset) asset1.get_margin_requirements.return_value = np.nan asset2.get_margin_requirements.return_value = 200 acc._position = { asset1: (1, 2, 3, None), asset2: (2, 2, 3, None) } self.assertRaises(ValueError, acc._calc_account_margin, pd.Timestamp('2018-01-02'))
def test_process_position(self): with mock.patch('yauber_backtester._account.Account._calc_transactions') as mock_calc_trans: with mock.patch('yauber_backtester._account.Account._calc_account_margin') as mock_acc_margin: mock_calc_trans.return_value = ( ['trans1', 'trans2'], 100, 200, -0.5, -1.0, -3, -4, ) mock_acc_margin.return_value = 999 acc = Account(buffer_len=6, kw=True) acc.capital_transaction(pd.Timestamp('2018-01-02'), 1000) pos1 = {self.asset1: 1} acc._process_position(pd.Timestamp('2018-01-02'), pos1) self.assertEqual(False, acc._has_synthetic_assets) self.assertEqual(acc._position, {self.asset1: (1, 2, 3, None)}) self.assertEqual(True, mock_calc_trans.called) self.assertEqual((pd.Timestamp('2018-01-02'), {self.asset1: (1, 2, 3, None)}, {}), mock_calc_trans.call_args[0]) self.assertEqual(['trans1', 'trans2'], acc._transactions) self.assertEqual(1100, acc._equity_close) self.assertEqual(1200, acc._equity_exec) self.assertEqual((pd.Timestamp('2018-01-02'), ), mock_acc_margin.call_args[0]) self.assertEqual(999, acc._margin) self.assertEqual(1, acc._buf_cnt) self.assertEqual(pd.Timestamp('2018-01-02'), acc._date_array[acc._buf_cnt - 1]) self.assertEqual(100, acc._pnl_array_close[acc._buf_cnt - 1]) self.assertEqual(200, acc._pnl_array_exec[acc._buf_cnt - 1]) self.assertEqual(1100, acc._equity_array_close[acc._buf_cnt - 1]) self.assertEqual(1200, acc._equity_array_exec[acc._buf_cnt - 1]) self.assertEqual(1000, acc._capital_invested_array[acc._buf_cnt - 1]) self.assertEqual(-0.5, acc._costs_array_close[acc._buf_cnt - 1]) self.assertEqual(-1.0, acc._costs_array_exec[acc._buf_cnt - 1]) self.assertEqual(-3, acc._costs_array_potential_close[acc._buf_cnt - 1]) self.assertEqual(-4, acc._costs_array_potential_exec[acc._buf_cnt - 1]) self.assertEqual(999, acc._margin_array[acc._buf_cnt - 1]) # Synthetic asset flag setting pos1 = {self.asset2: 1} acc._process_position(pd.Timestamp('2018-01-02'), pos1) self.assertEqual(True, acc._has_synthetic_assets) # Check buffer overflow acc._buf_cnt = 10 # ValueError: Incorrectly initialized account values buffer length or _process_position() called more times than expected self.assertRaises(ValueError, acc._process_position, pd.Timestamp('2018-01-02'), pos1)
def test_process_position_errors_checks(self): with mock.patch('yauber_backtester._account.Account._calc_transactions') as mock_calc_trans: with mock.patch('yauber_backtester._account.Account._calc_account_margin') as mock_acc_margin: mock_calc_trans.return_value = ( ['trans1', 'trans2'], 100, 200, -0.5, -1.0, -3, -4, ) mock_acc_margin.return_value = 999 acc = Account(buffer_len=6, kw=True) acc.capital_transaction(pd.Timestamp('2018-01-02'), 1000) self.assertRaises(ValueError, acc._process_position, pd.Timestamp('2018-01-02'), []) self.assertRaises(ValueError, acc._process_position, pd.Timestamp('2018-01-02'), {self.asset1: 'se'}) self.assertRaises(ValueError, acc._process_position, pd.Timestamp('2018-01-02'), {'nope': 1})
def test_calc_account_margin(self): acc = Account(buffer_len=6, kw=True) asset1 = mock.MagicMock(Asset) asset2 = mock.MagicMock(Asset) asset1.get_margin_requirements.return_value = 100 asset2.get_margin_requirements.return_value = 200 acc._position = { asset1: (1, 2, 3, None), asset2: (2, 2, 3, None) } margin = acc._calc_account_margin(pd.Timestamp('2018-01-02')) self.assertEqual(margin, 300) self.assertEqual((pd.Timestamp('2018-01-02'), 1), asset1.get_margin_requirements.call_args[0]) self.assertEqual((pd.Timestamp('2018-01-02'), 2), asset2.get_margin_requirements.call_args[0])
def test_as_dataframe(self): with mock.patch('yauber_backtester._account.Account._calc_transactions') as mock_calc_trans: with mock.patch('yauber_backtester._account.Account._calc_account_margin') as mock_acc_margin: mock_calc_trans.return_value = ( ['trans1', 'trans2'], 100, 200, -0.5, -1.0, -3, -4, ) mock_acc_margin.return_value = 999 acc = Account(buffer_len=6, name='acc') acc.capital_transaction(None, 1000) pos_dict = {self.asset1: 1} acc._process_position(pd.Timestamp('2018-01-02'), pos_dict) df = acc.as_dataframe() self.assertEqual(1, len(df)) self.assertEqual(5, len(df.columns)) self.assertEqual(1200, df['equity'][0]) self.assertEqual(1000, df['capital_invested'][0]) self.assertEqual(-1.0, df['costs'][0]) self.assertEqual(999, df['margin'][0]) self.assertEqual(200, df['pnl'][0]) self.assertEqual(pd.Timestamp('2018-01-02'), df.index[0])
def test_as_transactions(self): acc = Account(buffer_len=6, name='test') acc._transactions = [ # 'date', 'asset', 'position_action', 'qty', 'price_close', 'price_exec', # 'costs_close', 'costs_exec', 'pnl_close', 'pnl_execution', ( pd.Timestamp('2018-01-01'), self.asset1, 1, 1, 100, 101, -0.5, -0.6, 3, 4, ), ( pd.Timestamp('2018-01-02'), self.asset2, 1, -1, 100, 101, -0.5, -0.6, 3, 4, ), ] df = acc.as_transactions() self.assertEqual(True, isinstance(df, pd.DataFrame)) self.assertEqual(True, df.index.is_monotonic_increasing) self.assertEqual(2, len(df)) self.assertEqual([ 'asset', 'position_action', 'qty', 'price_close', 'price_exec', 'costs_close', 'costs_exec', 'pnl_close', 'pnl_execution', ], list(df.columns), ) self.assertEqual(df.index.name, 'date')
def test__calc_transations_change_existing_multiple(self): new_pos = {self.asset1: (3, 2, 3, None), self.asset2: (1, 2, 3, None)} old_pos = {self.asset1: (2, 1, 1, None)} # Old was opened at '2018-01-01' ( transactions, pnl_close_total, pnl_execution_total, costs_close_total, costs_exec_total, costs_potential_close_total, costs_potential_exec_total, ) = Account._calc_transactions(pd.Timestamp('2018-01-02'), new_pos, old_pos) self.assertEqual(2, len(transactions)) for t in transactions: ( t_dt, t_asset, t_position_action, t_trans_qty, t_close_price, t_exec_price, t_costs_close, t_costs_exec, t_pnl_close, t_pnl_exec, t_ctx, ) = t if t_asset == self.asset1: self.assertEqual(pd.Timestamp('2018-01-02'), t_dt) self.assertEqual(self.asset1, t_asset) self.assertEqual(1, t_position_action) self.assertEqual(1, t_trans_qty) self.assertEqual(2, t_close_price) self.assertEqual(3, t_exec_price) self.assertEqual(-2 * 0.5 * 1, t_costs_close) self.assertEqual(-3 * 0.5 * 1, t_costs_exec) elif t_asset == self.asset2: self.assertEqual(pd.Timestamp('2018-01-02'), t_dt) self.assertEqual(self.asset2, t_asset) self.assertEqual(1, t_position_action) self.assertEqual(1, t_trans_qty) self.assertEqual(2, t_close_price) self.assertEqual(3, t_exec_price) self.assertEqual(-2 * 0.5 * 1, t_costs_close) self.assertEqual(-3 * 0.5 * 1, t_costs_exec) self.assertEqual(pnl_close_total, 2 + (-2 * 0.5 * 1) + (-2 * 0.5 * 1) ) self.assertEqual(pnl_execution_total, 4 + (-3 * 0.5 * 1) + (-3 * 0.5 * 1)) self.assertEqual(costs_close_total, (-2 * 0.5 * 1) + (-2 * 0.5 * 1)) self.assertEqual(costs_exec_total, (-3 * 0.5 * 1) + (-3 * 0.5 * 1)) self.assertEqual(costs_potential_close_total, -2 * 0.5 * 4) self.assertEqual(costs_potential_exec_total, -3 * 0.5 * 4)
def test_position(self): acc = Account(buffer_len=6, kw=True) asset1 = mock.MagicMock(Asset) asset2 = mock.MagicMock(Asset) acc._position = { asset1: (1, 2, 3, None), asset2: (2, 2, 3, None) } p = acc.position() self.assertEqual(True, isinstance(p, dict)) self.assertEqual(True, asset1 in p) self.assertEqual(True, asset2 in p) self.assertTrue(isinstance(p[asset1], PositionInfo)) self.assertTrue(isinstance(p[asset2], PositionInfo)) self.assertEqual(asset1, p[asset1].asset) self.assertEqual(asset2, p[asset2].asset) self.assertEqual(1, p[asset1].qty) self.assertEqual(2, p[asset2].qty)
def test_init_test(self): acc = Account(buffer_len=6, kw=True) self.assertEqual({}, acc._position) self.assertEqual(0, acc._equity_close) self.assertEqual(0, acc._equity_exec) self.assertEqual(0, acc._capital_invested) self.assertEqual(0, acc._margin) self.assertEqual('GenericAccount', acc.name) self.assertEqual([], acc._transactions) self.assertEqual({'kw': True}, acc.kwargs) self.assertEqual(False, acc._has_synthetic_assets) self.assertEqual(0, acc._buf_cnt) self.assertEqual(6, acc._buffer_len) self.assertEqual(np.float, acc._pnl_array_close.dtype) self.assertEqual(acc._buffer_len, len(acc._pnl_array_close)) self.assertEqual(np.float, acc._pnl_array_exec.dtype) self.assertEqual(acc._buffer_len, len(acc._pnl_array_exec)) self.assertEqual(np.float, acc._costs_array_close.dtype) self.assertEqual(acc._buffer_len, len(acc._costs_array_close)) self.assertEqual(np.float, acc._costs_array_exec.dtype) self.assertEqual(acc._buffer_len, len(acc._costs_array_exec)) self.assertEqual(np.float, acc._costs_array_potential_close.dtype) self.assertEqual(acc._buffer_len, len(acc._costs_array_potential_close)) self.assertEqual(np.float, acc._equity_array_close.dtype) self.assertEqual(acc._buffer_len, len(acc._equity_array_close)) self.assertEqual(np.float, acc._equity_array_exec.dtype) self.assertEqual(acc._buffer_len, len(acc._equity_array_exec)) self.assertEqual(np.float, acc._capital_invested_array.dtype) self.assertEqual(acc._buffer_len, len(acc._capital_invested_array)) self.assertEqual(np.float, acc._margin_array.dtype) self.assertEqual(acc._buffer_len, len(acc._margin_array)) self.assertEqual(np.dtype('M8[us]'), acc._date_array.dtype) self.assertEqual(acc._buffer_len, len(acc._date_array))
def test__calc_transations_change_existing_both_zeros(self): new_pos = {self.asset1: (0, 2, 3, None)} old_pos = {self.asset1: (0, 1, 1, None)} # Old was opened at '2018-01-01' ( transactions, pnl_close_total, pnl_execution_total, costs_close_total, costs_exec_total, costs_potential_close_total, costs_potential_exec_total, ) = Account._calc_transactions(pd.Timestamp('2018-01-02'), new_pos, old_pos) self.assertEqual(0, len(transactions)) self.assertEqual(pnl_close_total, 0) self.assertEqual(pnl_execution_total, 0) self.assertEqual(costs_close_total, 0) self.assertEqual(costs_exec_total, 0) self.assertEqual(costs_potential_close_total, 0) self.assertEqual(costs_potential_exec_total, 0)
def test__calc_transations_change_existing_decrease(self): new_pos = {self.asset1: (1, 2, 3, None)} old_pos = {self.asset1: (2, 1, 1, None)} # Old was opened at '2018-01-01' ( transactions, pnl_close_total, pnl_execution_total, costs_close_total, costs_exec_total, costs_potential_close_total, costs_potential_exec_total, ) = Account._calc_transactions(pd.Timestamp('2018-01-02'), new_pos, old_pos) self.assertEqual(1, len(transactions)) ( t_dt, t_asset, t_position_action, t_trans_qty, t_close_price, t_exec_price, t_costs_close, t_costs_exec, t_pnl_close, t_pnl_exec, t_ctx, ) = transactions[0] self.assertEqual(pd.Timestamp('2018-01-02'), t_dt) self.assertEqual(self.asset1, t_asset) self.assertEqual(-1, t_position_action) self.assertEqual(-1, t_trans_qty) self.assertEqual(2, t_close_price) self.assertEqual(3, t_exec_price) self.assertEqual(-2 * 0.5 * 1, t_costs_close) self.assertEqual(-3 * 0.5 * 1, t_costs_exec) self.assertEqual(None, t_ctx) self.assertEqual(pnl_close_total, 2 + t_costs_close) self.assertEqual(pnl_execution_total, 4 + t_costs_exec) self.assertEqual(costs_close_total, t_costs_close) self.assertEqual(costs_exec_total, t_costs_exec) self.assertEqual(costs_potential_close_total, -2 * 0.5 * 1) self.assertEqual(costs_potential_exec_total, -3 * 0.5 * 1)
def test__calc_transations_new(self): new_pos = {self.asset1: (2, 2, 3, None)} old_pos = None ( transactions, pnl_close_total, pnl_execution_total, costs_close_total, costs_exec_total, costs_potential_close_total, costs_potential_exec_total, ) = Account._calc_transactions(pd.Timestamp('2018-01-02'), new_pos, old_pos) self.assertEqual(1, len(transactions)) ( t_dt, t_asset, t_position_action, t_curr_qty, t_close_price, t_exec_price, t_costs_close, t_costs_exec, t_pnl_close, t_pnl_exec, t_ctx, ) = transactions[0] self.assertEqual(pd.Timestamp('2018-01-02'), t_dt) self.assertEqual(self.asset1, t_asset) self.assertEqual(1, t_position_action) self.assertEqual(2, t_curr_qty) self.assertEqual(2, t_close_price) self.assertEqual(3, t_exec_price) self.assertEqual(-2 * 0.5 * 2, t_costs_close) self.assertEqual(-3 * 0.5 * 2, t_costs_exec) self.assertEqual(pnl_close_total, 0 + t_costs_close) self.assertEqual(pnl_execution_total, 0 + t_costs_exec) self.assertEqual(costs_close_total, t_costs_close) self.assertEqual(costs_exec_total, t_costs_exec) self.assertEqual(costs_potential_close_total, t_costs_close) self.assertEqual(costs_potential_exec_total, t_costs_exec)
def test_capital_transaction(self): acc = Account(buffer_len=6, kw=True) self.assertEqual(0, acc._equity_close) self.assertEqual(0, acc._equity_exec) self.assertEqual(0, acc._capital_invested) acc.capital_transaction(None, 1000) self.assertEqual(1000, acc._equity_close) self.assertEqual(1000, acc._equity_exec) self.assertEqual(1000, acc._capital_invested) acc.capital_transaction(None, -1000) self.assertEqual(0, acc._equity_close) self.assertEqual(0, acc._equity_exec) self.assertEqual(0, acc._capital_invested)
def test_process_position_with_context(self): with mock.patch('yauber_backtester._account.Account._calc_transactions') as mock_calc_trans: with mock.patch('yauber_backtester._account.Account._calc_account_margin') as mock_acc_margin: mock_calc_trans.return_value = ( ['trans1', 'trans2'], 100, 200, -0.5, -1.0, -3, -4, ) mock_acc_margin.return_value = 999 acc = Account(buffer_len=6, kw=True) acc.capital_transaction(pd.Timestamp('2018-01-02'), 1000) pos1 = {self.asset1: (1, ('ctx',))} acc._process_position(pd.Timestamp('2018-01-02'), pos1) self.assertEqual(False, acc._has_synthetic_assets) self.assertEqual(acc._position, {self.asset1: (1, 2, 3, ('ctx',))})
def test_as_asset(self): with mock.patch('yauber_backtester._account.Account._calc_transactions') as mock_calc_trans: with mock.patch('yauber_backtester._account.Account._calc_account_margin') as mock_acc_margin: mock_calc_trans.return_value = ( ['trans1', 'trans2'], 100, 200, -0.5, -1.0, -3, -4, ) mock_acc_margin.return_value = 999 acc = Account(buffer_len=6, name='acc') acc.capital_transaction(None, 1000) pos_dict = {self.asset1: 1} acc._process_position(pd.Timestamp('2018-01-02'), pos_dict) # Use default acc name synt_asset = acc.as_asset() self.assertEqual('acc', synt_asset.ticker) synt_asset = acc.as_asset("synt1") quotes = synt_asset.quotes() self.assertEqual('synt1', synt_asset.ticker) self.assertEqual(1, len(quotes)) self.assertEqual(1100, quotes['o'][0]) self.assertEqual(1100, quotes['h'][0]) self.assertEqual(1100, quotes['l'][0]) self.assertEqual(1100, quotes['c'][0]) self.assertEqual(0, quotes['v'][0]) self.assertEqual(1200, quotes['exec'][0]) self.assertEqual(True, synt_asset.is_synthetic) self.assertEqual(1.0, synt_asset.get_point_value(pd.Timestamp('2018-01-02'))) self.assertEqual(1, len(synt_asset.kwargs['margin'])) self.assertEqual(999, synt_asset.kwargs['margin'][0]) self.assertEqual(999, synt_asset.get_margin_requirements(pd.Timestamp('2018-01-02'), 1)) self.assertEqual({'A': 1}, synt_asset.legs) self.assertEqual('dynamic', synt_asset.kwargs['costs']['type']) self.assertEqual(1, len(synt_asset.kwargs['costs']['value'])) self.assertEqual(-3, synt_asset.kwargs['costs']['value']['c'][0]) self.assertEqual(-4, synt_asset.kwargs['costs']['value']['exec'][0]) # # Disallow creating synth asset from accounts holding another synth asset # acc = Account(buffer_len=6) pos_dict = {self.asset2: 1} acc._process_position(pd.Timestamp('2018-01-02'), pos_dict) # ValueError: It's not permitted to create multiple layers of synthetic assets. This account already contains one or more synthetic assets. self.assertRaises(ValueError, acc.as_asset, "synt1")