Exemplo n.º 1
0
def display_ef(
    stocks: List[str],
    period: str = "3mo",
    n_portfolios: int = 300,
    risk_free: bool = False,
):
    """Display efficient frontier

    Parameters
    ----------
    stocks : List[str]
        List of the stocks to be included in the weights
    other_args : List[str]
        argparse other args
    """
    fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
    ef, rets, stds = optimizer_model.generate_random_portfolios(
        stocks, period, n_portfolios)
    # The ef needs to be deep-copied to avoid error in plotting sharpe
    ef2 = copy.deepcopy(ef)

    sharpes = rets / stds
    ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")
    for ticker, ret, std in zip(ef.tickers, ef.expected_returns,
                                np.sqrt(np.diag(ef.cov_matrix))):
        ax.annotate(ticker, (std * 1.01, ret))
    plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True)
    # Find the tangency portfolio
    rfrate = get_rf()
    ef2.max_sharpe(risk_free_rate=rfrate)
    ret_sharpe, std_sharpe, _ = ef2.portfolio_performance(
        verbose=True, risk_free_rate=rfrate)
    ax.scatter(std_sharpe,
               ret_sharpe,
               marker="*",
               s=100,
               c="r",
               label="Max Sharpe")
    # Add risk free line
    if risk_free:
        y = ret_sharpe * 1.2
        b = get_rf()
        m = (ret_sharpe - b) / std_sharpe
        x2 = (y - b) / m
        x = [0, x2]
        y = [b, y]
        line = Line2D(x, y, color="#FF0000", label="Capital Allocation Line")
        ax.set_xlim(xmin=min(stds) * 0.8)
        ax.add_line(line)
    ax.set_title(f"Efficient Frontier simulating {n_portfolios} portfolios")
    ax.legend()
    fig.tight_layout()
    ax.grid(b=True, which="major", color="#666666", linestyle="-")

    if gtff.USE_ION:
        plt.ion()

    plt.show()
    console.print("")
Exemplo n.º 2
0
 def __init__(self, ticker: str, audit: bool):
     self.audit: bool = audit
     self.wb: Workbook = Workbook()
     self.ws1: worksheet = self.wb.active
     self.ws2: worksheet = self.wb.create_sheet("Free Cash Flows")
     self.ws3: worksheet = self.wb.create_sheet("Explanations")
     self.ws4: worksheet = self.wb.create_sheet("Ratios")
     self.ws1.title = "Financials"
     self.ticker: str = ticker
     self.now: str = datetime.now().strftime("%Y-%m-%d")
     self.letter: int = 0
     self.is_start: int = 4
     self.bs_start: int = 18
     self.cf_start: int = 47
     self.len_data: int = 0
     self.len_pred: int = 10
     self.years: List[str] = []
     self.rounding: int = 0
     self.df_bs: pd.DataFrame = self.get_data("BS", self.bs_start, False)
     self.df_is: pd.DataFrame = self.get_data("IS", self.is_start, True)
     self.df_cf: pd.DataFrame = self.get_data("CF", self.cf_start, False)
     self.info: pd.DataFrame = yf.Ticker(ticker).info
     self.t_bill: float = get_rf()
     self.r_ff: float = dcf_model.get_fama_coe(self.ticker)
     self.sisters: List[str] = dcf_model.others_in_sector(
         self.ticker, self.info["sector"], self.info["industry"]
     )
     self.sister_data: List[List[pd.DataFrame]] = [[pd.DataFrame()]]
