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")