Example #1
0
def create_simulated_portfolio(
    portfolio: pd.DataFrame, sim_symbol: str = "SWPPX"
) -> pd.DataFrame:
    """Given a portfolio, create a parallel portfolio which has
    all of the same contributions and withdrawals. In the parallel
    simulated portfolio, all contributions are immediately used to
    purchase the security indicated by the `sim_symbol`, and all
    withdrawals are financed by selling this security.
    """
    sim_port = port.init_portfolio(portfolio.index)
    sim_port = port.init_symbol(sim_port, sim_symbol)
    prices = quotes.get_price(sim_symbol, sim_port.index)
    for column in ["contributions", "withdrawals"]:
        sim_port[column] = portfolio[column].copy()

    deposits = port.get_deposits(portfolio)
    for date, amt in deposits[deposits != 0].iteritems():
        qty = np.abs(amt) / prices.loc[date]
        sign = -1 if amt < 0 else 1
        sim_port.loc[date:, f"{sim_symbol}"] += sign * qty

    # We've recorded simulated purchases, but the simulated security
    # would also have generated dividends.
    sim_port = add_sim_dividend(sim_port, sim_symbol)
    port.total_portfolio(sim_port)

    return sim_port
Example #2
0
def total_portfolio(portfolio: pd.DataFrame) -> pd.DataFrame:
    symbols = [c for c in portfolio.columns if c == c.upper()]
    portfolio["_total"] = 0.0
    for symbol in symbols:
        price = quotes.get_price(symbol, portfolio.index)
        portfolio[f"{symbol}_value"] = portfolio[symbol] * price
        portfolio["_total"] += portfolio[f"{symbol}_value"]
    return portfolio
Example #3
0
def record_inv_action(portfolio: pd.DataFrame,
                      action: pd.Series) -> pd.DataFrame:
    """Mark the results of an AceMoney investment transaction in a portfolio

    `portfolio`: pd.DataFrame
        Initialized as per `init_portfolio`
    `action`: pd.Series
        A row from the all-investment-transactions AceMoney export
    """
    port.init_symbol(portfolio, symbol=action['Symbol'])

    if not pd.isnull(action['Dividend']) and action['Dividend'] != 0:
        portfolio.loc[action.Date:,
                      f"{action.Symbol}_dist"] += action['Dividend']
        portfolio.loc[action.Date:, f"_total_dist"] += action.Dividend
    if not pd.isnull(action['Quantity']) and action['Quantity'] != 0:
        sign = -1 if action['Action'] in ['Sell', 'Remove Shares'] else 1
        portfolio.loc[action.Date:,
                      f"{action.Symbol}"] += sign * action['Quantity']
    if not pd.isnull(action['Total']) and action['Total'] != 0:
        sign = -1 if action['Action'] == 'Buy' else 1
        portfolio.loc[action['Date']:, "cash"] += sign * action['Total']
    if action['Action'] == 'Add Shares' and '__contribution__' in action[
            'Comment']:
        price = quotes.get_price(action.Symbol, [action.Date]).values[0]
        log.debug(f"Contribution of {action.Quantity} shares of "
                  f"{action.Symbol} @ {price} per share.")
        portfolio.loc[action.Date:,
                      'contributions'] += price * action['Quantity']
    if action['Action'] == 'Add Shares' and '__dividend__' in action['Comment']:
        value = (quotes.get_price(action.Symbol, [action.Date]).values[0] *
                 action['Quantity'])
        log.debug(f"Dividend of {action.Quantity} shares of {action.Symbol} "
                  f"of {action.Date} is ${value}.")
        portfolio.loc[action.Date:, f"{action.Symbol}_dist"] += value
        portfolio.loc[action.Date:, f"_total_dist"] += value

    return portfolio