Exemplo n.º 3
0
    def call_maxsharpe(self, other_args: List[str]):
        """Process maxsharpe command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            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",
        )
        parser.add_argument(
            "-r",
            "--risk-free-rate",
            type=float,
            dest="risk_free_rate",
            default=get_rf(),
            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(self.tickers) < 2:
                print("Please have at least 2 loaded tickers to calculate weights.\n")
                return
            optimizer_view.display_max_sharpe(
                stocks=self.tickers,
                period=ns_parser.period,
                value=ns_parser.value,
                rfrate=ns_parser.risk_free_rate,
                pie=ns_parser.pie,
            )
        except Exception as e:
            print(e, "\n")
Exemplo n.º 4
0
    def __init__(
        self,
        ticker: str,
        audit: bool = False,
        ratios: bool = True,
        len_pred: int = 10,
        max_similars: int = 3,
        no_filter: bool = False,
    ):
        """
        Creates a detialed DCF for a given company

        Parameters
        ----------
        ticker : str
            The ticker to create a DCF for
        audit : bool
            Whether or not to show that the balance sheet and income statement tie-out
        ratios : bool
            Whether to show ratios for the company and for similar companies
        len_pred : int
            The number of years to make predictions for before assuming a terminal value
        max_similars : int
            The maximum number of similar companies to show, will be less if there are not enough similar companies
        no_filter : bool
            Disable filtering of similar companies to being in the same market cap category
        """
        self.info: Dict[str, Any] = {
            "len_data": 0,
            "len_pred": len_pred,
            "max_similars": max_similars,
            "rounding": 0,
            "ticker": ticker,
            "audit": audit,
            "ratios": ratios,
            "no_filter": no_filter,
        }
        self.letter: int = 0
        self.starts: Dict[str, int] = {"IS": 4, "BS": 18, "CF": 47}
        self.wb: Workbook = Workbook()
        self.ws: Dict[int, Any] = {
            1: self.wb.active,
            2: self.wb.create_sheet("Free Cash Flows"),
            3: self.wb.create_sheet("Explanations"),
        }
        self.df: Dict[str, pd.DataFrame] = {
            "BS": self.get_data("BS", self.starts["BS"], False),
            "IS": self.get_data("IS", self.starts["IS"], True),
            "CF": self.get_data("CF", self.starts["CF"], False),
        }
        self.data: Dict[str, Any] = {
            "now": datetime.now().strftime("%Y-%m-%d"),
            "info": yf.Ticker(ticker).info,
            "t_bill": get_rf(),
            "r_ff": dcf_model.get_fama_coe(self.info["ticker"]),
        }
Exemplo n.º 5
0
    def __init__(self, df: pd.DataFrame, hist: pd.DataFrame, m_tick: str,
                 n: int):
        """Generate financial reports.
        Financial reports allow users to show the how they have been performing in
        trades. This allows for a simple way to show progress and analyze metrics
        that track portfolio performance

        Parameters
        ----------
        df : pd.DataFrame
            The dataframe with previous holdings information
        hist : pd.DataFrame
            The dataframe with previous prices for stocks in the portfolio
        m_tick : str
            The market asset to be identified
        n : int
            The number of days to analyze

        Attributes
        ----------
        generate_report : None
            Generates a report with the given parameters
        generate_pg1 : None
            Creates the first page of the PDF report
        generate_pg2 : None
            Creates the second page of the PDF report

        """
        self.df = df
        self.hist = hist
        self.m_tick = m_tick
        self.df_m = yfinance_model.get_market(self.df.index[0], self.m_tick)
        self.returns, self.variance = portfolio_model.get_return(
            df, self.df_m, n)
        self.rf = get_rf()
        self.betas = portfolio_model.get_rolling_beta(self.df, self.hist,
                                                      self.df_m, 365)
Exemplo n.º 6
0
def show_binom(
    ticker: str,
    expiration: str,
    strike: float,
    put: bool,
    europe: bool,
    export: bool,
    plot: bool,
    vol: float,
) -> None:
    """Get binomial pricing for option

    Parameters
    ----------
    ticker : str
        The ticker of the option's underlying asset
    expiration : str
        The expiration for the option
    strike : float
        The strike price for the option
    put : bool
        Value a put instead of a call
    europe : bool
        Value a European option instead of an American option
    export : bool
        Export the options data to an excel spreadsheet
    plot : bool
        Show a graph of expected ending prices
    vol : float
        The annualized volatility for the underlying asset
    """
    # Base variables to calculate values
    info = yfinance_model.get_info(ticker)
    price = info["regularMarketPrice"]
    if vol is None:
        closings = yfinance_model.get_closing(ticker)
        vol = (closings / closings.shift()).std() * (252**0.5)
    div_yield = (info["trailingAnnualDividendYield"]
                 if info["trailingAnnualDividendYield"] is not None else 0)
    delta_t = 1 / 252
    rf = get_rf()
    exp_date = datetime.strptime(expiration, "%Y-%m-%d").date()
    today = date.today()
    days = (exp_date - today).days

    # Binomial pricing specific variables
    up = math.exp(vol * (delta_t**0.5))
    down = 1 / up
    prob_up = (math.exp((rf - div_yield) * delta_t) - down) / (up - down)
    prob_down = 1 - prob_up
    discount = math.exp(delta_t * rf)

    und_vals: List[List[float]] = [[price]]

    # Binomial tree for underlying values
    for i in range(days):
        cur_date = today + timedelta(days=i + 1)
        if cur_date.weekday() < 5:
            last = und_vals[-1]
            new = [x * up for x in last]
            new.append(last[-1] * down)
            und_vals.append(new)

    # Binomial tree for option values
    if put:
        opt_vals = [[max(strike - x, 0) for x in und_vals[-1]]]
    else:
        opt_vals = [[max(x - strike, 0) for x in und_vals[-1]]]

    j = 2
    while len(opt_vals[0]) > 1:
        new_vals = []
        for i in range(len(opt_vals[0]) - 1):
            if europe:
                value = (opt_vals[0][i] * prob_up +
                         opt_vals[0][i + 1] * prob_down) / discount
            else:
                if put:
                    value = max(
                        (opt_vals[0][i] * prob_up +
                         opt_vals[0][i + 1] * prob_down) / discount,
                        strike - und_vals[-j][i],
                    )
                else:
                    value = max(
                        (opt_vals[0][i] * prob_up +
                         opt_vals[0][i + 1] * prob_down) / discount,
                        und_vals[-j][i] - strike,
                    )
            new_vals.append(value)
        opt_vals.insert(0, new_vals)
        j += 1

    if export:
        export_binomial_calcs(up, prob_up, discount, und_vals, opt_vals, days,
                              ticker)

    if plot:
        plot_expected_prices(und_vals, prob_up, ticker, expiration)

    option = "put" if put else "call"
    console.print(
        f"{ticker} {option} at ${strike:.2f} expiring on {expiration} is worth ${opt_vals[0][0]:.2f}\n"
    )
Exemplo n.º 7
0
def risk_neutral_vals(
    ticker: str,
    exp: str,
    put: bool,
    df: pd.DataFrame,
    mini: float,
    maxi: float,
    risk: float,
) -> None:
    """Prints current options prices and risk neutral values [Source: Yahoo Finance]

    Parameters
    ----------
    ticker : str
        Ticker to get expirations for
    exp : str
        Expiration to use for options
    put : bool
        Whether to use puts or calls
    df : pd.DataFrame
        Estimates for stocks prices and probabilities
    mini : float
        Minimum strike price to show
    maxi : float
        Maximum strike price to show
    risk : float
        The risk-free rate for the asset
    """
    if put:
        chain = get_option_chain(ticker, exp).puts
    else:
        chain = get_option_chain(ticker, exp).calls

    r_date = datetime.strptime(exp, "%Y-%m-%d").date()
    delta = (r_date - date.today()).days
    vals = []
    if risk is None:
        risk = get_rf()
    for _, row in chain.iterrows():
        vals.append([
            row["strike"],
            row["lastPrice"],
            op_helpers.rn_payoff(row["strike"], df, put, delta, risk),
        ])
    new_df = pd.DataFrame(vals,
                          columns=["Strike", "Last Price", "Value"],
                          dtype=float)
    new_df["Difference"] = new_df["Last Price"] - new_df["Value"]

    if mini is None:
        mini = new_df.Strike.quantile(0.25)
    if maxi is None:
        maxi = new_df.Strike.quantile(0.75)

    new_df = new_df[new_df["Strike"] >= mini]
    new_df = new_df[new_df["Strike"] <= maxi]

    print_rich_table(
        new_df,
        headers=[x.title() for x in new_df.columns],
        show_index=False,
        title="Risk Neutral Values",
    )
    console.print()
Exemplo n.º 8
0
def show_parity(ticker: str, exp: str, put: bool, ask: bool, mini: float,
                maxi: float, export: str) -> None:
    """Prints options and whether they are under or over priced [Source: Yahoo Finance]

    Parameters
    ----------
    ticker : str
        Ticker to get expirations for
    exp : str
        Expiration to use for options
    put : bool
        Whether to use puts or calls
    ask : bool
        Whether to use ask or lastPrice
    mini : float
        Minimum strike price to show
    maxi : float
        Maximum strike price to show
    export : str
        Export data
    """
    r_date = datetime.strptime(exp, "%Y-%m-%d").date()
    delta = (r_date - date.today()).days
    rate = ((1 + get_rf())**(delta / 365)) - 1
    stock = get_price(ticker)

    div_info = yfinance_model.get_dividend(ticker)
    div_dts = div_info.index.values.tolist()

    if div_dts:
        last_div = pd.to_datetime(div_dts[-1])

        if len(div_dts) > 3:
            avg_div = np.mean(div_info.to_list()[-4:])
        else:
            avg_div = np.mean(div_info.to_list())

        next_div = last_div + timedelta(days=91)
        dividends = []
        while next_div < datetime.strptime(exp, "%Y-%m-%d"):
            day_dif = (next_div - datetime.now()).days
            dividends.append((avg_div, day_dif))
            next_div += timedelta(days=91)
        div_pvs = [x[0] / ((1 + get_rf())**(x[1] / 365)) for x in dividends]
        pv_dividend = sum(div_pvs)
    else:
        pv_dividend = 0

    chain = get_option_chain(ticker, exp)
    name = "ask" if ask else "lastPrice"
    o_type = "put" if put else "call"

    calls = chain.calls[["strike", name]].copy()
    calls = calls.rename(columns={name: "callPrice"})
    puts = chain.puts[["strike", name]].copy()
    puts = puts.rename(columns={name: "putPrice"})

    opts = pd.merge(calls, puts, on="strike")
    opts = opts.dropna()
    opts = opts.loc[opts["callPrice"] * opts["putPrice"] != 0]

    opts["callParity"] = (opts["putPrice"] + stock -
                          (opts["strike"] / (1 + rate)) - pv_dividend)
    opts["putParity"] = ((opts["strike"] / (1 + rate)) + opts["callPrice"] -
                         stock + pv_dividend)

    diff = o_type + " Difference"
    opts[diff] = opts[o_type + "Price"] - opts[o_type + "Parity"]
    opts["distance"] = abs(stock - opts["strike"])
    filtered = opts.copy()

    if mini is None:
        mini = filtered.strike.quantile(0.25)
    if maxi is None:
        maxi = filtered.strike.quantile(0.75)

    filtered = filtered.loc[filtered["strike"] >= mini]
    filtered = filtered.loc[filtered["strike"] <= maxi]

    show = filtered[["strike", diff]].copy()

    if ask:
        console.print(
            "Warning: Options with no current ask price not shown.\n")

    print_rich_table(
        show,
        headers=[x.title() for x in show.columns],
        show_index=False,
        title="Warning: Low volume options may be difficult to trade.",
    )

    export_data(
        export,
        os.path.dirname(os.path.abspath(__file__)),
        "parity",
        show,
    )
    console.print()
Exemplo n.º 9
0
def show_greeks(
    ticker: str,
    div_cont: float,
    expire: str,
    rf: float = None,
    opt_type: int = 1,
    mini: float = None,
    maxi: float = None,
    show_all: bool = False,
) -> None:
    """
    Shows the greeks for a given option

    Parameters
    ----------
    ticker : str
        The ticker value of the option
    div_cont : float
        The dividend continuous rate
    expire : str
        The date of expiration
    rf : float
        The risk-free rate
    opt_type : Union[1, -1]
        The option type 1 is for call and -1 is for put
    mini : float
        The minimum strike price to include in the table
    maxi : float
        The maximum strike price to include in the table
    all : bool
        Whether to show all greeks
    """

    s = yfinance_model.get_price(ticker)
    chains = yfinance_model.get_option_chain(ticker, expire)
    chain = chains.calls if opt_type == 1 else chains.puts

    if mini is None:
        mini = chain.strike.quantile(0.25)
    if maxi is None:
        maxi = chain.strike.quantile(0.75)

    chain = chain[chain["strike"] >= mini]
    chain = chain[chain["strike"] <= maxi]

    risk_free = rf if rf is not None else get_rf()
    expire_dt = datetime.strptime(expire, "%Y-%m-%d")
    dif = (expire_dt - datetime.now()).seconds / (60 * 60 * 24)

    strikes = []
    for _, row in chain.iterrows():
        vol = row["impliedVolatility"]
        opt = Option(s, row["strike"], risk_free, div_cont, dif, vol, opt_type)
        result = [
            row["strike"],
            row["impliedVolatility"],
            opt.Delta(),
            opt.Gamma(),
            opt.Vega(),
            opt.Theta(),
        ]
        if show_all:
            result += [
                opt.Rho(),
                opt.Phi(),
                opt.Charm(),
                opt.Vanna(0.01),
                opt.Vomma(0.01),
            ]
        strikes.append(result)

    columns = [
        "Strike",
        "Implied Vol",
        "Delta",
        "Gamma",
        "Vega",
        "Theta",
    ]
    if show_all:
        columns += ["Rho", "Phi", "Charm", "Vanna", "Vomma"]
    df = pd.DataFrame(strikes, columns=columns)
    print_rich_table(df,
                     headers=list(df.columns),
                     show_index=False,
                     title="Greeks")
    console.print()
    return None
Exemplo n.º 10
0
def display_ef(
    stocks: List[str],
    period: str = "3mo",
    n_portfolios: int = 300,
    risk_free: bool = False,
    external_axes: Optional[List[plt.Axes]] = None,
):
    """Display efficient frontier

    Parameters
    ----------
    stocks : List[str]
        List of the stocks to be included in the weights
    period : str
        Time period to get returns for
    n_portfolios: int
        Number of portfolios to simulate
    external_axes: Optional[List[plt.Axes]]
        Optional axes to plot on
    """
    if external_axes is None:
        _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
    else:
        ax = external_axes[0]
    ef, rets, stds = optimizer_model.generate_random_portfolios(
        stocks, period, n_portfolios)
    # The ef needs to be deep-copied to avoid error in plotting sharpe
    ef2 = copy.deepcopy(ef)

    sharpes = rets / stds
    ax.scatter(stds, rets, marker=".", c=sharpes)
    plotting.plot_efficient_frontier(ef, ax=ax, show_assets=False)

    for ticker, ret, std in zip(ef.tickers, ef.expected_returns,
                                np.sqrt(np.diag(ef.cov_matrix))):
        ax.scatter(std, ret, s=50, marker=".", c="w")
        ax.annotate(ticker, (std * 1.01, ret))
    # Find the tangency portfolio
    rfrate = get_rf()
    ef2.max_sharpe(risk_free_rate=rfrate)
    ret_sharpe, std_sharpe, _ = ef2.portfolio_performance(
        verbose=True, risk_free_rate=rfrate)
    ax.scatter(std_sharpe,
               ret_sharpe,
               marker="*",
               s=100,
               c="r",
               label="Max Sharpe")
    # Add risk free line
    if risk_free:
        y = ret_sharpe * 1.2
        b = get_rf()
        m = (ret_sharpe - b) / std_sharpe
        x2 = (y - b) / m
        x = [0, x2]
        y = [b, y]
        line = Line2D(x, y, label="Capital Allocation Line")
        ax.set_xlim(xmin=min(stds) * 0.8)
        ax.add_line(line)
    ax.set_title(f"Efficient Frontier simulating {n_portfolios} portfolios")

    ax.legend(loc="best", scatterpoints=1)

    theme.style_primary_axis(ax)
    if external_axes is None:
        theme.visualize_output()