示例#1
0
def plot_frontier(portfolio: Portfolio,
                  frontier: list,
                  show: bool = True,
                  savefile: str = None) -> Union[FigureCanvas, None]:
    title = " ("
    for i, item in enumerate(portfolio.tickers):
        if i != (len(portfolio.tickers) - 1):
            title += item + ", "
        else:
            title += item + ") Efficient Frontier"

    return_profile, risk_profile = [], []
    for allocation in frontier:
        return_profile.append(portfolio.return_function(allocation))
        risk_profile.append(portfolio.volatility_function(allocation))

    canvas = FigureCanvas(Figure())
    axes = canvas.figure.subplots()

    axes.plot(risk_profile, return_profile, linestyle='dashed')
    axes.grid()
    axes.set_xlabel('Volatility')
    axes.set_ylabel('Return')
    axes.set_title(title)

    return _show_or_save(canvas=canvas, show=show, savefile=savefile)
示例#2
0
def maximize_portfolio_return(portfolio: Portfolio) -> List[float]:
    """
    Parameters
    ----------
    1. **portfolio**: `scrilla.analysis.objects.Portfolio`
        An instance of the Portfolio class. Must be initialized with an array of ticker symbols. Optionally, it can be initialized with a ``start_date`` and ``end_date`` ``datetime.date``. If ``start_date`` and ``end_date`` are specified, the portfolio will be optimized over the stated time period.

    Output
    ------
    ``List[float]``
        An array of floats that represents the proportion of the portfolio that should be allocated to the corresponding ticker symbols given as a parameter within the portfolio object to achieve the maximum return. Note, this function is often uninteresting because if the rate of return for equity A is 50% and the rate of return of equity B is 25%, the portfolio with a maximized return will always allocated 100% of its value to equity A. However, this function is useful for determining whether or not the optimization algorithm is actually working, so it has been left in the program for debugging purposes. 
    """
    tickers = portfolio.tickers
    init_guess = portfolio.get_init_guess()
    equity_bounds = portfolio.get_default_bounds()
    equity_constraint = {'type': 'eq', 'fun': portfolio.get_constraint}

    logger.debug(f'Maximizing {tickers} Portfolio Return')
    allocation = optimize.minimize(
        fun=lambda x: (-1) * portfolio.return_function(x),
        x0=init_guess,
        method=constants.constants['OPTIMIZATION_METHOD'],
        bounds=equity_bounds,
        constraints=equity_constraint,
        options={'disp': False})

    return allocation.x
示例#3
0
def optimize_conditional_value_at_risk(
        portfolio: Portfolio,
        prob: float,
        expiry: float,
        target_return: float = None) -> List[float]:
    """
    Parameters
    ----------
    1. **portfolio**: `scrilla.analysis.objects.Portfolio`
        An instance of the `Portfolio` class. Must be initialized with an array of ticker symbols. Optionally, it can be initialized with a start_date and end_date datetime. If start_date and end_date are specified, the portfolio will be optimized over the stated time period. Otherwise, date range will default to range defined by `scrilla.settings.DEFAULT_ANALYSIS_PERIOD`.
    2. **prob**: ``float``
        Probability of loss.
    3. **expiry**: ``float``
        Time horizon for the value at risk expectation, i.e. the time in the future at which point the portfolio will be considered "closed" and the hypothetical loss will occur. 
    4. **target_return**: ``float``
        *Optional*. Defaults to `None`. The target return constraint, as a decimal, subject to which the portfolio's conditional value at risk will be optimized.

    Returns
    -------
    ``list``
        A list of floats that represents the proportion of the portfolio that should be allocated to the corresponding ticker symbols given as a parameter within the `Portfolio` object. In other words, if `portfolio.tickers = ['AAPL', 'MSFT']` and the output to this function is `[0.25, 0.75]`, this result means a portfolio with 25% allocation in AAPL and a 75% allocation in MSFT will result in an optimally constructed portfolio with respect to its conditional value at risk. 

    """
    tickers = portfolio.tickers
    init_guess = portfolio.get_init_guess()
    equity_bounds = portfolio.get_default_bounds()

    equity_constraint = {'type': 'eq', 'fun': portfolio.get_constraint}

    if target_return is not None:
        logger.debug(
            f'Optimizing {tickers} Portfolio Conditional Value at Risk Subject To Return = {target_return}'
        )

        return_constraint = {
            'type': 'eq',
            'fun': portfolio.get_target_return_constraint
        }
        portfolio_constraints = [equity_constraint, return_constraint]
    else:
        logger.debug(
            f'Minimizing {tickers} Portfolio Conditional Value at Risk')
        portfolio_constraints = equity_constraint

    allocation = optimize.minimize(
        fun=lambda x: portfolio.conditional_value_at_risk_function(
            x, expiry, prob),
        x0=init_guess,
        method=constants.constants['OPTIMIZATION_METHOD'],
        bounds=equity_bounds,
        constraints=portfolio_constraints,
        options={'disp': False})

    return allocation.x
