def reprice(self, price_date: datetime): ''' Reads the current prices, computes the latest returns and updates the portfolio object. ''' # Update the current returns in the securities set for security in self.model['securities_set']: analysis_price = security['analysis_price'] (price_date_str, latest_price) = intrinio_data.get_latest_close_price( security['ticker_symbol'], price_date, 5) security['current_price'] = latest_price # if a portfolio exsts, reprice it too if not self.is_empty(): for security in self.model['current_portfolio']['securities']: purchase_price = security['purchase_price'] (price_date_str, latest_price) = intrinio_data.get_latest_close_price( security['ticker_symbol'], price_date, 5) security['current_price'] = latest_price self.recalc_returns() # finally set the price date try: price_date = parser.parse(price_date_str) except Exception as e: raise ValidationError( "Could parse price date returned by Intrinio API", e) self.model['price_date'] = util.date_to_iso_utc_string(price_date) log.info("Repriced portfolio for date of %s" % str(price_date))
def create_empty_portfolio(self, recommendation_set: object): ''' Creates a new and empty portfolio object based on a recommendation set. Once created, the portfolio will be ready to trade ''' securities = recommendation_set.to_dict()['securities_set'] securities_list = [] for security in securities: ticker = security['ticker_symbol'] analysis_price = security['price'] (price_date_str, latest_price) = intrinio_data.get_latest_close_price( ticker, datetime.now(), 5) securities_list.append({ "ticker_symbol": ticker, "analysis_price": analysis_price, "current_price": latest_price, "current_returns": ((latest_price / analysis_price) - 1), }) try: price_date = parser.parse(price_date_str) except Exception as e: raise ValidationError( "Could parse price date returned by Intrinio API", e) securities_set = {"securities_set": securities_list} self.model = { "portfolio_id": str(uuid.uuid1()), "set_id": recommendation_set.to_dict()['set_id'], "creation_date": util.date_to_iso_utc_string(datetime.now()), "price_date": util.date_to_iso_utc_string(price_date), "securities_set": securities_list } self.validate_model() log.info("Created empty portfolio using price date of: %s", str(price_date))
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 from_parameters(cls, creation_date: datetime, valid_from: datetime, valid_to: datetime, price_date: datetime, strategy_name: str, security_type: str, securities_set: dict): ''' Initializes This class by supplying all required parameters. The "securities_set" is a ticker->price dictionary. E.g. { 'AAPL': 123.45, 'XO' : 234.56, ... } ''' if (strategy_name is None or strategy_name == "" or security_type is None or security_type == "" or securities_set is None or len(securities_set) == 0): raise ValidationError( "Could not initialize Portfolio objects from parameters", None) try: cls.model = { "set_id": str(uuid.uuid1()), "creation_date": util.date_to_iso_utc_string(creation_date), "valid_from": util.date_to_iso_string(valid_from), "valid_to": util.date_to_iso_string(valid_to), "price_date": util.date_to_iso_string(price_date), "strategy_name": strategy_name, "security_type": security_type, "securities_set": [] } for ticker in securities_set.keys(): cls.model['securities_set'].append({ "ticker_symbol": ticker, "price": securities_set[ticker] }) except Exception as e: raise ValidationError( "Could not initialize Portfolio objects from parameters", e) return cls.from_dict(cls.model)
def fill_order(order_id: str, quantity: int, purchase_time: str): ''' If the order is a BUY, then update the portfolio with the details of the trade. ''' if order_id in order_ids: order_ids.remove(order_id) if new_portfolio is None or action == 'SELL': return for sec in new_portfolio.model['current_portfolio']['securities']: if sec['order_id'] == order_id: sec['purchase_date'] = util.date_to_iso_utc_string( parser.parse(purchase_time)) sec['trade_state'] = 'FILLED' sec['quantity'] = quantity break
def test_date_to_iso_utc_string_none(self): self.assertEqual(util.date_to_iso_utc_string(None), "None")
def test_date_to_iso_utc_string_with_error(self): with self.assertRaises(ValidationError): util.date_to_iso_utc_string("not a date")