def show_ef(stocks: List[str], other_args: List[str]):
    parser = argparse.ArgumentParser(add_help=False, prog="ef")

    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-n", default=300, dest="n_port", help="number of portfolios to simulate"
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return
        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return

        stock_prices = process_stocks(stocks, ns_parser.period)
        mu = expected_returns.mean_historical_return(stock_prices)
        S = risk_models.sample_cov(stock_prices)
        ef = EfficientFrontier(mu, S)
        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        # Generate random portfolios
        n_samples = ns_parser.n_port
        w = np.random.dirichlet(np.ones(len(mu)), n_samples)
        rets = w.dot(mu)
        stds = np.sqrt(np.diag(w @ S @ w.T))
        sharpes = rets / stds
        ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")

        plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True)
        # Find the tangency portfolio
        ef.max_sharpe()
        ret_sharpe, std_sharpe, _ = ef.portfolio_performance()
        ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe")

        ax.set_title("Efficient Frontier")
        ax.legend()
        plt.tight_layout()
        plt.grid(b=True, which="major", color="#666666", linestyle="-")
        plt.minorticks_on()
        plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)

        if gtff.USE_ION:
            plt.ion()

        plt.show()
        print("")

    except Exception as e:
        print(e)
        print("")
def efficient_return(stocks: List[str], other_args: List[str]):
    """Displays a portfolio that minimises volatility for a given target return ('Markowitz portfolio')

    Parameters
    ----------
    stocks : List[str]
        List of the stocks to be included in the weights
    other_args : List[str]
        argparse other args
    """

    parser = argparse.ArgumentParser(
        add_help=False,
        prog="effret",
        description="Calculate the 'Markowitz portfolio', minimising volatility for a given target return",
    )
    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-v",
        "--value",
        dest="value",
        help="Amount to allocate to portfolio",
        type=float,
        default=1.0,
    )
    parser.add_argument(
        "-n",
        "--market-neutral",
        action="store_true",
        default=False,
        dest="market_neutral",
        help="""whether the portfolio should be market neutral (weights sum to zero), defaults to False.
        Requires negative lower weight bound.""",
    )
    if "-n" not in other_args:
        parser.add_argument(
            "--pie",
            action="store_true",
            dest="pie",
            default=False,
            help="Display a pie chart for weights. Only if neutral flag is left False.",
        )

    if other_args:
        if "-" not in other_args[0]:
            other_args.insert(0, "-t")
    parser.add_argument(
        "-t",
        "--target-return",
        type=float,
        dest="target_return",
        default=0.1,
        help="the desired return of the resulting portfolio",
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return

        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return

        period = ns_parser.period
        stock_prices = process_stocks(stocks, period)
        ef = prepare_efficient_frontier(stock_prices)

        sp = d_period[ns_parser.period]

        ef_opt = dict(
            ef.efficient_return(ns_parser.target_return, ns_parser.market_neutral)
        )
        s_title = f"{sp} Weights that minimise volatility for a given target return of {ns_parser.target_return}"

        weights = {
            key: ns_parser.value * round(value, 5) for key, value in ef_opt.items()
        }

        if not ns_parser.market_neutral:
            if ns_parser.pie:
                pie_chart_weights(weights, s_title)
                ef.portfolio_performance(verbose=True)
                print("")
                return

        print(s_title)
        display_weights(weights)
        print("")
        ef.portfolio_performance(verbose=True)
        print("")

    except Exception as e:
        print(e)
        print("")
        return
def min_volatility(stocks: List[str], other_args: List[str]):
    """Return a portfolio that optimizes for minimum volatility

    Parameters
    ----------
    stocks : List[str]
        List of the stocks to be included in the weights
    other_args : List[str]
        argparse other args
    """

    parser = argparse.ArgumentParser(
        add_help=False,
        prog="min_volatility",
        description="Optimizes for minimum volatility",
    )
    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-v",
        "--value",
        dest="value",
        help="Amount to allocate to portfolio",
        type=float,
        default=1.0,
    )
    parser.add_argument(
        "--pie",
        action="store_true",
        dest="pie",
        default=False,
        help="Display a pie chart for weights",
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return

        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return

        period = ns_parser.period
        stock_prices = process_stocks(stocks, period)
        ef = prepare_efficient_frontier(stock_prices)

        sp = d_period[ns_parser.period]

        ef_opt = dict(ef.min_volatility())
        s_title = f"{sp} Weights that minimize volatility"

        weights = {
            key: ns_parser.value * round(value, 5) for key, value in ef_opt.items()
        }

        if ns_parser.pie:
            pie_chart_weights(weights, s_title)
        else:
            print(s_title)
            display_weights(weights)
            print("")

        ef.portfolio_performance(verbose=True)
        print("")

    except Exception as e:
        print(e)
        print("")
        return
def max_sharpe(stocks: List[str], other_args: List[str]):
    """Return a portfolio that maximises the Sharpe Ratio

    Parameters
    ----------
    stocks : List[str]
        List of the stocks to be included in the weights
    other_args : List[str]
        argparse other args
    """

    parser = argparse.ArgumentParser(
        add_help=False, prog="maxsharpe", description="Maximise the Sharpe Ratio"
    )
    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-v",
        "--value",
        dest="value",
        help="Amount to allocate to portfolio",
        type=float,
        default=1.0,
    )
    parser.add_argument(
        "--pie",
        action="store_true",
        dest="pie",
        default=False,
        help="Display a pie chart for weights",
    )

    if other_args:
        if "-" not in other_args[0]:
            other_args.insert(0, "-r")
    parser.add_argument(
        "-r",
        "--risk-free-rate",
        type=float,
        dest="risk_free_rate",
        default=0.02,
        help="""Risk-free rate of borrowing/lending. The period of the risk-free rate
                should correspond to the frequency of expected returns.""",
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return

        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return

        period = ns_parser.period
        stock_prices = process_stocks(stocks, period)
        ef = prepare_efficient_frontier(stock_prices)

        sp = d_period[ns_parser.period]

        ef_opt = dict(ef.max_sharpe(ns_parser.risk_free_rate))
        s_title = f"{sp} Weights that maximize Sharpe ratio with risk free level of {ns_parser.risk_free_rate}"

        weights = {
            key: ns_parser.value * round(value, 5) for key, value in ef_opt.items()
        }

        if ns_parser.pie:
            pie_chart_weights(weights, s_title)
        else:
            print(s_title)
            display_weights(weights)
            print("")

        ef.portfolio_performance(verbose=True)
        print("")

    except Exception as e:
        print(e)
        print("")
        return
def ef_portfolio(stocks: List[str], port_type: str, other_args: List[str]):
    """
    Return a portfolio based on condition in port_type  Defaults to 3m of historical data
    Parameters
    ----------
    stocks: List[str]
        List of the stocks to be included in the weights
    port_type: str
        Method to be used on ef object (example: max_sharpe, min_volatility)
    Returns
    -------
    weights: dict
        Dictionary of weights where keys are the tickers.
    """

    parser = argparse.ArgumentParser(add_help=False, prog=port_type)

    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )

    parser.add_argument(
        "-v",
        "--value",
        dest="value",
        help="Amount to allocate to portfolio",
        type=float,
        default=1.0,
    )
    parser.add_argument(
        "--pie",
        action="store_true",
        dest="pie",
        default=False,
        help="Display a pie chart for weights",
    )

    try:
        ns_parser = parse_from_port_type(parser, port_type, other_args)
        if not ns_parser:
            return
        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return
        period = ns_parser.period
        stock_prices = process_stocks(stocks, period)
        ef = prepare_efficient_frontier(stock_prices)

        if port_type == "max_sharpe":

            ef_sharpe = dict(ef.max_sharpe())
            weights = {
                key: ns_parser.value * round(value, 5)
                for key, value in ef_sharpe.items()
            }
            val = 0
            print("Weights that maximize Sharpe Ratio:")

        elif port_type == "min_volatility":

            ef_min_vol = dict(ef.min_volatility())
            weights = {
                key: ns_parser.value * round(value, 5)
                for key, value in ef_min_vol.items()
            }
            val = 0
            print("Weights that minimize volatility")

        elif port_type == "eff_risk":

            ef_eff_risk = dict(ef.efficient_risk(ns_parser.risk_level))
            weights = {
                key: ns_parser.value * round(value, 5)
                for key, value in ef_eff_risk.items()
            }
            val = ns_parser.risk_level
            print(f"Weights for maximizing returns at risk = {100*val:.1f} %")

        elif port_type == "eff_ret":

            ef_eff_risk = dict(ef.efficient_return(ns_parser.target_return))
            weights = {
                key: ns_parser.value * round(value, 5)
                for key, value in ef_eff_risk.items()
            }
            val = ns_parser.target_return
            print(f"Weights for minimizing risk at target return = {100*val:.1f} %")

        else:
            raise ValueError("EF Method not found")

        if ns_parser.pie:
            pie_chart_weights(weights, port_type, val)

        print("")
        ef.portfolio_performance(verbose=True)
        print("")
        display_weights(weights)
        print("")

    except Exception as e:
        print(e)
        print("")
        return