示例#4
0
    def optimize(self):
        if self.table_widget.table.isVisible():
            self.table_widget.table.clear()
            self.table_widget.table.hide()

        symbols = self.arg_widget.get_symbol_input()

        # TODO: better error checking
        if len(symbols) > 1:
            investment = self.arg_widget.get_control_input('investment')
            this_portfolio = Portfolio(
                tickers=symbols,
                start_date=self.arg_widget.get_control_input('start_date'),
                end_date=self.arg_widget.get_control_input('end_date'))
            allocation = optimizer.optimize_portfolio_variance(
                portfolio=this_portfolio,
                target_return=self.arg_widget.get_control_input('target'))
            self.title.setText(
                formats.format_allocation_profile_title(
                    allocation, this_portfolio))

            prices = services.get_daily_prices_latest(tickers=symbols)

            if investment is None:
                self.table_widget.init_table(rows=symbols,
                                             columns=['Allocation'])
            else:
                self.table_widget.init_table(rows=symbols,
                                             columns=['Allocation', 'Shares'])
                shares = this_portfolio.calculate_approximate_shares(
                    allocation, float(investment), prices)

            for i in range(len(symbols)):
                item = factories.atomic_widget_factory(
                    component='table-item',
                    title=helper.format_float_percent(allocation[i]))
                self.table_widget.table.setItem(i, 0, item)

                if investment is not None:
                    share_item = factories.atomic_widget_factory(
                        component='table-item', title=str(shares[i]))
                    self.table_widget.table.setItem(i, 1, share_item)

            # TODO: display amount vested per equity
            # TODO: display total portfolio return and volatility
            # TODO: display actual investment
            self.table_widget.show_table()
            self.arg_widget.fire()

        else:
            print('something went wrong')
示例#5
0
def calculate_efficient_frontier(portfolio: Portfolio,
                                 steps=None) -> List[List[float]]:
    """
    Parameters
    ----------
    1. **portfolio**: `scrilla.analysis.objects.Portfolio`
        An instance of the Portfolio class defined in  analysis.objects.portfolio. Must be initialized with an array of ticker symbols. Optionally, it can be initialized with a start_date and end_date datetime. If start_date and end_date are specified, the portfolio will be optimized over the stated time period.\n \n

    2. **steps**: ``int``
        *Optional*. Defaults to `None`. The number of points calculated in the efficient frontier. If none is provided, it defaults to the environment variable **FRONTIER_STEPS**.

    Returns
    -------
    ``List[List[float]]``
        A nested list of floats. Each float list corresponds to a point on a portfolio's efficient frontier, i.e. each list represents the percentage of a portfolio that should be allocated to the equity with the corresponding ticker symbol supplied as an attribute to the ``scrilla.analysis.objects.Portfolio`` object parameter.
    """
    if steps is None:
        steps = settings.FRONTIER_STEPS

    minimum_allocation = optimize_portfolio_variance(portfolio=portfolio)
    maximum_allocation = maximize_portfolio_return(portfolio=portfolio)

    minimum_return = portfolio.return_function(minimum_allocation)
    maximum_return = portfolio.return_function(maximum_allocation)
    return_width = (maximum_return - minimum_return) / steps

    frontier = []
    for i in range(steps + 1):
        target_return = minimum_return + return_width * i
        allocation = optimize_portfolio_variance(portfolio=portfolio,
                                                 target_return=target_return)
        frontier.append(allocation)

    return frontier
示例#6
0
def test_asset_groups(tickers, groups):
    with HTTMock(mock.mock_prices):
        with HTTMock(mock.mock_interest):
            test_portfolio = Portfolio(tickers=tickers,
                                       start_date=test_settings.START,
                                       end_date=test_settings.END)
    assert (test_portfolio.asset_groups == groups)