Example #4
0
def record_inv_action(portfolio: pd.DataFrame,
                      action: pd.Series) -> pd.DataFrame:
    """Mark the results of an AceMoney investment transaction in a portfolio

    `portfolio`: pd.DataFrame
        Initialized as per `init_portfolio`
    `action`: pd.Series
        A row from the all-investment-transactions AceMoney export
    """
    port.init_symbol(portfolio, symbol=action["Symbol"])

    if not pd.isnull(action["Dividend"]) and action["Dividend"] != 0:
        portfolio.loc[action.Date:,
                      f"{action.Symbol}_dist"] += action["Dividend"]
        portfolio.loc[action.Date:, f"_total_dist"] += action.Dividend
    if not pd.isnull(action["Quantity"]) and action["Quantity"] != 0:
        sign = -1 if action["Action"] in ["Sell", "Remove Shares"] else 1
        portfolio.loc[action.Date:,
                      f"{action.Symbol}"] += sign * action["Quantity"]
    if not pd.isnull(action["Total"]) and action["Total"] != 0:
        sign = -1 if action["Action"] == "Buy" else 1
        portfolio.loc[action["Date"]:, "cash"] += sign * action["Total"]
    if action["Action"] == "Add Shares" and "__contribution__" in action[
            "Comment"]:
        price = quotes.get_price(action.Symbol, [action.Date]).values[0]
        log.debug(f"Contribution of {action.Quantity} shares of "
                  f"{action.Symbol} @ {price} per share.")
        portfolio.loc[action.Date:,
                      "contributions"] += price * action["Quantity"]
    if action["Action"] == "Add Shares" and "__dividend__" in action["Comment"]:
        value = (quotes.get_price(action.Symbol, [action.Date]).values[0] *
                 action["Quantity"])
        log.debug(f"Dividend of {action.Quantity} shares of {action.Symbol} "
                  f"of {action.Date} is ${value}.")
        portfolio.loc[action.Date:, f"{action.Symbol}_dist"] += value
        portfolio.loc[action.Date:, f"_total_dist"] += value

    return portfolio
Example #5
0
def add_sim_dividend(portfolio: pd.DataFrame, sim_symbol: str) -> pd.DataFrame:
    """Look at a portfolio and add the dividends that you would have gotten
    from a particular security. For simulated portfolios.
    """
    div = quotes.get_dividend(sim_symbol, portfolio.index)
    for date, amount in div.iteritems():
        if date in portfolio.index:
            price = quotes.get_price(sim_symbol, [date]).values[0]

            # Create a Series with 0s before the date, and the value of
            # the distribution at and after the date.
            value = portfolio.loc[[date], sim_symbol] * amount
            value = value.reindex(portfolio.index, method="ffill").fillna(0)

            qty = value / price
            portfolio[f"{sim_symbol}_dist"] += value
            portfolio[sim_symbol] += qty
            portfolio["_total_dist"] += value

    return portfolio
Example #6
0
def _include_reinvest_dividend(
    buy_transactions: pd.DataFrame, dates: pd.DatetimeIndex
) -> pd.DataFrame:
    """Include "Reinvest Dividend" transactions in a buy transactions DataFrame

    This assumes that the `buy_transactions` input is a
    single security in a single account.
    """
    trans = buy_transactions.set_index("Date").sort_index(ascending=True)
    assert len(buy_transactions["Symbol"].unique()) == 1
    assert len(buy_transactions["Account"].unique()) == 1
    symbol = buy_transactions["Symbol"].unique()[0]
    div = quotes.get_dividend(symbol, dates).sort_index()
    prices = quotes.get_price(symbol, div.index)

    div_trans = pd.DataFrame(columns=TRANS_HEADER)  # Empty DF for appending
    for date, div_value in div.iteritems():
        n_shares = trans.loc[:date, "Quantity"].sum() + div_trans["Quantity"].sum()
        div_trans_row = pd.DataFrame(
            {
                "Date": date,
                "Action": "Reinvest Dividend",
                "Symbol": symbol,
                "Commission": 0.0,
                "Total": 0.0,
                "Comment": "",
                "Account": trans["Account"].unique()[0],
                "Dividend": round(n_shares * div_value, 2),
                "Price": prices.loc[date],
                "Quantity": round((n_shares * div_value) / prices.loc[date], 4),
            },
            columns=TRANS_HEADER,
            index=[len(div_trans)],
        )
        div_trans = div_trans.append(div_trans_row)
    assert len(div_trans) == len(div) == len(prices)
    return (
        buy_transactions.append(div_trans)
        .sort_values("Date", ascending=True)
        .reset_index(drop=True)
    )
Example #7
0
def _create_single_buy_transactions(dates: pd.DatetimeIndex,
                                    contribution: float, symbol: str,
                                    account: str) -> pd.DataFrame:
    """Create buy transactions in a format matching
    AceMoney's investment transactions
    """
    prices = quotes.get_price(symbol, dates)
    trans = pd.DataFrame(
        {
            "Date": dates,
            "Action": "Buy",
            "Symbol": symbol,
            "Account": account,
            "Dividend": 0.,
            "Price": prices,
            "Quantity": np.round(contribution / prices, 4),
            "Commission": 0.,
            "Total": contribution,
            "Comment": ""
        },
        columns=TRANS_HEADER)
    return trans.reset_index(drop=True)