This allocates capital to the Security. This is the method used to
        buy/sell the security.

        A given amount of shares will be determined on the current price, a
        commission will be calculated based on the parent's commission fn, and
        any remaining capital will be passed back up  to parent as an
        adjustment.

        Args:
            * amount (float): Amount of adjustment.
            * update (bool): Force update?

def allocate(self, amount, update=True):
        """
        This allocates capital to the Security. This is the method used to
        buy/sell the security.

        A given amount of shares will be determined on the current price, a
        commission will be calculated based on the parent's commission fn, and
        any remaining capital will be passed back up  to parent as an
        adjustment.

        Args:
            * amount (float): Amount of adjustment.
            * update (bool): Force update?

        """

        # will need to update if this has been idle for a while...
        # update if needupdate or if now is stale
        # fetch parent's now since our now is stale
        if self._needupdate or self.now != self.parent.now:
            self.update(self.parent.now)

        # ignore 0 alloc
        # Note that if the price of security has dropped to zero, then it
        # should never be selected by SelectAll, SelectN etc. I.e. we should
        # not open the position at zero price. At the same time, we are able
        # to close it at zero price, because at that point amount=0.
        # Note also that we don't erase the position in an asset which price
        # has dropped to zero (though the weight will indeed be = 0)
        if amount == 0:
            return

        if self.parent is self or self.parent is None:
            raise Exception(
                'Cannot allocate capital to a parentless security')

        if self._price == 0 or np.isnan(self._price):
            raise Exception(
                'Cannot allocate capital to '
                '%s because price is %s as of %s'
                % (self.name, self._price, self.parent.now))

        # buy/sell
        # determine quantity - must also factor in commission
        # closing out?
        if amount == -self._value:
            q = -self._position
        else:
            q = amount / (self._price * self.multiplier)
            if self.integer_positions:
                if (self._position > 0) or ((self._position == 0) and (
                        amount > 0)):
                    # if we're going long or changing long position
                    q = math.floor(q)
                else:
                    # if we're going short or changing short position
                    q = math.ceil(q)

        # if q is 0 nothing to do
        if q == 0 or np.isnan(q):
            return

        # unless we are closing out a position (q == -position)
        # we want to ensure that
        #
        # - In the event of a positive amount, this indicates the maximum
        # amount a given security can use up for a purchase. Therefore, if
        # commissions push us above this amount, we cannot buy `q`, and must
        # decrease its value
        #
        # - In the event of a negative amount, we want to 'raise' at least the
        # amount indicated, no less. Therefore, if we have commission, we must
        # sell additional units to fund this requirement. As such, q must once
        # again decrease.
        #
        if not q == -self._position:
            full_outlay, _, _ = self.outlay(q)

            # if full outlay > amount, we must decrease the magnitude of `q`
            # this can potentially lead to an infinite loop if the commission
            # per share > price per share. However, we cannot really detect
            # that in advance since the function can be non-linear (say a fn
            # like max(1, abs(q) * 0.01). Nevertheless, we want to avoid these
            # situations.
            # cap the maximum number of iterations to 1e4 and raise exception
            # if we get there
            # if integer positions then we know we are stuck if q doesn't change

            # if integer positions is false then we want full_outlay == amount
            # if integer positions is true then we want to be at the q where
            #   if we bought 1 more then we wouldn't have enough cash
            i = 0
            last_q = q
            last_amount_short = full_outlay - amount
            while not np.isclose(full_outlay, amount, rtol=0.) and q != 0:

                dq_wout_considering_tx_costs = (full_outlay - amount)/(self._price * self.multiplier)
                q = q - dq_wout_considering_tx_costs

                if self.integer_positions:
                    q = math.floor(q)

                full_outlay, _, _ = self.outlay(q)

                # if our q is too low and we have integer positions
                # then we know that the correct quantity is the one  where
                # the outlay of q + 1 < amount. i.e. if we bought one more
                # position then we wouldn't have enough cash
                if self.integer_positions:

                    full_outlay_of_1_more, _, _ = self.outlay(q + 1)

                    if full_outlay < amount and full_outlay_of_1_more > amount:
                        break

                # if not integer positions then we should keep going until
                # full_outlay == amount or is close enough

                i = i + 1
                if i > 1e4:
                    raise Exception(
                        'Potentially infinite loop detected. This occurred '
                        'while trying to reduce the amount of shares purchased'
                        ' to respect the outlay <= amount rule. This is most '
                        'likely due to a commission function that outputs a '
                        'commission that is greater than the amount of cash '
                        'a short sale can raise.')

                if self.integer_positions and last_q == q:
                    raise Exception(
                        'Newton Method like root search for quantity is stuck!'
                        ' q did not change in iterations so it is probably a bug'
                        ' but we are not entirely sure it is wrong! Consider '
                        ' changing to warning.'
                    )
                last_q = q

                if np.abs(full_outlay - amount) > np.abs(last_amount_short):
                    raise Exception(
                        'The difference between what we have raised with q and'
                        ' the amount we are trying to raise has gotten bigger since'
                        ' last iteration! full_outlay should always be approaching'
                        ' amount! There may be a case where the commission fn is'
                        ' not smooth'
                    )
                last_amount_short = full_outlay - amount

        # if last step led to q == 0, then we can return just like above
        if q == 0:
            return

        # this security will need an update, even if pos is 0 (for example if
        # we close the positions, value and pos is 0, but still need to do that
        # last update)
        self._needupdate = True

        # adjust position & value
        self._position += q

        # calculate proper adjustment for parent
        # parent passed down amount so we want to pass
        # -outlay back up to parent to adjust for capital
        # used
        full_outlay, outlay, fee = self.outlay(q)

        # store outlay for future reference
        self._outlay += outlay

        # call parent
        self.parent.adjust(-full_outlay, update=update, flow=False, fee=fee)