示例#7
0
def test_weekend_initialization(tickers, weekends):
    with HTTMock(mock.mock_prices):
        with HTTMock(mock.mock_interest):
            test_portfolio = Portfolio(tickers=tickers,
                                       start_date=test_settings.START,
                                       end_date=test_settings.END)
    assert (test_portfolio.weekends == weekends)
示例#8
0
def maximize_sharpe_ratio(portfolio: Portfolio,
                          target_return: float = None) -> List[float]:
    """
    Parameters
    ----------
    1. **portfolio**: `scrilla.analysis.objects.Portfolio`
        An instance of the `Portfolio` class. Must be initialized with an array of ticker symbols. Optionally, it can be initialized with a start_date and end_date datetime. If start_date and end_date are specified, the portfolio will be optimized over the stated time period. Otherwise, date range will default to range defined by `scrilla.settings.DEFAULT_ANALYSIS_PERIOD`.
    2. **target_return**: ``float``
        *Optional*. Defaults to `None`. The target return constraint, as a decimal, subject to which the portfolio's sharpe ratio will be maximized.

    Returns
    -------
    ``list``
        A list of floats that represents the proportion of the portfolio that should be allocated to the corresponding ticker symbols given as a parameter within the `Portfolio` object. In other words, if `portfolio.tickers = ['AAPL', 'MSFT']` and the output to this function is `[0.25, 0.75]`, this result means a portfolio with 25% allocation in AAPL and a 75% allocation in MSFT will result in an optimally constructed portfolio with respect to its sharpe ratio.  
    """
    tickers = portfolio.tickers
    portfolio.set_target_return(target_return)

    init_guess = portfolio.get_init_guess()
    equity_bounds = portfolio.get_default_bounds()
    equity_constraint = {'type': 'eq', 'fun': portfolio.get_constraint}

    if target_return is not None:
        logger.debug(
            f'Optimizing {tickers} Portfolio Sharpe Ratio Subject To Return = {target_return}'
        )

        return_constraint = {
            'type': 'eq',
            'fun': portfolio.get_target_return_constraint
        }
        portfolio_constraints = [equity_constraint, return_constraint]
    else:
        logger.debug(f'Maximizing {tickers} Portfolio Sharpe Ratio')
        portfolio_constraints = equity_constraint

    allocation = optimize.minimize(
        fun=lambda x: (-1) * portfolio.sharpe_ratio_function(x),
        x0=init_guess,
        method=constants.constants['OPTIMIZATION_METHOD'],
        bounds=equity_bounds,
        constraints=portfolio_constraints,
        options={'disp': False})

    return allocation.x
示例#9
0
    def calculate(self):
        if self.graph_widget.figure.isVisible():
            self.graph_widget.figure.hide()

        this_portfolio = Portfolio(
            tickers=self.arg_widget.get_symbol_input(),
            start_date=self.arg_widget.get_control_input('start_date'),
            end_date=self.arg_widget.get_control_input('end_date'))
        frontier = optimizer.calculate_efficient_frontier(
            portfolio=this_portfolio,
            steps=self.arg_widget.get_control_input('steps'))
        plotter.plot_frontier(
            portfolio=this_portfolio,
            frontier=frontier,
            show=False,
            savefile=
            f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["FRONTIER"]}')

        self.graph_widget.set_pixmap()
        self.arg_widget.fire()
示例#10
0
def portfolios():
    with HTTMock(mock.mock_prices):
        with HTTMock(mock.mock_interest):
            portfolios = [
                Portfolio(tickers=['ALLY', 'BX'],
                          start_date=test_settings.START,
                          end_date=test_settings.END),
                Portfolio(tickers=['SPY', 'BTC'],
                          start_date=test_settings.START,
                          end_date=test_settings.END),
                Portfolio(tickers=['BTC', 'ALGO'],
                          start_date=test_settings.START,
                          end_date=test_settings.END),
                Portfolio(tickers=['ALLY', 'DIS', 'BX'],
                          start_date=test_settings.START,
                          end_date=test_settings.END),
                Portfolio(tickers=['SPY', 'GLD', 'BTC'],
                          start_date=test_settings.START,
                          end_date=test_settings.END),
                Portfolio(tickers=['ALLY', 'SPY', 'BTC', 'ALGO'],
                          start_date=test_settings.START,
                          end_date=test_settings.END)
            ]
    return portfolios