def equal_weight(stocks: List[str], other_args: List[str]): """ Equally weighted portfolio, where weight = 1/# of stocks Parameters ---------- stocks: List[str] List of tickers to be included in optimization Returns ------- weights : dict Dictionary of weights where keys are the tickers """ parser = argparse.ArgumentParser( add_help=False, prog="equal", description="Returns an equally weighted portfolio", ) parser.add_argument( "-v", "--value", default=1, type=float, dest="value", help="Amount to allocate to portfolio", ) 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 values = {} for stock in stocks: values[stock] = ns_parser.value * round(1 / len(stocks), 5) if ns_parser.pie: pie_chart_weights(values, "Equally Weighted Portfolio") else: display_weights(values) 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 property_weighting(stocks: List[str], other_args: List[str]): """Weighted portfolio where each weight is the relative fraction of a specified info property. Parameters ---------- stocks: List[str] List of tickers to be included in optimization other_args : List[str] Command line arguments to be processed with argparse """ parser = argparse.ArgumentParser( add_help=False, prog="property", description="Returns a portfolio that is weighted based on a selected property info", ) parser.add_argument( "-p", "--property", required=bool("-h" not in other_args), type=check_valid_property_type, dest="property", help="""Property info to weigh. Use one of: previousClose, regularMarketOpen, twoHundredDayAverage, trailingAnnualDividendYield, payoutRatio, volume24Hr, regularMarketDayHigh, navPrice, averageDailyVolume10Day, totalAssets, regularMarketPreviousClose, fiftyDayAverage, trailingAnnualDividendRate, open, toCurrency, averageVolume10days, expireDate, yield, algorithm, dividendRate, exDividendDate, beta, circulatingSupply, regularMarketDayLow, priceHint, currency, trailingPE, regularMarketVolume, lastMarket, maxSupply, openInterest, marketCap, volumeAllCurrencies, strikePrice, averageVolume, priceToSalesTrailing12Months, dayLow, ask, ytdReturn, askSize, volume, fiftyTwoWeekHigh, forwardPE, fromCurrency, fiveYearAvgDividendYield, fiftyTwoWeekLow, bid, dividendYield, bidSize, dayHigh, annualHoldingsTurnover, enterpriseToRevenue, beta3Year, profitMargins, enterpriseToEbitda, 52WeekChange, morningStarRiskRating, forwardEps, revenueQuarterlyGrowth, sharesOutstanding, fundInceptionDate, annualReportExpenseRatio, bookValue, sharesShort, sharesPercentSharesOut, fundFamily, lastFiscalYearEnd, heldPercentInstitutions, netIncomeToCommon, trailingEps, lastDividendValue, SandP52WeekChange, priceToBook, heldPercentInsiders, shortRatio, sharesShortPreviousMonthDate, floatShares, enterpriseValue, threeYearAverageReturn, lastSplitFactor, legalType, lastDividendDate, morningStarOverallRating, earningsQuarterlyGrowth, pegRatio, lastCapGain, shortPercentOfFloat, sharesShortPriorMonth, impliedSharesOutstanding, fiveYearAverageReturn, and regularMarketPrice.""", ) parser.add_argument( "-v", "--value", default=1, type=float, dest="value", help="Amount to allocate to portfolio", ) parser.add_argument( "--pie", action="store_true", dest="pie", default=False, help="Display a pie chart for weights", ) try: if other_args: if "-" not in other_args[0]: other_args.insert(0, "-p") 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 weights = {} prop = {} prop_sum = 0 for stock in stocks: stock_prop = yf.Ticker(stock).info[ns_parser.property] if stock_prop is None: stock_prop = 0 prop[stock] = stock_prop prop_sum += stock_prop if prop_sum == 0: print(f"No {ns_parser.property} was found on list of tickers provided") print("") return for k, v in prop.items(): weights[k] = round(v / prop_sum, 5) * ns_parser.value if ns_parser.pie: pie_chart_weights( weights, "Weighted Portfolio based on " + ns_parser.property ) else: display_weights(weights) print("") except Exception as e: print(e) print("") return
def property_weighting(stocks: List[str], property_type: str, other_args: List[str]): """ Property weighted portfolio where each weight is the relative fraction. Parameters ---------- stocks: List[str] List of tickers to be included in optimization property_type: str Property to weight by. Can be anything in yfinance.Ticker().info. Examples: "marketCap", "dividendYield", etc Returns ------- weights: dict Dictionary of weights where keys are the tickers """ parser = argparse.ArgumentParser( add_help=False, prog="market_cap_weighted", description="Return portfolio weights/values that are weighted by marketcap", ) parser.add_argument( "-v", "--value", default=1, type=float, dest="value", help="Amount to allocate to portfolio", ) parser.add_argument( "--pie", action="store_true", dest="pie", default=False, help="Display a pie chart for weights", ) weights = {} prop = {} prop_sum = 0 try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return for stock in stocks: stock_prop = yf.Ticker(stock).info[property_type] if stock_prop is None: stock_prop = 0 prop[stock] = stock_prop prop_sum += stock_prop for k, v in prop.items(): weights[k] = round(v / prop_sum, 5) * ns_parser.value if ns_parser.pie: pie_chart_weights(weights, property_type, 0) if property_type == "marketCap": print("Market Cap Weighted Portfolio: ") elif property_type == "dividendYield": print("Dividend Yield Weighted Portfolio: ") if len(stocks) >= 1: display_weights(weights) 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