diff --git a/app.py b/app.py index fb41ee4..f4cfad2 100644 --- a/app.py +++ b/app.py @@ -893,6 +893,68 @@ with tab_fundlab: "funds with 4/5 (merger arb, market-neutral, " "securitized credit) that still earned their 5y alpha.") + # ---- tax location: taxable account vs IRA ------------------------- + with st.expander( + "Tax location - which account (taxable vs IRA) for each fund"): + _TP = _dc.RESULTS.parent / "taxplan_results.json" + if not _TP.exists(): + st.info("No tax-location screen on file yet " + "(run `python -m fundlab.taxplan`).") + else: + _tp = json.loads(_TP.read_text()) + st.caption( + "Where each fund's distributions should live, given the " + "current LTCG rate < future ordinary rate. Basis: N-PORT " + "holdings (16 shortlist + 22 cross-checked) or return-" + "sleeve proxy (250 candidates). 'score' = estimated share " + "of distributions that are tax-favorable (qualified " + "dividends + LTCG + tax-exempt). MIXED funds: pull the " + "last 1099-DIV - it is the final arbiter.") + + def _tp_table(funds: dict) -> pd.DataFrame: + rows = [] + for s, r in sorted(funds.items()): + rows.append({ + "fund": s, + "name": r["name"][:44], + "location": r["location"], + "score": r["score"], + "basis": r["basis"], + "notes": r["notes"][:120], + }) + order = {"TAXABLE": 0, "TAXABLE (munis)": 1, + "MIXED (check 1099)": 2, "IRA": 3, + "FLEXIBLE (cash)": 4, "NO DATA": 9} + df = pd.DataFrame(rows) + df["_o"] = df["location"].map( + lambda x: order.get(x, 5)) + df = df.sort_values(["_o", "score"], + ascending=[True, False]) + return df.drop(columns="_o") + + st.markdown("**16-fund shortlist**") + st.dataframe(_tp_table(_tp["shortlist"]), width="stretch") + st.markdown("**22 cross-checked**") + st.dataframe(_tp_table(_tp["xcheck"]), width="stretch") + _sel = st.selectbox( + "Candidates (250)", + ["All locations", "TAXABLE", "TAXABLE (munis)", + "MIXED (check 1099)", "IRA", "FLEXIBLE (cash)"], + key="_tp_loc") + _c = _tp["candidates"] + if _sel != "All locations": + _c = {s: r for s, r in _c.items() + if r["location"] == _sel} + st.dataframe(_tp_table(_c), width="stretch") + st.caption( + "Reading the table: TAXABLE = income is mostly qualified " + "dividends/LTCG (or tax-exempt) - the taxable account's " + "low LTCG rate is the benefit. IRA = ordinary interest / " + "STCG / non-qualified - deferral is the benefit. FLEXIBLE " + "= cash, no placement value either way. Note the merger-" + "arb trap: equity-looking books that distribute mostly " + "SHORT-TERM gains (HMEZX, MERVX) belong in the IRA.") + _f = _FUNDS.get(_fl_pick, {}) _man = _MAN.get(_fl_pick, {}) st.subheader(f"{_f.get('name', _fl_pick)} ยท {_fl_pick.upper()}") diff --git a/fundlab/RESEARCH.md b/fundlab/RESEARCH.md index fc02117..46daf3c 100644 --- a/fundlab/RESEARCH.md +++ b/fundlab/RESEARCH.md @@ -130,6 +130,54 @@ not a gate. 4. CEF universe (485/N-2 filers) - separate pass; CEFs have premium/discount dynamics the NAV screen can't see. +### Tax-location plan (fundlab/taxplan.py, 2026-08-27) +User's premise: current LTCG rate < future ordinary rate, so a fund's +account placement follows the CHARACTER of its distributions: +- qualified dividends + LTCG -> TAXABLE (low LTCG rate is the benefit) +- tax-exempt (munis) -> TAXABLE (wasted in an IRA) +- ordinary interest / STCG / REIT / K-1 -> IRA (deferral is the benefit) +- cash -> FLEXIBLE + +No 1099-DIV characterizations on file for 2,400 funds, so this is a +STRUCTURAL estimate. `score` = estimated share of distributions that +are tax-favorable (QD + LTCG + tax-exempt), from three tiers of ground +truth: +1. 16-fund shortlist -> nport_cache buckets (keyword) +2. 22 cross-checked -> xcheck_report buckets (SEC assetCat/issuerCat) +3. 250 candidates -> factor sleeve loadings (return proxy) +Fallback: if the keyword parser left >50% of a book unclassified +("Other"), use the return sleeves. Manual override for the Leuthold +wrappers (no return history). + +Location bands: score >= 0.60 TAXABLE, <= 0.35 IRA, else MIXED (check +the 1099). Name-based overrides: muni name -> TAXABLE (munis), money +market -> FLEXIBLE, and strategy caps (merger-arb/event-driven capped +at 0.35 because gains are mostly SHORT-TERM; market-neutral 0.35; +hedge 0.50; style-premia 0.50). + +KEY FINDINGS: +- 16 shortlist: TAXABLE = ATESX, JLPSX, LAMHX, LCORX, LCRIX (all + equity). IRA = ATRFX, COSIX, CVSIX, PMORX, SVARX, EAGMX/EGRSX + (macro/market-neutral/income). MIXED (check 1099) = MBXIX (hedge), + QSPNX (AQR factor), PMAIX/PMFKX (multi-asset income, same fund two + classes). +- 22 cross-checked: the four MUNIS (BTMIX, FHMIX, HICOX, USMSX) -> + TAXABLE, everything else IRA except the macro FOFs (EGRIX MIXED, + ETSIX IRA) and DMSZX (MIXED, 38% equity + 36% CLO). +- MERGER-ARB TRAP: HMEZX + MERVX hold ~75% equity (looks tax- + efficient) but their distributions are mostly SHORT-TERM gains + (deals close <1 yr) -> IRA, not taxable. This is the one place the + equity-looking book is misleading. +- 250 candidates: 109 munis (TAXABLE), 127 IRA (bonds/credit/HY/loans), + 6 equity TAXABLE (PHSTX, ANNPX, FKUTX, ALGRX, EBSAX, MCOAX), 7 + MIXED, 1 FLEXIBLE. The candidate pool is credit-heavy, so most are + IRA. + +App: Fund Lab -> "Tax location" expander (shortlist + cross-checked ++ 250-candidate tables, location filter). Output: +fundlab/taxplan_results.json. The last 1099-DIV is the final arbiter +for any MIXED fund. + ### Drawdown-resilience screen (fundlab/drawdown.py, 2026-08-27) Scenarios DETECTED from IVV (S&P 500) - one worst peak->trough per calendar year since 2022, min depth 8% (2024's Aug-5 dip and 2023's diff --git a/fundlab/taxplan.py b/fundlab/taxplan.py new file mode 100644 index 0000000..87ea9cf --- /dev/null +++ b/fundlab/taxplan.py @@ -0,0 +1,396 @@ +"""Tax-location plan: which funds belong in the TAXABLE account vs an IRA. + +The user's premise: current LTCG rate < ordinary-income rate expected +after retirement. So a fund's right home depends on the CHARACTER of +its distributions: + + qualified dividends + LTCG -> TAXABLE (the LTCG rate is the benefit) + tax-exempt interest (munis) -> TAXABLE (wasted in an IRA) + ordinary interest / STCG / + non-qualified (REIT, K-1) -> IRA (deferring it is the benefit) + cash -> FLEXIBLE (no character to place) + +We don't have 1099-DIV characterizations on file for 2,400 funds, so +this is a STRUCTURAL estimate from what the fund actually holds: + + 1. 16-fund shortlist -> nport_cache/*.json buckets (keyword-based) + 2. 22 cross-checked -> xcheck_report.json buckets (SEC + assetCat/issuerCat codes, precise) + 3. 250 candidates -> factor_results.json sleeve loadings (proxy: + a fund that trades like 90% Treasuries earns + ~90% ordinary income) + +plus name-based strategy overrides (merger arb gains are mostly +SHORT-TERM, munis are tax-exempt, FOFs are pass-through, ...). + +The output says where a fund's income character points; the 1099-DIV +for the most recent year is the final arbiter for MIXED funds. + +Run: python -m fundlab.taxplan +Output: fundlab/taxplan_results.json +""" +from __future__ import annotations + +import json +import re +from pathlib import Path + +HERE = Path(__file__).parent +EXTRA_BETAS = HERE / "universe_cache" / "betas_extra.json" +SHORTLIST = HERE / "decompose_results.json" +XCHECK = HERE / "xcheck_report.json" +FACTORS = HERE / "factor_results.json" +RESULTS = HERE / "taxplan_results.json" + +# ------------------------------------------------------------------------ +# bucket -> (fraction of distributions that are tax-favorable, character) +# tax-favorable = qualified dividends + LTCG + tax-exempt interest. +# A None fraction means "pass-through / unclassified - unknown". +# ------------------------------------------------------------------------ +BUCKET_FRAC: dict[str, tuple[float | None, str]] = { + # equity: qualified dividends + LTCG + "Equity (US)": (1.0, "qualified div + LTCG"), + "Equity (intl)": (1.0, "qualified div + LTCG"), + "Equity (common)": (1.0, "qualified div + LTCG"), + "EC": (1.0, "qualified div + LTCG"), + # tax-exempt + "Municipal bond": (1.0, "tax-exempt interest"), + # mostly non-qualified + "Real estate": (0.15, "REIT income (mostly ordinary)"), + "RE": (0.15, "REIT income (mostly ordinary)"), + "Preferred stock": (0.15, "preferred div (mostly ordinary)"), + "EP": (0.15, "preferred div (mostly ordinary)"), + # commodities: 60/40 LTCG if section 1256 futures + "Commodities": (0.60, "commodity (60/40 if 1256)"), + "Commodity": (0.60, "commodity (60/40 if 1256)"), + "COMM": (0.60, "commodity (60/40 if 1256)"), + # derivatives / structured + "Futures": (0.40, "derivatives (mixed)"), + "Derivative / hedge": (0.40, "derivatives (mixed)"), + "Structured note": (0.30, "structured (mixed)"), + "SN": (0.30, "structured (mixed)"), + # debt: ordinary interest + "US Treasury": (0.0, "ordinary interest"), + "US agency": (0.0, "ordinary interest"), + "US GSE (Fed/FF)": (0.0, "ordinary interest"), + "Corporate bond": (0.05, "ordinary interest"), + "Debt": (0.05, "ordinary interest"), + "Foreign sovereign": (0.0, "ordinary interest"), + "High yield": (0.0, "ordinary interest"), + "Loan (leveraged/private credit)": (0.0, "ordinary / K-1"), + "LON": (0.0, "ordinary / K-1"), + "CLO (collateralized debt)": (0.0, "ordinary interest"), + "ABS-CBDO": (0.0, "ordinary interest"), + "ABS-O": (0.0, "ordinary interest"), + "ABS-MBS": (0.0, "ordinary interest"), + "ABS-APCP": (0.0, "ordinary interest"), + "ABS other (CLO/CMBS/AB)": (0.0, "ordinary interest"), + "ABS auto/personal loan": (0.0, "ordinary interest"), + "MBS (mortgage-backed)": (0.0, "ordinary interest"), + "Agency MBS": (0.0, "ordinary interest"), + "DBT": (0.05, "debt (ordinary)"), + # cash: ordinary, no placement value + "Cash & T-bills": (0.0, "cash (ordinary)"), + "Cash/MMF (short-term)": (0.0, "cash (ordinary)"), + "STIV": (0.0, "cash (ordinary)"), + "Repurchase agreement": (0.0, "ordinary interest"), + "RA": (0.0, "ordinary interest"), + # pass-through / unclassified + "Fund holdings": (None, "FOF - pass-through"), + "Fund/ETF holdings": (None, "FOF - pass-through"), + "PF": (None, "private fund - pass-through"), + "RF": (None, "fund - pass-through"), + # nport.py lump: corporates + munis together + "IG credit / munis": (0.45, "IG credit + munis (mixed)"), + "Other": (None, "unclassified"), +} + +# ------------------------------------------------------------------------ +# sleeve -> same fraction (proxy for the candidate set, no N-PORT on +# file). Equity sleeves = qualified div + LTCG; bond sleeves = ordinary; +# commodity/CTA sleeves = 60/40 if section 1256. +# ------------------------------------------------------------------------ +SLEEVE_FRAC: dict[str, float] = { + "qqq": 1.0, "ivv": 1.0, "iwm": 1.0, "vea": 1.0, "efa": 1.0, + "vwo": 1.0, "vug": 1.0, "vtv": 1.0, + "xlk": 1.0, "xlf": 1.0, "xle": 0.90, "xlv": 0.95, "xlp": 1.0, + "xlu": 1.0, "xly": 0.95, "xlb": 0.95, + "vnq": 0.15, + "bil": 0.0, "shv": 0.0, "shy": 0.0, "ief": 0.0, "tlt": 0.0, + "agg": 0.0, "lqd": 0.05, "hyg": 0.0, "pff": 0.15, "emb": 0.0, + "tip": 0.10, "vweax": 0.0, "vmbix": 0.0, "finux": 0.0, + "fxe": 0.0, "fxy": 0.0, "vblix": 0.0, + "djp": 0.60, "gsg": 0.60, "gld": 0.60, "dbb": 0.60, "dbmf": 0.60, +} + +# name-based strategy overrides: (regex, action, note) +# action: "cap" -> score capped at the given number; None -> note only +OVERRIDES: list[tuple[re.Pattern, float | None, str]] = [ + (re.compile(r"\bmerger\b", re.I), 0.35, + "merger arb: gains are largely SHORT-TERM (deals close <1 yr) - " + "1099 will show STCG despite the equity book"), + (re.compile(r"style premia|style and valuation", re.I), 0.50, + "long/short factor strategy: gains mix STCG/LTCG - check 1099"), + (re.compile(r"event[- ]?driven", re.I), 0.45, + "event-driven: gains mostly short-term"), + (re.compile(r"market neutral", re.I), 0.35, + "market-neutral: gains from short-dated option/systematic trades " + "- often STCG"), + (re.compile(r"global macro", re.I), None, + "macro: 60% LTCG if section-1256 futures; OTC swaps -> STCG - " + "check 1099"), + (re.compile(r"managed futures|\bCTA\b|systematic", re.I), None, + "CTA/systematic: 60/40 if section-1256 regulated futures"), + (re.compile(r"hedge (fund|strategy|strategies)", re.I), 0.50, + "hedge fund: gains often short-term - check 1099"), + (re.compile(r"absolute return", re.I), None, + "absolute-return: character varies - check 1099"), + (re.compile(r"multi[- ]?asset", re.I), None, + "multi-asset: mixed qualified/LTCG + ordinary interest - " + "check 1099"), + (re.compile(r"fund of funds", re.I), None, + "FOF: pass-through of underlying character - check 1099"), +] + +MUNI_RX = re.compile(r"municipal|tax[- ]?exempt|munis\b", re.I) +MMF_RX = re.compile(r"money market", re.I) + +TAXABLE_AT = 0.60 # score >= this -> taxable +IRA_AT = 0.35 # score <= this -> IRA +FOF_UNKNOWN_AT = 0.40 # >40% pass-through -> can't clear either bar + + +def bucket_score(buckets: list[dict]) -> tuple[float, float, list[str]]: + """(score, unknown_frac, unknown_names) from N-PORT-style buckets.""" + score = 0.0 + known = 0.0 + unknown = 0.0 + unk_names: list[str] = [] + for b in buckets: + pct = (b.get("pct") or 0.0) / 100.0 + frac, _ = BUCKET_FRAC.get(b["name"], (None, b["name"])) + if frac is None: + unknown += pct + if pct >= 0.05: + unk_names.append(f"{b['name']} {pct*100:.0f}%") + else: + score += frac * pct + known += pct + if known > 0: + score /= known # renormalize over classified assets + return score, unknown, unk_names + + +def sleeve_score(betas: dict) -> float | None: + """Score from sleeve loadings (proxy when no N-PORT is on file).""" + num = 0.0 + den = 0.0 + for s, b in (betas or {}).items(): + if not isinstance(b, (int, float)) or b <= 0: + continue + f = SLEEVE_FRAC.get(s) + if f is None: + continue + num += f * b + den += b + if den < 0.05: + return None + return num / den + + +def classify(name: str, + buckets: list[dict] | None = None, + betas: dict | None = None) -> dict: + """Location decision for one fund. Returns a result dict.""" + notes: list[str] = [] + unknown = 0.0 + used_sleeves = False + if buckets: + score, unknown, unk_names = bucket_score(buckets) + basis = "N-PORT" + if unk_names: + notes.append("unclassified: " + ", ".join(unk_names)) + # keyword parser left most of the book unclassified ("Other") - + # trust the return sleeves instead + if unknown > 0.5 and betas: + s2 = sleeve_score(betas) + if s2 is not None: + score, basis, used_sleeves = s2, "N-PORT+sleeves", True + notes.append("holdings mostly unclassified - used " + "return sleeves") + else: + score = sleeve_score(betas) + basis = "sleeves" + if score is None: + score = 0.5 + notes.append("no clean sleeve match - treat as mixed") + score = min(max(score, 0.0), 1.0) + + is_muni = bool(MUNI_RX.search(name or "")) + is_mmf = bool(MMF_RX.search(name or "")) + if is_muni: + score = 1.0 # all distributions are tax-exempt = tax-favorable + + # strategy overrides + cap: float | None = None + for rx, act, note in OVERRIDES: + if rx.search(name or ""): + notes.append(note) + if act is not None: + cap = min(cap, act) if cap is not None else act + if cap is not None: + score = min(score, cap) + + # location + if is_muni: + loc = "TAXABLE (munis)" + notes.append("tax-exempt interest - keep OUT of the IRA") + elif is_mmf: + loc = "FLEXIBLE (cash)" + notes.append("ordinary interest, no placement value either way") + elif not used_sleeves and unknown > FOF_UNKNOWN_AT: + loc = "MIXED (check 1099)" + notes.append(f"{unknown*100:.0f}% pass-through/unclassified - " + "character is the underlying funds'") + elif score >= TAXABLE_AT: + loc = "TAXABLE" + elif score <= IRA_AT: + loc = "IRA" + else: + loc = "MIXED (check 1099)" + return {"name": name, "basis": basis, "score": round(score, 2), + "unknown": round(unknown, 2), "location": loc, + "notes": "; ".join(dict.fromkeys(notes))} + + +# Manual overrides for funds the structural data can't resolve - each +# with the reason it's needed. (LCORX/LCRIX are new share classes with +# no return history; the NPORT shows they are a 91.7% wrapper around the +# Leuthold Core ETF, a US equity fund.) +MANUAL: dict[str, tuple[str, str]] = { + "LCORX": ("TAXABLE", "wrapper: 91.7% Leuthold Core ETF (US equity) " + "+ 8% money market"), + "LCRIX": ("TAXABLE", "wrapper: 91.7% Leuthold Core ETF (US equity) " + "+ 8% money market"), +} + + +def finalize(sym: str, r: dict) -> dict: + if sym.upper() in MANUAL: + loc, note = MANUAL[sym.upper()] + r["location"] = loc + r["score"] = 1.0 if loc == "TAXABLE" else 0.0 + r["basis"] = (r["basis"] + "+manual").lstrip("+") + r["notes"] = (note + "; " + r["notes"]).strip("; ") + return r + + +# ------------------------------------------------------------------------ +def run() -> dict: + # sleeve loadings as a fallback for groups whose N-PORT parse left + # the book mostly unclassified. The 16-fund shortlist was never in + # the 2,384 screen, so compute + cache betas for those on demand. + fac = json.loads(FACTORS.read_text()) + extra = (json.loads(EXTRA_BETAS.read_text()) + if EXTRA_BETAS.exists() else {}) + + def betas_of(sym: str) -> dict: + v = fac.get(sym.lower()) or fac.get(sym.upper()) or {} + b = (v.get("full") or {}).get("betas") + if b: + return b + key = sym.lower() + if key in extra: + return extra[key] + from fundlab import factors + r = factors.factor_screen(sym) + if r and r.get("full"): + extra[key] = r["full"]["betas"] + EXTRA_BETAS.parent.mkdir(exist_ok=True) + EXTRA_BETAS.write_text(json.dumps(extra, indent=1)) + return extra.get(key) or {} + + # 16-fund shortlist (N-PORT keyword buckets + names from funds.json) + funds = json.loads((HERE.parent / "funds.json").read_text()) + shortlist: dict = {} + dr = json.loads(SHORTLIST.read_text()) + for sym in dr: + snap = json.loads((HERE / "nport_cache" / f"{sym}.json").read_text()) + name = (funds.get(sym.lower()) or {}).get("name") or sym.upper() + r = classify(name, buckets=snap.get("buckets") or None, + betas=betas_of(sym)) + r["as_of"] = snap.get("as_of", "") + shortlist[sym.upper()] = finalize(sym, r) + + # 22 cross-checked (precise code-based buckets) + xcheck: dict = {} + xc = json.loads(XCHECK.read_text()) + for sym, v in xc.items(): + r = classify(v.get("name") or sym.upper(), + buckets=v.get("buckets") or None, + betas=betas_of(sym)) + r["as_of"] = v.get("as_of", "") + xcheck[sym.upper()] = finalize(sym, r) + + # 250 candidates (sleeve loadings + name) + cands: dict = {} + for sym, v in fac.items(): + if not (v.get("verdict") or "").startswith("CANDIDATE"): + continue + betas = (v.get("full") or {}).get("betas") or {} + cands[sym.upper()] = finalize(sym, classify(v.get("name") or "", + betas=betas)) + + res = {"shortlist": shortlist, "xcheck": xcheck, "candidates": cands} + RESULTS.write_text(json.dumps(res, indent=1)) + _print(res) + return res + + +def _print(res: dict) -> None: + from collections import Counter + + def row(s: str, r: dict) -> str: + return (f" {s:<7} {r['location']:<20} {r['score']:<5.2f} " + f"{r['basis']:<14} {r['name'][:34]:<34} {r['notes'][:64]}") + + hdr = (f" {'fund':<7} {'location':<20} score basis " + f"{'name':<34} notes") + for key, title in (("shortlist", "16-fund shortlist"), + ("xcheck", "22 cross-checked")): + funds = res[key] + print(f"\n== {title} ({len(funds)}) ==") + print(hdr) + for s, r in sorted(funds.items()): + print(row(s, r)) + + c = res["candidates"] + locs = Counter(r["location"] for r in c.values()) + print(f"\n== 250 candidates: {dict(locs)} ==") + sections = [ + ("TAXABLE - equity character (by score)", + lambda r: r["location"] == "TAXABLE", -18, 18), + ("TAXABLE - munis (sample)", + lambda r: r["location"] == "TAXABLE (munis)", 0, 12), + ("MIXED - check the 1099 (by score)", + lambda r: r["location"] == "MIXED (check 1099)", -12, 12), + ("IRA - most ordinary income (by score)", + lambda r: r["location"] == "IRA", 12, 12), + ("FLEXIBLE - cash", + lambda r: r["location"] == "FLEXIBLE (cash)", 0, 8), + ] + for title, pick, sortkey, limit in sections: + sel = [(s, r) for s, r in c.items() if pick(r)] + if sortkey: + sel.sort(key=lambda kv: (sortkey * kv[1]["score"], kv[0])) + else: + sel.sort(key=lambda kv: kv[0]) + print(f"\n -- {title} ({len(sel)})") + print(hdr) + for s, r in sel[:limit]: + print(row(s, r)) + + + +if __name__ == "__main__": + run() diff --git a/fundlab/taxplan_results.json b/fundlab/taxplan_results.json new file mode 100644 index 0000000..66894c2 --- /dev/null +++ b/fundlab/taxplan_results.json @@ -0,0 +1,2350 @@ +{ + "shortlist": { + "ATESX": { + "name": "Anchor Risk Mgd Equity Strategies Instl", + "basis": "N-PORT", + "score": 1.0, + "unknown": 0.01, + "location": "TAXABLE", + "notes": "", + "as_of": "May 31, 2026" + }, + "ATRFX": { + "name": "Catalyst Systematic Alpha I", + "basis": "N-PORT", + "score": 0.16, + "unknown": 0.23, + "location": "IRA", + "notes": "unclassified: US govt 18%; CTA/systematic: 60/40 if section-1256 regulated futures", + "as_of": "March 31, 2026" + }, + "CVSIX": { + "name": "Calamos Market Neutral Income A", + "basis": "sleeves", + "score": 0.35, + "unknown": 0.0, + "location": "IRA", + "notes": "market-neutral: gains from short-dated option/systematic trades - often STCG", + "as_of": "January 31, 2026" + }, + "JLPSX": { + "name": "JPMorgan US Large Cap Core Plus I", + "basis": "N-PORT+sleeves", + "score": 0.91, + "unknown": 1.0, + "location": "TAXABLE", + "notes": "unclassified: Other 99%; holdings mostly unclassified - used return sleeves", + "as_of": "March 31, 2026" + }, + "PMAIX": { + "name": "Victory Pioneer Multi-Asset Income A", + "basis": "N-PORT+sleeves", + "score": 0.44, + "unknown": 0.82, + "location": "MIXED (check 1099)", + "notes": "unclassified: Other 59%, Fund holdings 21%; holdings mostly unclassified - used return sleeves; multi-asset: mixed qualified/LTCG + ordinary interest - check 1099", + "as_of": "December 31, 2025" + }, + "PMORX": { + "name": "Putnam Mortgage Opportunities A", + "basis": "sleeves", + "score": 0.25, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "February 28, 2026" + }, + "QSPNX": { + "name": "AQR Style Premia Alternative N", + "basis": "N-PORT+sleeves", + "score": 0.5, + "unknown": 1.0, + "location": "MIXED (check 1099)", + "notes": "unclassified: Other 100%; holdings mostly unclassified - used return sleeves; long/short factor strategy: gains mix STCG/LTCG - check 1099", + "as_of": "March 31, 2026" + }, + "SVARX": { + "name": "Spectrum Low Volatility Investor", + "basis": "N-PORT+sleeves", + "score": 0.23, + "unknown": 0.5, + "location": "IRA", + "notes": "unclassified: Fund holdings 40%, US govt 10%; holdings mostly unclassified - used return sleeves", + "as_of": "June 30, 2026" + }, + "COSIX": { + "name": "Columbia Strategic Income A", + "basis": "N-PORT", + "score": 0.0, + "unknown": 0.3, + "location": "IRA", + "notes": "unclassified: Other 30%", + "as_of": "May 31, 2026" + }, + "MBXIX": { + "name": "Catalyst/Millburn Hedge Strategy I", + "basis": "N-PORT+sleeves", + "score": 0.5, + "unknown": 1.0, + "location": "MIXED (check 1099)", + "notes": "unclassified: Fund holdings 77%, US govt 23%; holdings mostly unclassified - used return sleeves; hedge fund: gains often short-term - check 1099", + "as_of": "September 30, 2024" + }, + "EAGMX": { + "name": "Eaton Vance Glbl Macr Absolute Return A", + "basis": "N-PORT+sleeves", + "score": 0.1, + "unknown": 0.73, + "location": "IRA", + "notes": "unclassified: Other 69%; holdings mostly unclassified - used return sleeves; absolute-return: character varies - check 1099", + "as_of": "July 31, 2025" + }, + "LCORX": { + "name": "Leuthold Core Investment Retail", + "basis": "N-PORT+manual", + "score": 1.0, + "unknown": 1.0, + "location": "TAXABLE", + "notes": "wrapper: 91.7% Leuthold Core ETF (US equity) + 8% money market; unclassified: Fund holdings 100%; 100% pass-through/unclassified - character is the underlying funds'", + "as_of": "December 31, 2025" + }, + "LAMHX": { + "name": "Lord Abbett Dividend Growth R6", + "basis": "N-PORT+sleeves", + "score": 0.92, + "unknown": 1.0, + "location": "TAXABLE", + "notes": "unclassified: Other 100%; holdings mostly unclassified - used return sleeves", + "as_of": "February 28, 2026" + }, + "PMFKX": { + "name": "Victory Pioneer Multi-Asset Income R6", + "basis": "N-PORT+sleeves", + "score": 0.44, + "unknown": 0.82, + "location": "MIXED (check 1099)", + "notes": "unclassified: Other 59%, Fund holdings 21%; holdings mostly unclassified - used return sleeves; multi-asset: mixed qualified/LTCG + ordinary interest - check 1099", + "as_of": "December 31, 2025" + }, + "LCRIX": { + "name": "Leuthold Core Investment Institutional", + "basis": "N-PORT+manual", + "score": 1.0, + "unknown": 1.0, + "location": "TAXABLE", + "notes": "wrapper: 91.7% Leuthold Core ETF (US equity) + 8% money market; unclassified: Fund holdings 100%; 100% pass-through/unclassified - character is the underlying funds'", + "as_of": "December 31, 2025" + }, + "EGRSX": { + "name": "Eaton Vance Glbl Macro Abs Ret Advtg R6", + "basis": "N-PORT+sleeves", + "score": 0.35, + "unknown": 0.73, + "location": "IRA", + "notes": "unclassified: Other 69%; holdings mostly unclassified - used return sleeves", + "as_of": "July 31, 2025" + } + }, + "xcheck": { + "SCFZX": { + "name": "PGIM Securitized Credit Fund", + "basis": "N-PORT", + "score": 0.0, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-08-26" + }, + "HMEZX": { + "name": "NexPoint Merger Arbitrage Fund", + "basis": "N-PORT", + "score": 0.35, + "unknown": 0.0, + "location": "IRA", + "notes": "merger arb: gains are largely SHORT-TERM (deals close <1 yr) - 1099 will show STCG despite the equity book", + "as_of": "2026-06-01" + }, + "COIAX": { + "name": "SIMT Conservative Income Fund", + "basis": "N-PORT", + "score": 0.0, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-05-29" + }, + "WMNUX": { + "name": "Westwood Alternative Income Fund", + "basis": "N-PORT", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-06-25" + }, + "FHCOX": { + "name": "Federated Hermes Conservative Microshort Fund", + "basis": "N-PORT", + "score": 0.02, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-07-27" + }, + "RCTIX": { + "name": "River Canyon Total Return Bond Fund", + "basis": "N-PORT", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-05-29" + }, + "EGRIX": { + "name": "Eaton Vance Global Macro Absolute Return Advantage Fund", + "basis": "N-PORT+sleeves", + "score": 0.35, + "unknown": 1.0, + "location": "MIXED (check 1099)", + "notes": "unclassified: Fund/ETF holdings 100%; holdings mostly unclassified - used return sleeves; macro: 60% LTCG if section-1256 futures; OTC swaps -> STCG - check 1099; absolute-return: character varies - check 1099", + "as_of": "2026-06-24" + }, + "ETSIX": { + "name": "Eaton Vance Strategic Income Fund", + "basis": "N-PORT+sleeves", + "score": 0.13, + "unknown": 1.0, + "location": "IRA", + "notes": "unclassified: Fund/ETF holdings 100%; holdings mostly unclassified - used return sleeves", + "as_of": "2026-06-24" + }, + "AFLIX": { + "name": "Anfield Universal Fixed Income Fund", + "basis": "N-PORT", + "score": 0.03, + "unknown": 0.03, + "location": "IRA", + "notes": "", + "as_of": "2026-06-29" + }, + "FHMIX": { + "name": "Federated Hermes Conservative Municipal Microshort Fund", + "basis": "N-PORT", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA", + "as_of": "2026-07-27" + }, + "HICOX": { + "name": "COLORADO BONDSHARES A TAX EXEMPT FUND", + "basis": "N-PORT", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA", + "as_of": "2026-05-29" + }, + "DULTX": { + "name": "Nomura Ultrashort Fund", + "basis": "N-PORT", + "score": 0.01, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-08-26" + }, + "USMSX": { + "name": "JPMorgan Ultra-Short Municipal Fund", + "basis": "N-PORT", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA", + "as_of": "2026-07-28" + }, + "BTMIX": { + "name": "Baird Short-Term Municipal Bond Fund", + "basis": "N-PORT", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA", + "as_of": "2026-08-14" + }, + "SAFEX": { + "name": "Ultra Short Government Fund", + "basis": "N-PORT", + "score": 0.0, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-05-28" + }, + "QCMMRX": { + "name": "Money Market Account", + "basis": "sleeves", + "score": 0.03, + "unknown": 0.0, + "location": "FLEXIBLE (cash)", + "notes": "ordinary interest, no placement value either way", + "as_of": "" + }, + "MERVX": { + "name": "The Merger Fund VL", + "basis": "N-PORT", + "score": 0.35, + "unknown": 0.0, + "location": "IRA", + "notes": "merger arb: gains are largely SHORT-TERM (deals close <1 yr) - 1099 will show STCG despite the equity book", + "as_of": "2026-05-29" + }, + "AGUAX": { + "name": "American Beacon Developing World Income Fund", + "basis": "N-PORT", + "score": 0.03, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-06-26" + }, + "DMSZX": { + "name": "Destinations Multi Strategy Alternatives Fund", + "basis": "N-PORT", + "score": 0.51, + "unknown": 0.25, + "location": "MIXED (check 1099)", + "notes": "unclassified: Fund/ETF holdings 25%", + "as_of": "2026-07-20" + }, + "ANGLX": { + "name": "Angel Oak Multi-Strategy Income Fund", + "basis": "N-PORT", + "score": 0.02, + "unknown": 0.02, + "location": "IRA", + "notes": "", + "as_of": "2026-06-26" + }, + "FEMDX": { + "name": "Franklin Emerging Market Debt Opportunities Fund", + "basis": "N-PORT", + "score": 0.01, + "unknown": 0.02, + "location": "IRA", + "notes": "", + "as_of": "2026-06-24" + }, + "LPXAX": { + "name": "Cohen & Steers Low Duration Preferred & Income Fund,Inc.", + "basis": "N-PORT", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "", + "as_of": "2026-06-24" + } + }, + "candidates": { + "ABHYX": { + "name": "HIGH-YIELD MUNICIPAL FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ACFIX": { + "name": "WATER ISLAND CREDIT OPPORTUNITIES FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ACITX": { + "name": "INFLATION-ADJUSTED BOND FUND", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ACTHX": { + "name": "INVESCO HIGH YIELD MUNICIPAL FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "AFLIX": { + "name": "Anfield Universal Fixed Income Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "AFTEX": { + "name": "TAX EXEMPT BOND FUND OF AMERICA", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "AGOVX": { + "name": "INVESCO Income Fund", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "AGUAX": { + "name": "American Beacon Developing World Income Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "AIDAX": { + "name": "Diversified Municipal Portfolio", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ALCAX": { + "name": "AB California Portfolio", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ALGRX": { + "name": "Alger Focus Equity Fund", + "basis": "sleeves", + "score": 0.62, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "" + }, + "ALNYX": { + "name": "AB New York Portfolio", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ALTHX": { + "name": "AB National Portfolio", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "AMAAX": { + "name": "AB Massachusetts Portfolio", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "AMHIX": { + "name": "AMERICAN HIGH-INCOME MUNICIPAL BOND FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ANGLX": { + "name": "Angel Oak Multi-Strategy Income Fund", + "basis": "sleeves", + "score": 0.15, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ANNPX": { + "name": "Virtus Convertible Fund", + "basis": "sleeves", + "score": 0.65, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "" + }, + "ASDVX": { + "name": "SHORT DURATION STRATEGIC INCOME FUND", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ATFAX": { + "name": "Invesco Limited Term Municipal Income", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "AVAAX": { + "name": "AB Virginia Portfolio", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "BCHYX": { + "name": "CALIFORNIA HIGH-YIELD MUNICIPAL FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "BCITX": { + "name": "CALIFORNIA INTERMEDIATE-TERM TAX-FREE BOND FUND", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "BILS": { + "name": "State Street(R) SPDR(R) Bloomberg 3-12 Month T-Bill ETF", + "basis": "sleeves", + "score": 0.0, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "BMBIX": { + "name": "Baird Quality Intermediate Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "BSNIX": { + "name": "Baird Strategic Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "BTMIX": { + "name": "Baird Short-Term Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "CBHCX": { + "name": "Victory Market Neutral Income Fund", + "basis": "sleeves", + "score": 0.35, + "unknown": 0.0, + "location": "IRA", + "notes": "market-neutral: gains from short-dated option/systematic trades - often STCG" + }, + "CFMOX": { + "name": "The Missouri Tax-Free Intermediate Bond Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "CFNLX": { + "name": "The National Tax-Free Intermediate Bond Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "CFRAX": { + "name": "Catalyst/CIFC Senior Secured Income Fund", + "basis": "sleeves", + "score": 0.16, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "COIAX": { + "name": "SIMT Conservative Income Fund", + "basis": "sleeves", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "COLTX": { + "name": "Columbia Total Return Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "CPXAX": { + "name": "Cohen & Steers Preferred Securities & Income Fund, Inc.", + "basis": "sleeves", + "score": 0.15, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "CSDAX": { + "name": "Calvert Short Duration Income Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "CSHIX": { + "name": "Credit Suisse Floating Rate High Income Fund", + "basis": "sleeves", + "score": 0.07, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "CXHYX": { + "name": "Nomura National High-Yield Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DEFFX": { + "name": "Nomura Tax-Free Minnesota Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DELIX": { + "name": "Nomura Tax-Free Pennsylvania Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DFLEX": { + "name": "DoubleLine Flexible Income Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DITEX": { + "name": "BNY Mellon Intermediate Municipal Bond Fund, Inc.", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DMSZX": { + "name": "Destinations Multi Strategy Alternatives Fund", + "basis": "sleeves", + "score": 0.14, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DMUSX": { + "name": "Nomura Tax-Free USA Intermediate Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DNMZX": { + "name": "PGIM NATIONAL MUNI FUND", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DPIAX": { + "name": "Destra Flaherty & Crumrine Preferred and Income Fund", + "basis": "sleeves", + "score": 0.15, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DRCAX": { + "name": "BNY Mellon California AMT-Free Municipal Bond Fund, Inc.", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DRNJX": { + "name": "BNY Mellon New Jersey Municipal Bond Fund, Inc.", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DSIBX": { + "name": "BNY Mellon Short Term Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DULTX": { + "name": "Nomura Ultrashort Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "DVMHX": { + "name": "Nomura Minnesota High-Yield Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "DVTAX": { + "name": "Nomura Tax-Free California Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "EABLX": { + "name": "Eaton Vance Floating-Rate Fund", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "EACAX": { + "name": "Eaton Vance California Municipal Opportunities Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "EANAX": { + "name": "Eaton Vance National Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "EASCX": { + "name": "Eaton Vance South Carolina Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "EBSAX": { + "name": "Campbell Systematic Macro Fund", + "basis": "sleeves", + "score": 0.62, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "CTA/systematic: 60/40 if section-1256 regulated futures" + }, + "EGRIX": { + "name": "Eaton Vance Global Macro Absolute Return Advantage Fund", + "basis": "sleeves", + "score": 0.35, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "macro: 60% LTCG if section-1256 futures; OTC swaps -> STCG - check 1099; absolute-return: character varies - check 1099" + }, + "ENIAX": { + "name": "SIIT Opportunistic Income Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ETAZX": { + "name": "Eaton Vance Arizona Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETGAX": { + "name": "Eaton Vance Georgia Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETHYX": { + "name": "Eaton Vance High Yield Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETMDX": { + "name": "Eaton Vance Maryland Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETMNX": { + "name": "Eaton Vance Minnesota Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETMOX": { + "name": "Eaton Vance Missouri Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETNCX": { + "name": "Eaton Vance North Carolina Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETNJX": { + "name": "Eaton Vance New Jersey Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETORX": { + "name": "Eaton Vance Oregon Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETPAX": { + "name": "Eaton Vance Pennsylvania Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ETSIX": { + "name": "Eaton Vance Strategic Income Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ETVAX": { + "name": "Eaton Vance Virginia Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "EVFAX": { + "name": "Eaton Vance Floating-Rate Advantage Fund", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "EXMAX": { + "name": "Eaton Vance Short Duration Municipal Opportunities Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "EXNAX": { + "name": "Eaton Vance National Limited Maturity Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FAFRX": { + "name": "FRANKLIN FLOATING RATE DAILY ACCESS FUND", + "basis": "sleeves", + "score": 0.07, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FAZTX": { + "name": "Nuveen Arizona Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FCAMX": { + "name": "FRANKLIN CALIFORNIA HIGH YIELD MUNICIPAL FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FCFIX": { + "name": "FROST CREDIT FUND", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FCOTX": { + "name": "Nuveen Colorado Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FCSTX": { + "name": "Fidelity California Limited Term Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FCVSX": { + "name": "Fidelity Convertible Securities Fund", + "basis": "sleeves", + "score": 0.6, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "FDMMX": { + "name": "Fidelity Massachusetts Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FEMDX": { + "name": "Franklin Emerging Market Debt Opportunities Fund", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FFRSX": { + "name": "Federated Hermes Floating Rate Strategic Income Fund", + "basis": "sleeves", + "score": 0.14, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FHAIX": { + "name": "FRANKLIN HIGH INCOME FUND", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FHCOX": { + "name": "Federated Hermes Conservative Microshort Fund", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FHMIX": { + "name": "Federated Hermes Conservative Municipal Microshort Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FICNX": { + "name": "Fidelity Connecticut Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FISCX": { + "name": "FRANKLIN CONVERTIBLE SECURITIES FUND", + "basis": "sleeves", + "score": 0.56, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "FKCIX": { + "name": "FRANKLIN CALIFORNIA INTERMEDIATE-TERM TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FKLAX": { + "name": "FRANKLIN LOUISIANA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FKNIX": { + "name": "FRANKLIN NEW YORK INTERMEDIATE-TERM TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FKSTX": { + "name": "Nuveen Kansas Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FKTFX": { + "name": "FRANKLIN CALIFORNIA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FKTIX": { + "name": "FRANKLIN FEDERAL TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FKUTX": { + "name": "FRANKLIN UTILITIES FUND", + "basis": "sleeves", + "score": 0.65, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "" + }, + "FKYTX": { + "name": "Nuveen Kentucky Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FLRN": { + "name": "State Street(R) SPDR(R) Bloomberg Investment Grade Floating Rate ETF", + "basis": "sleeves", + "score": 0.29, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FLTDX": { + "name": "Nuveen Limited Term Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FLTMX": { + "name": "Fidelity Intermediate Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FLTR": { + "name": "VanEck IG Floating Rate ETF", + "basis": "sleeves", + "score": 0.27, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FMDTX": { + "name": "FRANKLIN MARYLAND TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FMOAX": { + "name": "Federated Hermes Municipal High Yield Advantage Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FMOTX": { + "name": "Nuveen Missouri Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FNMTX": { + "name": "Nuveen New Mexico Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FNYTX": { + "name": "FRANKLIN NEW YORK TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FPNTX": { + "name": "Nuveen Pennsylvania Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FRALX": { + "name": "FRANKLIN ALABAMA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRCOX": { + "name": "FRANKLIN COLORADO TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRMOX": { + "name": "FRANKLIN MISSOURI TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRNJX": { + "name": "FRANKLIN NEW JERSEY TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRORX": { + "name": "FRANKLIN OREGON TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRPAX": { + "name": "FRANKLIN PENNSYLVANIA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FRSTX": { + "name": "FRANKLIN CORE PLUS BOND FUND", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FSAZX": { + "name": "Fidelity Arizona Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FTAZX": { + "name": "FRANKLIN ARIZONA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FTFMX": { + "name": "Fidelity New York Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FTGAX": { + "name": "FRANKLIN GEORGIA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FTLAX": { + "name": "Nuveen Louisiana Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FTNYX": { + "name": "Nomura Tax-Free New York Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FTORX": { + "name": "Nomura Tax-Free Oregon Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "FWIAX": { + "name": "Nuveen Wisconsin Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "FXNCX": { + "name": "FRANKLIN NORTH CAROLINA TAX-FREE INCOME FUND", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "GBONX": { + "name": "JPMorgan Global Bond Opportunities Fund", + "basis": "sleeves", + "score": 0.16, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "GIYIX": { + "name": "Guggenheim Ultra Short Duration Fund", + "basis": "sleeves", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "GTFBX": { + "name": "T. Rowe Price Georgia Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "HICOX": { + "name": "COLORADO BONDSHARES A TAX EXEMPT FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "HMEZX": { + "name": "NexPoint Merger Arbitrage Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "merger arb: gains are largely SHORT-TERM (deals close <1 yr) - 1099 will show STCG despite the equity book" + }, + "HUBAX": { + "name": "HARTFORD ULTRASHORT BOND HLS FUND", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ICIFX": { + "name": "Invesco Conservative Income Fund", + "basis": "sleeves", + "score": 0.03, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "IHIAX": { + "name": "Federated Hermes Emerging Market Debt Fund", + "basis": "sleeves", + "score": 0.14, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "INTAX": { + "name": "Columbia Strategic Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "KCTAX": { + "name": "DWS California Tax-Free Income Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "KMDNX": { + "name": "Kinetics Multi-Disciplinary Income Fund", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "KNTAX": { + "name": "DWS New York Tax-Free Income Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "LANSX": { + "name": "Lord Abbett National Tax-Free Income Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "LMSFX": { + "name": "Federated Hermes Municipal Bond Fund, Inc.", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "LPXAX": { + "name": "Cohen & Steers Low Duration Preferred & Income Fund,Inc.", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "LSBDX": { + "name": "Loomis Sayles Income Fund", + "basis": "sleeves", + "score": 0.2, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "LSYUX": { + "name": "Lord Abbett Short Duration High Yield Fund", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "LTEBX": { + "name": "LIMITED TERM TAX EXEMPT BOND FUND OF AMERICA", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "LTNYX": { + "name": "Invesco Rochester Limited Term New York Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "LUBAX": { + "name": "Lord Abbett Ultra Short Bond Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "MASAX": { + "name": "NYLI MacKay Strategic Bond Fund", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "MCOAX": { + "name": "NYLI MacKay Convertible Fund", + "basis": "sleeves", + "score": 0.62, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "" + }, + "MDXBX": { + "name": "T. Rowe Price Maryland Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "MERVX": { + "name": "The Merger Fund VL", + "basis": "sleeves", + "score": 0.24, + "unknown": 0.0, + "location": "IRA", + "notes": "merger arb: gains are largely SHORT-TERM (deals close <1 yr) - 1099 will show STCG despite the equity book" + }, + "MFALX": { + "name": "MFS Alabama Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFARX": { + "name": "MFS Arkansas Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFIAX": { + "name": "MFS Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFPAX": { + "name": "MFS Pennsylvania Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFSCX": { + "name": "MFS South Carolina Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFSMX": { + "name": "MFS Maryland Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFSSX": { + "name": "MFS Massachusetts Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MFWVX": { + "name": "MFS West Virginia Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MGFOX": { + "name": "Income Opportunities Fund", + "basis": "sleeves", + "score": 0.07, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "MISSX": { + "name": "MFS Mississippi Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MMGAX": { + "name": "MFS Georgia Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MMHYX": { + "name": "MFS Municipal High Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MMUFX": { + "name": "MFS Utilities Fund", + "basis": "sleeves", + "score": 0.51, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "MSNCX": { + "name": "MFS North Carolina Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MSNYX": { + "name": "MFS New York Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MSVAX": { + "name": "MFS Virginia Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "MTBAX": { + "name": "NYLI MacKay Tax Free Bond Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "MTLFX": { + "name": "MFS Municipal Limited Maturity Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NEFZX": { + "name": "Loomis Sayles Strategic Income Fund", + "basis": "sleeves", + "score": 0.24, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "NHMAX": { + "name": "Nuveen High Yield Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NMBAX": { + "name": "Nuveen Intermediate Duration Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NMDAX": { + "name": "Nuveen Maryland Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NMUIX": { + "name": "Neuberger Municipal Intermediate Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NNJAX": { + "name": "Nuveen New Jersey Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NNYAX": { + "name": "Nuveen New York Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NSMMX": { + "name": "Columbia Short Duration Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "NTHEX": { + "name": "NORTHEAST INVESTORS TRUST", + "basis": "sleeves", + "score": 0.19, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "OLCAX": { + "name": "Invesco Limited Term California Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "OMIFX": { + "name": "Federated Hermes Ohio Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ONJCX": { + "name": "Invesco New Jersey Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "OPCAX": { + "name": "Invesco California Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "OPNYX": { + "name": "Invesco Rochester AMT-Free New York Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "ORNCX": { + "name": "Invesco Rochester Municipal Opportunities Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PABAX": { + "name": "Putnam Dynamic Asset Allocation Balanced Fund", + "basis": "sleeves", + "score": 0.41, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "PAMFX": { + "name": "Federated Hermes Pennsylvania Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PBAIX": { + "name": "BLACKROCK TACTICAL OPPORTUNITIES FUND", + "basis": "sleeves", + "score": 0.23, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PBCAX": { + "name": "PGIM CALIFORNIA MUNI INCOME FUND", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PDINX": { + "name": "PUTNAM DIVERSIFIED INCOME TRUST", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PGSIX": { + "name": "PUTNAM MORTGAGE SECURITIES FUND", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PHIZX": { + "name": "PGIM Muni High Income Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PHSTX": { + "name": "PUTNAM GLOBAL HEALTH CARE FUND", + "basis": "sleeves", + "score": 0.69, + "unknown": 0.0, + "location": "TAXABLE", + "notes": "" + }, + "PPNAX": { + "name": "Putnam Strategic Intermediate Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PRFHX": { + "name": "T. Rowe Price Tax-Free High Yield Fund", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRFRX": { + "name": "T. Rowe Price Floating Rate Fund", + "basis": "sleeves", + "score": 0.15, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRFSX": { + "name": "T. Rowe Price Tax-Free Short-Intermediate Fund, Inc.", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRINX": { + "name": "T. Rowe Price Summit Municipal Income Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PRMDX": { + "name": "T. Rowe Price Maryland Short-Term Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.09, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRNYX": { + "name": "T. Rowe Price New York Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRSMX": { + "name": "T. Rowe Price Summit Municipal Intermediate Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PRTAX": { + "name": "T. Rowe Price Tax-Free Income Fund, Inc.", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRUAX": { + "name": "PGIM Jennison Utility Fund", + "basis": "sleeves", + "score": 0.53, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "PRVAX": { + "name": "T. Rowe Price Virginia Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRVBX": { + "name": "Versatile Bond Portfolio", + "basis": "sleeves", + "score": 0.12, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PRXCX": { + "name": "T. Rowe Price California Tax-Free Bond Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PSNYX": { + "name": "BNY Mellon New York AMT-Free Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PTEBX": { + "name": "BNY Mellon Opportunistic Municipal Securities Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "PULS": { + "name": "PGIM Ultra Short Bond ETF", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "PYAIX": { + "name": "Payden Absolute Return Bond Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "absolute-return: character varies - check 1099" + }, + "PYSIX": { + "name": "Payden Strategic Income Fund", + "basis": "sleeves", + "score": 0.14, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "QCMMRX": { + "name": "Money Market Account", + "basis": "sleeves", + "score": 0.03, + "unknown": 0.0, + "location": "FLEXIBLE (cash)", + "notes": "ordinary interest, no placement value either way" + }, + "RCTIX": { + "name": "River Canyon Total Return Bond Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "RLVSX": { + "name": "Tax-Exempt Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "RMUYX": { + "name": "Invesco Rochester New York Municipals Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "RPIDX": { + "name": "T. Rowe Price Dynamic Credit Fund", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "RPIFX": { + "name": "T. Rowe Price Institutional Floating Rate Fund", + "basis": "sleeves", + "score": 0.07, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SAFEX": { + "name": "Ultra Short Government Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SCFZX": { + "name": "PGIM Securitized Credit Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SDSAX": { + "name": "Western Asset Income Fund", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SEFIX": { + "name": "SIT INTERNATIONAL FIXED INCOME FUND", + "basis": "sleeves", + "score": 0.19, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SEIMX": { + "name": "STET INTERMEDIATE TERM MUNICIPAL FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "SHTIX": { + "name": "INVESCO Short Duration Inflation Protected Fund", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SITEX": { + "name": "SIT EMERGING MARKETS DEBT FUND", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SMLAX": { + "name": "DWS Managed Municipal Bond Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "SNGVX": { + "name": "SIT U S GOVERNMENT SECURITIES FUND INC", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "SZMAX": { + "name": "DWS Intermediate Tax-Free Fund", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "TAFTX": { + "name": "Tax-Exempt Fund of California", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "TISIX": { + "name": "Nuveen Short Term Bond Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "TRBUX": { + "name": "T. Rowe Price Ultra Short-Term Bond Fund", + "basis": "sleeves", + "score": 0.06, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "TRHYX": { + "name": "T. Rowe Price Institutional High Yield Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "TSDJX": { + "name": "Nuveen Short Duration Impact Bond Fund", + "basis": "sleeves", + "score": 0.05, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "TWTIX": { + "name": "INTERMEDIATE-TERM TAX-FREE BOND FUND", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "ULST": { + "name": "State Street(R) Ultra Short Term Bond ETF", + "basis": "sleeves", + "score": 0.1, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "USIAX": { + "name": "UBS Ultra Short Income Fund", + "basis": "sleeves", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "USMSX": { + "name": "JPMorgan Ultra-Short Municipal Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VCAIX": { + "name": "Vanguard California Intermediate-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VCITX": { + "name": "Vanguard California Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VCTFX": { + "name": "Nomura Tax-Free Colorado Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VIDAX": { + "name": "Nomura Tax-Free Idaho Fund", + "basis": "sleeves", + "score": 0.11, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VKLMX": { + "name": "INVESCO INTERMEDIATE TERM MUNICIPAL INCOME FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VKMMX": { + "name": "INVESCO MUNICIPAL INCOME FUND", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VMATX": { + "name": "Vanguard Massachusetts Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VMLTX": { + "name": "Vanguard Limited-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VNJTX": { + "name": "Vanguard New Jersey Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VNYTX": { + "name": "Vanguard New York Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VOHIX": { + "name": "Vanguard Ohio Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VPAIX": { + "name": "Vanguard Pennsylvania Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VTIPX": { + "name": "Vanguard Short-Term Inflation-Protected Securities Index Fund", + "basis": "sleeves", + "score": 0.13, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VUBFX": { + "name": "Vanguard Ultra-Short-Term Bond Fund", + "basis": "sleeves", + "score": 0.08, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VUSB": { + "name": "Vanguard Ultra-Short Bond ETF", + "basis": "sleeves", + "score": 0.04, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VWAHX": { + "name": "Vanguard High-Yield Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VWEAX": { + "name": "Vanguard High-Yield Corporate Fund", + "basis": "sleeves", + "score": 0.0, + "unknown": 0.0, + "location": "IRA", + "notes": "" + }, + "VWITX": { + "name": "Vanguard Intermediate-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "VWLTX": { + "name": "Vanguard Long-Term Tax-Exempt Fund", + "basis": "sleeves", + "score": 1.0, + "unknown": 0.0, + "location": "TAXABLE (munis)", + "notes": "tax-exempt interest - keep OUT of the IRA" + }, + "WISEX": { + "name": "Azzad Wise Capital Fund", + "basis": "sleeves", + "score": 0.44, + "unknown": 0.0, + "location": "MIXED (check 1099)", + "notes": "" + }, + "WMNUX": { + "name": "Westwood Alternative Income Fund", + "basis": "sleeves", + "score": 0.18, + "unknown": 0.0, + "location": "IRA", + "notes": "" + } + } +} \ No newline at end of file diff --git a/tests/test_fundlab.py b/tests/test_fundlab.py index 5946ec4..20225b9 100644 --- a/tests/test_fundlab.py +++ b/tests/test_fundlab.py @@ -452,6 +452,68 @@ def test_xcheck() -> None: and s.endswith("Advantage Fund"), str(s)) +def test_taxplan() -> None: + print("taxplan", flush=True) + import fundlab.taxplan as tp + + # equity book -> taxable + r = tp.classify("Some US Equity Fund", + buckets=[{"name": "Equity (common)", "pct": 80}, + {"name": "Cash/MMF (short-term)", "pct": 20}]) + check("equity fund -> TAXABLE", r["location"] == "TAXABLE", + f"{r['location']} {r['score']}") + + # bond book -> IRA + r = tp.classify("Some Bond Fund", + buckets=[{"name": "Corporate bond", "pct": 70}, + {"name": "US Treasury", "pct": 25}, + {"name": "Cash/MMF (short-term)", "pct": 5}]) + check("bond fund -> IRA", r["location"] == "IRA", + f"{r['location']} {r['score']}") + + # muni name override wins regardless of sleeves + r = tp.classify("X Municipal Bond Fund", betas={"shv": 5.0}) + check("muni name -> TAXABLE (munis)", + r["location"] == "TAXABLE (munis)" and r["score"] == 1.0, + f"{r['location']}") + + # merger arb: equity book but STCG character -> capped to IRA + r = tp.classify("The Merger Fund", + buckets=[{"name": "Equity (common)", "pct": 90}, + {"name": "Cash/MMF (short-term)", "pct": 10}]) + check("merger arb capped (STCG) -> IRA", + r["location"] == "IRA" and r["score"] <= 0.35, + f"{r['location']} {r['score']}") + + # money market -> flexible + r = tp.classify("Plain Money Market Account", + buckets=[{"name": "Cash/MMF (short-term)", "pct": 100}]) + check("money market -> FLEXIBLE", r["location"] == "FLEXIBLE (cash)", + r["location"]) + + # mostly pass-through, no sleeves -> MIXED + r = tp.classify("Wrapper Fund", + buckets=[{"name": "Fund/ETF holdings", "pct": 100}]) + check("100% FOF no sleeves -> MIXED", + r["location"] == "MIXED (check 1099)", r["location"]) + + # sleeve proxy: pure rates -> IRA; pure equity -> TAXABLE + check("sleeve proxy rates -> IRA", + tp.classify("F", betas={"tlt": 0.9, "shv": 0.2})["location"] + == "IRA", "") + check("sleeve proxy equity -> TAXABLE", + tp.classify("F", betas={"ivv": 0.8, "qqq": 0.2})["location"] + == "TAXABLE", "") + + # manual override for the Leuthold wrappers + r = tp.finalize("LCORX", tp.classify("Leuthold Core Investment", + buckets=[ + {"name": "Fund holdings", + "pct": 100}])) + check("LCORX manual -> TAXABLE", r["location"] == "TAXABLE", + r["location"]) + + def test_drawdown() -> None: print("drawdown", flush=True) import pandas as pd @@ -498,6 +560,7 @@ def main() -> int: test_overnight() test_curated() test_xcheck() + test_taxplan() test_drawdown() test_edgar_live() print(f"\n{PASS} passed, {FAIL} failed")