def max_quadratic_utility(stocks: List[str], other_args: List[str]):
    """
    Return a portfolio that maximises the quadratic utility, given some risk aversion

    Parameters
    ----------
    stocks: List[str]
        List of the stocks to be included in the weights

    Returns
    -------
    weights: dict
        Dictionary of weights where keys are the tickers.
    """
    parser = argparse.ArgumentParser(
        add_help=False,
        prog="max_quadratic_utility",
        description="Maximises the quadratic utility, given some risk aversion",
    )
    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-v",
        "--value",
        dest="value",
        help="Amount to allocate to portfolio",
        type=float,
        default=1.0,
    )
    parser.add_argument(
        "-n",
        "--market-neutral",
        action="store_true",
        default=False,
        dest="market_neutral",
        help=
        """whether the portfolio should be market neutral (weights sum to zero), defaults to False.
        Requires negative lower weight bound.""",
    )
    if "-n" not in other_args:
        parser.add_argument(
            "--pie",
            action="store_true",
            dest="pie",
            default=False,
            help=
            "Display a pie chart for weights. Only if neutral flag is left False.",
        )

    if other_args:
        if "-" not in other_args[0]:
            other_args.insert(0, "-r")

    parser.add_argument(
        "-r",
        "--risk-aversion",
        type=float,
        dest="risk_aversion",
        default=1,
        help="risk aversion parameter",
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return None

        if len(stocks) < 2:
            print(
                "Please have at least 2 loaded tickers to calculate weights.\n"
            )
            return

        period = ns_parser.period
        stock_prices = process_stocks(stocks, period)
        ef = prepare_efficient_frontier(stock_prices)

        sp = d_period[ns_parser.period]

        ef_opt = dict(
            ef.max_quadratic_utility(ns_parser.risk_aversion,
                                     ns_parser.market_neutral))
        s_title = f"{sp} Weights that maximise the quadratic utility with risk aversion of {ns_parser.risk_aversion}"

        weights = {
            key: ns_parser.value * round(value, 5)
            for key, value in ef_opt.items()
        }

        if not ns_parser.market_neutral:
            if ns_parser.pie:
                pie_chart_weights(weights, s_title)
                ef.portfolio_performance(verbose=True)
                print("")
                return

        print(s_title)
        display_weights(weights)
        print("")
        ef.portfolio_performance(verbose=True)
        print("")

    except Exception as e:
        print(e)
        print("")
        return