def test_invalid_object_missing_properties(self): portfolio_dict = { "creation_date": "2020-04-14T12:20:50.219487+00:00", "price_date": "2020-03-31T04:00:00+00:00", "current_portfolio": [{ "ticker_symbol": "AAPL", "quantity": 1000, "purchase_date": "2020-03-31T04:00:00+00:00", "purchase_price": 123.45, "current_price": 234.56, "current_returns": 0.9, "trade_state": "FILLED", "order_id": None }], "securities_set": [{ "ticker_symbol": "AAPL", "analysis_price": 100, "current_price": 102, "current_returns": 0.02 }] } with self.assertRaises(ValidationError): Portfolio.from_dict(portfolio_dict)
def test_valid_object_no_portfolio(self): portfolio_dict = { "portfolio_id": "xxx", "set_id": "yyy", "creation_date": "2020-04-14T12:20:50.219487+00:00", "price_date": "2020-03-31T04:00:00+00:00", "current_portfolio": { "securities": [{ "ticker_symbol": "AAPL", "quantity": 1000, "purchase_date": "2020-03-31T04:00:00+00:00", "purchase_price": 123.45, "current_price": 234.56, "current_returns": 0.9, "trade_state": "FILLED", "order_id": None }] }, "securities_set": [{ "ticker_symbol": "AAPL", "analysis_price": 100, "current_price": 102, "current_returns": 0.02 }] } Portfolio.from_dict(portfolio_dict)
def test_trade_buy_single_security(self): buy_positions = [('BA', 1.0)] portfolio = deepcopy(self.base_portfolio) del portfolio['current_portfolio']['securities'][2] del portfolio['current_portfolio']['securities'][1] portfolio = Portfolio.from_dict(portfolio) with patch.object(td_ameritrade, 'place_order', return_value='order-xxx'), \ patch.object(td_ameritrade, 'list_recent_orders', return_value={ "order-xxx": { "status": "FILLED", "symbol": "BA", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" }, }): broker = Broker() self.assertTrue(broker.trade('BUY', buy_positions, portfolio)) pos = portfolio.get_position('BA') self.assertEqual(pos['trade_state'], 'FILLED') self.assertEqual(pos['quantity'], 1) self.assertIsNotNone(pos['purchase_date'])
def test_get_position(self): portfolio_dict = { "portfolio_id": "xxx", "set_id": "yyy", "creation_date": "2020-04-14T12:20:50.219487+00:00", "price_date": "2020-03-31T04:00:00+00:00", "current_portfolio": { "securities": [{ "ticker_symbol": "INTC", "quantity": 100, "purchase_date": None, "purchase_price": 100, "current_price": 100, "current_returns": 0, "trade_state": "UNFILLED", "order_id": None }] }, "securities_set": [{ "ticker_symbol": "AAPL", "analysis_price": 100, "current_price": 100, "current_returns": 0 }] } portfolio = Portfolio.from_dict(portfolio_dict) self.assertIsNotNone(portfolio.get_position("INTC")) self.assertIsNone(portfolio.get_position("XXX"))
def test_synchronize_portfolio_all_extra_portfolio_positions(self): portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() broker.synchronize_portfolio(self.base_positions, portfolio) portfolio.model['current_portfolio']['securities'].append({ "ticker_symbol": "XXX", "quantity": 1, "purchase_date": None, "purchase_price": 1.0, "current_price": 1.0, "current_returns": 0.0, "trade_state": "UNFILLED", "order_id": None }) self.assertEqual( portfolio.get_position('XXX')['trade_state'], 'UNFILLED')
def test_trade_buy_multiple_securities_with_exception(self): buy_positions = [('BA', 1.0), ('GE', 1.0), ('XOM', 1.0)] # portfolio has 3 positions portfolio = deepcopy(self.base_portfolio) portfolio = Portfolio.from_dict(portfolio) with patch.object(td_ameritrade, 'place_order', side_effect=[ 'order-1', 'order-2', TradeError("Some Error", None, None)]), \ patch.object(td_ameritrade, 'list_recent_orders', return_value={ "order-1": { "status": "FILLED", "symbol": "BA", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" }, "order-2": { "status": "FILLED", "symbol": "GE", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" } }): broker = Broker() self.assertFalse(broker.trade('BUY', buy_positions, portfolio))
def test_generate_test_instructions_nothing_to_do(self): portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() (sell_list, buy_list) = broker._generate_trade_instructions( self.base_positions, portfolio) self.assertListEqual(sell_list, []) self.assertListEqual(buy_list, [])
def test_generate_test_instructions_no_positions(self): portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() (sell_list, buy_list) = broker._generate_trade_instructions({}, portfolio) self.assertListEqual(sell_list, []) self.assertListEqual(buy_list, ['BA', 'GE', 'XOM'])
def test_reprice_unfilled_order(self): portfolio_dict = { "portfolio_id": "xxx", "set_id": "yyy", "creation_date": "2020-04-14T12:20:50.219487+00:00", "price_date": "2020-03-31T04:00:00+00:00", "current_portfolio": { "securities": [{ "ticker_symbol": "INTC", "quantity": 100, "purchase_date": "2020-03-31T04:00:00+00:00", "purchase_price": 0, "current_price": 0, "current_returns": 0, "trade_state": "UNFILLED", "order_id": None }] }, "securities_set": [{ "ticker_symbol": "AAPL", "analysis_price": 0, "current_price": 0, "current_returns": 0 }] } portfolio = Portfolio.from_dict(portfolio_dict) with patch.object(intrinio_data, 'get_latest_close_price', return_value=('2020-04-30', 101)): now = datetime.now() portfolio.reprice(now) self.assertEqual( portfolio.model["current_portfolio"]["securities"][0] ["current_price"], 101) self.assertEqual( round( portfolio.model["current_portfolio"]["securities"][0] ["current_returns"], 2), 0) self.assertEqual( portfolio.model["securities_set"][0]["current_price"], 101) self.assertEqual( round(portfolio.model["securities_set"][0]["current_returns"], 2), 0) self.assertEqual( portfolio.model["price_date"], util.date_to_iso_utc_string(parser.parse('2020-04-30')))
def test_reconcile_portfolio_mismatching_quantity(self): pfolio = deepcopy(self.base_portfolio) pfolio['current_portfolio']['securities'][0]['quantity'] = 999 portfolio = Portfolio.from_dict(pfolio) broker = Broker() self.assertFalse( broker.reconcile_portfolio(self.base_positions, portfolio))
def test_reconcile_portfolio_mismatching_ticker(self): pfolio = deepcopy(self.base_portfolio) pos = deepcopy(self.base_positions) pfolio['current_portfolio']['securities'][0]['ticker_symbol'] = 'XXX' with patch.object(td_ameritrade, 'login', return_value=None): portfolio = Portfolio.from_dict(pfolio) broker = Broker() self.assertFalse(broker.reconcile_portfolio(pos, portfolio))
def test_synchronize_portfolio_all_positions_filled(self): portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() broker.synchronize_portfolio(self.base_positions, portfolio) for sec in portfolio.model['current_portfolio']['securities']: self.assertEqual(sec['trade_state'], 'FILLED') self.assertEqual( sec['purchase_price'], self.base_positions['equities'][ sec['ticker_symbol']]['averagePrice'])
def test_reconcile_portfolio_fewer_positions(self): pfolio = deepcopy(self.base_portfolio) pos = deepcopy(self.base_positions) del pfolio['current_portfolio']['securities'][0] with patch.object(td_ameritrade, 'login', return_value=None): portfolio = Portfolio.from_dict(pfolio) broker = Broker() self.assertFalse(broker.reconcile_portfolio(pos, portfolio))
def test_reconcile_portfolio_matching(self): portfolio = deepcopy(self.base_portfolio) # this is the bare minimum required to reconcile the portfolio for sec in portfolio['current_portfolio']['securities']: sec['quantity'] = 1 sec['trade_state'] = 'FILLED' portfolio = Portfolio.from_dict(portfolio) broker = Broker() self.assertTrue( broker.reconcile_portfolio(self.base_positions, portfolio))
def test_trade_buy_failed_trades(self): buy_positions = [('BA', 1.0), ('GE', 1.0), ('XOM', 1.0)] # portfolio has 3 positions portfolio = deepcopy(self.base_portfolio) portfolio = Portfolio.from_dict(portfolio) with patch.object(td_ameritrade, 'place_order', side_effect=[ 'order-1', 'order-2', 'order-3']), \ patch.object(td_ameritrade, 'list_recent_orders', return_value={ "order-1": { "status": "FILLED", "symbol": "BA", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" }, "order-2": { "status": "FILLED", "symbol": "GE", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" }, "order-3": { "status": "UNKNOWN", "symbol": "XOM", "quantity": 1, "closeTime": "2020-05-04T03:21:04+0000", "tag": "AA_myuser" }, }): broker = Broker() self.assertTrue(broker.trade('BUY', buy_positions, portfolio)) pos = portfolio.get_position('BA') self.assertEqual(pos['trade_state'], 'FILLED') self.assertEqual(pos['quantity'], 1) self.assertIsNotNone(pos['purchase_date']) pos = portfolio.get_position('GE') self.assertEqual(pos['trade_state'], 'FILLED') self.assertEqual(pos['quantity'], 1) self.assertIsNotNone(pos['purchase_date']) pos = portfolio.get_position('XOM') self.assertEqual(pos['trade_state'], 'UNFILLED') self.assertEqual(pos['quantity'], 0) self.assertIsNone(pos['purchase_date'])
def test_synchronize_portfolio_no_boker_positions_filled(self): portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() broker.synchronize_portfolio( { 'equities': {}, 'cash': { 'cashAvailableForTrading': 100 } }, portfolio) for sec in portfolio.model['current_portfolio']['securities']: self.assertEqual(sec['trade_state'], 'UNFILLED')
def test_generate_test_instructions_with_sells(self): portfolio = deepcopy(self.base_portfolio) del portfolio['current_portfolio']['securities'][2] del portfolio['current_portfolio']['securities'][1] portfolio = Portfolio.from_dict(portfolio) broker = Broker() (sell_list, buy_list) = broker._generate_trade_instructions( self.base_positions, portfolio) self.assertListEqual(sell_list, [('GE', 1), ('XOM', 1)]) self.assertListEqual(buy_list, [])
def test_generate_test_instructions_with_buys(self): positions = deepcopy(self.base_positions) del positions['equities']['GE'] del positions['equities']['XOM'] portfolio = Portfolio.from_dict(self.base_portfolio) broker = Broker() (sell_list, buy_list) = broker._generate_trade_instructions(positions, portfolio) self.assertListEqual(sell_list, []) self.assertListEqual(buy_list, ['GE', 'XOM'])
def test_synchronize_portfolio_all_extra_broker_positions(self): portfolio = Portfolio.from_dict(self.base_portfolio) positions = deepcopy(self.base_positions) broker = Broker() broker.synchronize_portfolio(positions, portfolio) positions['equities']['XXX'] = { 'longQuantity': 1.0, 'averagePrice': 10.0, 'marketValue': 10.0 } for sec in portfolio.model['current_portfolio']['securities']: self.assertEqual(sec['trade_state'], 'FILLED') self.assertEqual( sec['purchase_price'], positions['equities'][sec['ticker_symbol']]['averagePrice'])
def test_update_portfolio_new_recommendation(self): sr_mod = deepcopy(self.sr_dict) sr_mod['set_id'] = 'different_set' security_recommendation = SecurityRecommendationSet.from_dict(sr_mod) portfolio = Portfolio.from_dict(self.portfolio_dict) (new_p, updated) = portfolio_mgr_svc.update_portfolio( portfolio, security_recommendation, 1) ''' ensure that 1) portfolio is updated 2) set id are being set properly ''' self.assertTrue(updated) self.assertEqual(new_p.model['set_id'], security_recommendation.model['set_id']) self.assertNotEqual(new_p.model['set_id'], self.sr_dict['set_id'])