RIC-vs-pass-through verification + return-of-capital detector
fundlab/rocdetect.py: for a fund's latest N-CSR annual report, parses the per-share "Financial Highlights" distribution table (NII / gains / (tax) return of capital / total), with whitespace normalization, dollar-basis and fiscal-year-column rejection, per-column arithmetic placement of short rows (NII+gains+ROC==total), and family-report disambiguation by current-NAV match. SEC 503 backoff, per-fund cache in roc_cache/. Verified over the 38 core funds: - HMEZX: 18.3% of 5y distributions were return of capital (0.62 + 0.37 per share in 2 of 5 fiscal years) - reinforces the IRA placement. - 17 funds verified zero ROC (AFLIX, ANGLX, ATESX, BTMIX, the EV macro funds, FHCOX/FHMIX, LCORX/LCRIX, PMAIX/PMFKX, SVARX, WMNUX). - 14 unverified (non-standard report layouts - prototype parser), PMORX/QCMMRX tickers not EDGAR-resolvable. Also verified (form-type history on EDGAR): CVSIX, QSPNX, MBXIX, ATRFX, ATESX, EAGMX, PBAIX, WISEX, EBSAX all file NPORT-P + N-CSR + 497 -> registered RICs, not pass-throughs; the whole 497-filer universe is registered, so no candidate can pass through capital losses. Proof case for ROC: PGSIX per-share table shows a tax return-of-capital line and NAV eroded 11.87 -> 7.88 (-34%) over 5 fiscal years while paying out every year. RESEARCH.md: full write-up. No app change (analysis artifact).
This commit is contained in:
parent
9458e316cb
commit
620e2499ac
|
|
@ -130,6 +130,62 @@ not a gate.
|
|||
4. CEF universe (485/N-2 filers) - separate pass; CEFs have
|
||||
premium/discount dynamics the NAV screen can't see.
|
||||
|
||||
### RIC vs pass-through + return-of-capital check (2026-08-27)
|
||||
User asked (1) whether the long-short alternatives are RICs or
|
||||
pass-throughs, and (2) whether mutual funds can distribute
|
||||
non-taxable "return of capital".
|
||||
|
||||
**RIC vs pass-through - verified on EDGAR (form-type history):**
|
||||
CVSIX, QSPNX, MBXIX, ATRFX, ATESX, EAGMX, PBAIX, WISEX, EBSAX ALL
|
||||
file NPORT-P + N-CSR + N-CSRS + N-CEN + 497/497K - i.e. registered
|
||||
40 Act open-end funds = RICs. MBXIX/ATRFX (the "hedge strategy" I
|
||||
classes) are in a registered trust (Mutual Fund Series Trust) even
|
||||
though they sound like hedge funds. 1120-R tax returns are filed with
|
||||
the IRS, not EDGAR, so their absence there is expected. The whole
|
||||
2,384-fund universe is 497-filers, so NO candidate is a pass-through:
|
||||
none can pass capital losses to shareholders; the only internal
|
||||
tax benefit is the harvest reserve (offsets the fund's FUTURE gain
|
||||
distributions). K-1 loss pass-throughs (MLPs, private credit) are
|
||||
outside the universe and IRA-bound anyway.
|
||||
|
||||
**Return of capital - yes, and it happens in the candidate pool:**
|
||||
ROC = distribution characterized as a return of the shareholder's
|
||||
OWN basis. Non-taxable until basis is exhausted, then taxed as a
|
||||
capital gain - i.e. DEFERRED, not exempt. It is also a red flag:
|
||||
the fund is paying back principal. The definitive source is the
|
||||
per-share "Financial Highlights" table in the N-CSR annual report
|
||||
("Distributions from: NII / gains / (tax) return of capital /
|
||||
total").
|
||||
|
||||
fundlab/rocdetect.py parses that table (whitespace-normalized,
|
||||
dollar-basis and date-column rejection, lone values placed by
|
||||
per-column arithmetic NII+gains+ROC==total, family reports
|
||||
disambiguated by current-NAV match). Run over the 38 core funds
|
||||
(cached per fund in roc_cache/):
|
||||
- HMEZX: 18.3% of 5y distributions were ROC ($0.62 and $0.37 per
|
||||
share in 2 of 5 fiscal years; $1.01/yr distributions otherwise
|
||||
from NII) - reinforces the IRA placement.
|
||||
- 17 funds verified ZERO ROC: AFLIX, ANGLX, ATESX, BTMIX, EAGMX,
|
||||
EGRIX, EGRSX, ETSIX, FHCOX, FHMIX, LCORX, LCRIX, PMAIX, PMFKX,
|
||||
SVARX, WMNUX.
|
||||
- 14 unverified (non-standard report layouts: Vanguard MERVX,
|
||||
JPMorgan JLPSX, AQR QSPNX, PGIM SCFZX, Columbia COSIX, ...):
|
||||
parser is a prototype; per-family layouts not all covered.
|
||||
- PMORX/QCMMRX: ticker not resolvable via browse-edgar.
|
||||
|
||||
Separate proof case found earlier while checking the NAV-decline
|
||||
heuristic: PGSIX (Putnam Mortgage Securities, a drawdown-screen
|
||||
candidate) - per-share table shows a "Tax return of capital" line
|
||||
($0.35/sh in FY2021: NII $0.14 + ROC $0.35 = $0.49 total) and the
|
||||
NAV eroded $11.87 -> $7.88 (-34%) over the 5 shown fiscal years
|
||||
while paying out every year. Classic constant-distribution principal
|
||||
erosion.
|
||||
|
||||
Placement consequence: ROC does NOT help the taxable-account case -
|
||||
basis deferral in a taxable account is what a traditional IRA gives
|
||||
you anyway, and it signals principal erosion. The taxable-friendly
|
||||
character remains qualified dividends / LTCG.
|
||||
|
||||
### Price-appreciation vs. payout split (fundlab/taxsplit.py, 2026-08-27)
|
||||
Follow-up to the tax-location plan: the user pointed out that fund
|
||||
NAV appreciation is ALSO a capital gain (LTCG on a >1y sale) - the
|
||||
|
|
|
|||
22
fundlab/roc_cache/aflix.json
Normal file
22
fundlab/roc_cache/aflix.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "AFLIX",
|
||||
"cik": "0001552947",
|
||||
"trust": "Two Roads Shared Trust",
|
||||
"filing": "2026-07-09",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.78
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/aguax.json
Normal file
9
fundlab/roc_cache/aguax.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "AGUAX",
|
||||
"cik": "0000809593",
|
||||
"trust": "AMERICAN BEACON FUNDS",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
24
fundlab/roc_cache/anglx.json
Normal file
24
fundlab/roc_cache/anglx.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"sym": "ANGLX",
|
||||
"cik": "0001612930",
|
||||
"trust": "Angel Oak Funds Trust",
|
||||
"filing": "2026-04-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.47
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.47
|
||||
],
|
||||
"nav": [
|
||||
8.78
|
||||
],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/atesx.json
Normal file
22
fundlab/roc_cache/atesx.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "ATESX",
|
||||
"cik": "0001644419",
|
||||
"trust": "Northern Lights Fund Trust IV",
|
||||
"filing": "2026-08-10",
|
||||
"table": {
|
||||
"nii": [
|
||||
-1.14
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.14
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/atrfx.json
Normal file
9
fundlab/roc_cache/atrfx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "ATRFX",
|
||||
"cik": "0001355064",
|
||||
"trust": "MUTUAL FUND SERIES TRUST",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
40
fundlab/roc_cache/btmix.json
Normal file
40
fundlab/roc_cache/btmix.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"sym": "BTMIX",
|
||||
"cik": "0001282693",
|
||||
"trust": "BAIRD FUNDS INC",
|
||||
"filing": "2026-03-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.31,
|
||||
-0.29,
|
||||
-0.25,
|
||||
-0.13,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.31,
|
||||
-0.29,
|
||||
-0.25,
|
||||
-0.13,
|
||||
-0.09
|
||||
],
|
||||
"nav": [
|
||||
10.09,
|
||||
9.96,
|
||||
9.96,
|
||||
9.83,
|
||||
10.38
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": -0.028
|
||||
}
|
||||
9
fundlab/roc_cache/coiax.json
Normal file
9
fundlab/roc_cache/coiax.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "COIAX",
|
||||
"cik": "0000804239",
|
||||
"trust": "SEI INSTITUTIONAL MANAGED TRUST",
|
||||
"filing": "2025-12-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/cosix.json
Normal file
9
fundlab/roc_cache/cosix.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "COSIX",
|
||||
"cik": "0000773757",
|
||||
"trust": "COLUMBIA FUNDS SERIES TRUST I",
|
||||
"filing": "2026-08-06",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/cvsix.json
Normal file
9
fundlab/roc_cache/cvsix.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "CVSIX",
|
||||
"cik": "0000826732",
|
||||
"trust": "CALAMOS INVESTMENT TRUST/IL",
|
||||
"filing": "2025-12-29",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/dmszx.json
Normal file
9
fundlab/roc_cache/dmszx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "DMSZX",
|
||||
"cik": "0001688680",
|
||||
"trust": "Brinker Capital Destinations Trust",
|
||||
"filing": "2026-05-06",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
20
fundlab/roc_cache/dultx.json
Normal file
20
fundlab/roc_cache/dultx.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"sym": "DULTX",
|
||||
"cik": "0000230173",
|
||||
"trust": "DELAWARE GROUP CASH RESERVE",
|
||||
"filing": "2026-06-09",
|
||||
"table": {
|
||||
"nii": [
|
||||
2.0
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/eagmx.json
Normal file
22
fundlab/roc_cache/eagmx.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "EAGMX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/egrix.json
Normal file
22
fundlab/roc_cache/egrix.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "EGRIX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/egrsx.json
Normal file
22
fundlab/roc_cache/egrsx.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "EGRSX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/etsix.json
Normal file
22
fundlab/roc_cache/etsix.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "ETSIX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
32
fundlab/roc_cache/femdx.json
Normal file
32
fundlab/roc_cache/femdx.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"sym": "FEMDX",
|
||||
"cik": "0001124459",
|
||||
"trust": "Franklin Global Trust",
|
||||
"filing": "2025-09-26",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.53,
|
||||
-0.34,
|
||||
-0.9
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [
|
||||
12.35,
|
||||
11.55,
|
||||
10.46,
|
||||
9.91,
|
||||
11.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": 0.053
|
||||
}
|
||||
32
fundlab/roc_cache/fhcox.json
Normal file
32
fundlab/roc_cache/fhcox.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"sym": "FHCOX",
|
||||
"cik": "0001707560",
|
||||
"trust": "Federated Hermes Adviser Series",
|
||||
"filing": "2026-08-25",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.01,
|
||||
-0.01
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.21,
|
||||
-0.81,
|
||||
-0.63,
|
||||
-0.34,
|
||||
-0.61
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
32
fundlab/roc_cache/fhmix.json
Normal file
32
fundlab/roc_cache/fhmix.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"sym": "FHMIX",
|
||||
"cik": "0001707560",
|
||||
"trust": "Federated Hermes Adviser Series",
|
||||
"filing": "2026-08-25",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.01,
|
||||
-0.01
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.21,
|
||||
-0.81,
|
||||
-0.63,
|
||||
-0.34,
|
||||
-0.61
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/hicox.json
Normal file
9
fundlab/roc_cache/hicox.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "HICOX",
|
||||
"cik": "0000810744",
|
||||
"trust": "COLORADO BONDSHARES A TAX EXEMPT FUND",
|
||||
"filing": "2025-12-04",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
39
fundlab/roc_cache/hmezx.json
Normal file
39
fundlab/roc_cache/hmezx.json
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"sym": "HMEZX",
|
||||
"cik": "0001354917",
|
||||
"trust": "NEXPOINT FUNDS I",
|
||||
"filing": "2025-09-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-1.01,
|
||||
-1.0,
|
||||
-0.38,
|
||||
-0.4
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
-0.62,
|
||||
-0.37,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.01,
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.24,
|
||||
-1.16
|
||||
],
|
||||
"nav": [
|
||||
19.83,
|
||||
19.71,
|
||||
19.21,
|
||||
19.89,
|
||||
20.58
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": 0.183,
|
||||
"nav_change_5y": -0.036
|
||||
}
|
||||
9
fundlab/roc_cache/jlpsx.json
Normal file
9
fundlab/roc_cache/jlpsx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "JLPSX",
|
||||
"cik": "0001217286",
|
||||
"trust": "JPMorgan Trust I",
|
||||
"filing": "2026-05-07",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
20
fundlab/roc_cache/lamhx.json
Normal file
20
fundlab/roc_cache/lamhx.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"sym": "LAMHX",
|
||||
"cik": "0000887194",
|
||||
"trust": "LORD ABBETT RESEARCH FUND INC",
|
||||
"filing": "2026-02-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
24.79
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
32
fundlab/roc_cache/lcorx.json
Normal file
32
fundlab/roc_cache/lcorx.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"sym": "LCORX",
|
||||
"cik": "0001511699",
|
||||
"trust": "Managed Portfolio Series",
|
||||
"filing": "2026-08-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.04,
|
||||
-0.06,
|
||||
-0.03,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.2
|
||||
],
|
||||
"nav": [
|
||||
18.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
32
fundlab/roc_cache/lcrix.json
Normal file
32
fundlab/roc_cache/lcrix.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"sym": "LCRIX",
|
||||
"cik": "0001511699",
|
||||
"trust": "Managed Portfolio Series",
|
||||
"filing": "2026-08-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.04,
|
||||
-0.06,
|
||||
-0.03,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.2
|
||||
],
|
||||
"nav": [
|
||||
18.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
30
fundlab/roc_cache/lpxax.json
Normal file
30
fundlab/roc_cache/lpxax.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"sym": "LPXAX",
|
||||
"cik": "0001652200",
|
||||
"trust": "Cohen & Steers Low Duration Preferred & Income Fund, Inc.",
|
||||
"filing": "2026-07-02",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.51
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
-0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [
|
||||
9.59,
|
||||
9.43,
|
||||
9.23,
|
||||
8.87,
|
||||
9.36
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": 0.025
|
||||
}
|
||||
9
fundlab/roc_cache/mbxix.json
Normal file
9
fundlab/roc_cache/mbxix.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "MBXIX",
|
||||
"cik": "0001355064",
|
||||
"trust": "MUTUAL FUND SERIES TRUST",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/mervx.json
Normal file
9
fundlab/roc_cache/mervx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "MERVX",
|
||||
"cik": "0001208133",
|
||||
"trust": "MERGER FUND VL",
|
||||
"filing": "2026-03-05",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
31
fundlab/roc_cache/pmaix.json
Normal file
31
fundlab/roc_cache/pmaix.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"sym": "PMAIX",
|
||||
"cik": "0002042316",
|
||||
"trust": "Victory Portfolios IV",
|
||||
"filing": "2026-06-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.04,
|
||||
-0.04
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-6.32,
|
||||
-1.99,
|
||||
-1.1,
|
||||
-1.06,
|
||||
-6.45
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
31
fundlab/roc_cache/pmfkx.json
Normal file
31
fundlab/roc_cache/pmfkx.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"sym": "PMFKX",
|
||||
"cik": "0002042316",
|
||||
"trust": "Victory Portfolios IV",
|
||||
"filing": "2026-06-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.04,
|
||||
-0.04
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-6.32,
|
||||
-1.99,
|
||||
-1.1,
|
||||
-1.06,
|
||||
-6.45
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/qspnx.json
Normal file
9
fundlab/roc_cache/qspnx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "QSPNX",
|
||||
"cik": "0001444822",
|
||||
"trust": "AQR Funds",
|
||||
"filing": "2026-02-26",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/rctix.json
Normal file
9
fundlab/roc_cache/rctix.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "RCTIX",
|
||||
"cik": "0001516523",
|
||||
"trust": "Advisers Investment Trust",
|
||||
"filing": "2025-11-26",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/safex.json
Normal file
9
fundlab/roc_cache/safex.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "SAFEX",
|
||||
"cik": "0001257927",
|
||||
"trust": "WEITZ FUNDS",
|
||||
"filing": "2026-05-27",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/scfzx.json
Normal file
9
fundlab/roc_cache/scfzx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "SCFZX",
|
||||
"cik": "0000887991",
|
||||
"trust": "PRUDENTIAL INVESTMENT PORTFOLIOS 8",
|
||||
"filing": "2025-12-03",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
24
fundlab/roc_cache/svarx.json
Normal file
24
fundlab/roc_cache/svarx.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"sym": "SVARX",
|
||||
"cik": "0001556505",
|
||||
"trust": "Advisors Preferred Trust",
|
||||
"filing": "2026-03-10",
|
||||
"table": {
|
||||
"nii": [
|
||||
-3.72
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-3.72
|
||||
],
|
||||
"nav": [
|
||||
38.76
|
||||
],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
9
fundlab/roc_cache/usmsx.json
Normal file
9
fundlab/roc_cache/usmsx.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sym": "USMSX",
|
||||
"cik": "0001659326",
|
||||
"trust": "JPMORGAN TRUST IV",
|
||||
"filing": "2026-05-07",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
22
fundlab/roc_cache/wmnux.json
Normal file
22
fundlab/roc_cache/wmnux.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"sym": "WMNUX",
|
||||
"cik": "0001545440",
|
||||
"trust": "Ultimus Managers Trust",
|
||||
"filing": "2026-08-03",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.31
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.31
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
718
fundlab/roc_results.json
Normal file
718
fundlab/roc_results.json
Normal file
|
|
@ -0,0 +1,718 @@
|
|||
{
|
||||
"AFLIX": {
|
||||
"sym": "AFLIX",
|
||||
"cik": "0001552947",
|
||||
"trust": "Two Roads Shared Trust",
|
||||
"filing": "2026-07-09",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.78
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"AGUAX": {
|
||||
"sym": "AGUAX",
|
||||
"cik": "0000809593",
|
||||
"trust": "AMERICAN BEACON FUNDS",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"ANGLX": {
|
||||
"sym": "ANGLX",
|
||||
"cik": "0001612930",
|
||||
"trust": "Angel Oak Funds Trust",
|
||||
"filing": "2026-04-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.47
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.47
|
||||
],
|
||||
"nav": [
|
||||
8.78
|
||||
],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"ATESX": {
|
||||
"sym": "ATESX",
|
||||
"cik": "0001644419",
|
||||
"trust": "Northern Lights Fund Trust IV",
|
||||
"filing": "2026-08-10",
|
||||
"table": {
|
||||
"nii": [
|
||||
-1.14
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.14
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"ATRFX": {
|
||||
"sym": "ATRFX",
|
||||
"cik": "0001355064",
|
||||
"trust": "MUTUAL FUND SERIES TRUST",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"BTMIX": {
|
||||
"sym": "BTMIX",
|
||||
"cik": "0001282693",
|
||||
"trust": "BAIRD FUNDS INC",
|
||||
"filing": "2026-03-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.31,
|
||||
-0.29,
|
||||
-0.25,
|
||||
-0.13,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.31,
|
||||
-0.29,
|
||||
-0.25,
|
||||
-0.13,
|
||||
-0.09
|
||||
],
|
||||
"nav": [
|
||||
10.09,
|
||||
9.96,
|
||||
9.96,
|
||||
9.83,
|
||||
10.38
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": -0.028
|
||||
},
|
||||
"COIAX": {
|
||||
"sym": "COIAX",
|
||||
"cik": "0000804239",
|
||||
"trust": "SEI INSTITUTIONAL MANAGED TRUST",
|
||||
"filing": "2025-12-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"COSIX": {
|
||||
"sym": "COSIX",
|
||||
"cik": "0000773757",
|
||||
"trust": "COLUMBIA FUNDS SERIES TRUST I",
|
||||
"filing": "2026-08-06",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"CVSIX": {
|
||||
"sym": "CVSIX",
|
||||
"cik": "0000826732",
|
||||
"trust": "CALAMOS INVESTMENT TRUST/IL",
|
||||
"filing": "2025-12-29",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"DMSZX": {
|
||||
"sym": "DMSZX",
|
||||
"cik": "0001688680",
|
||||
"trust": "Brinker Capital Destinations Trust",
|
||||
"filing": "2026-05-06",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"DULTX": {
|
||||
"sym": "DULTX",
|
||||
"cik": "0000230173",
|
||||
"trust": "DELAWARE GROUP CASH RESERVE",
|
||||
"filing": "2026-06-09",
|
||||
"table": {
|
||||
"nii": [
|
||||
2.0
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"EAGMX": {
|
||||
"sym": "EAGMX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"EGRIX": {
|
||||
"sym": "EGRIX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"EGRSX": {
|
||||
"sym": "EGRSX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"ETSIX": {
|
||||
"sym": "ETSIX",
|
||||
"cik": "0000745463",
|
||||
"trust": "Eaton Vance Mutual Funds Trust",
|
||||
"filing": "2026-03-31",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.73
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-2.05
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"FEMDX": {
|
||||
"sym": "FEMDX",
|
||||
"cik": "0001124459",
|
||||
"trust": "Franklin Global Trust",
|
||||
"filing": "2025-09-26",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.53,
|
||||
-0.34,
|
||||
-0.9
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [
|
||||
12.35,
|
||||
11.55,
|
||||
10.46,
|
||||
9.91,
|
||||
11.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": 0.053
|
||||
},
|
||||
"FHCOX": {
|
||||
"sym": "FHCOX",
|
||||
"cik": "0001707560",
|
||||
"trust": "Federated Hermes Adviser Series",
|
||||
"filing": "2026-08-25",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.01,
|
||||
-0.01
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.21,
|
||||
-0.81,
|
||||
-0.63,
|
||||
-0.34,
|
||||
-0.61
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"FHMIX": {
|
||||
"sym": "FHMIX",
|
||||
"cik": "0001707560",
|
||||
"trust": "Federated Hermes Adviser Series",
|
||||
"filing": "2026-08-25",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.01,
|
||||
-0.01
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.21,
|
||||
-0.81,
|
||||
-0.63,
|
||||
-0.34,
|
||||
-0.61
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"HICOX": {
|
||||
"sym": "HICOX",
|
||||
"cik": "0000810744",
|
||||
"trust": "COLORADO BONDSHARES A TAX EXEMPT FUND",
|
||||
"filing": "2025-12-04",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"HMEZX": {
|
||||
"sym": "HMEZX",
|
||||
"cik": "0001354917",
|
||||
"trust": "NEXPOINT FUNDS I",
|
||||
"filing": "2025-09-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-1.01,
|
||||
-1.0,
|
||||
-0.38,
|
||||
-0.4
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
-0.62,
|
||||
-0.37,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.01,
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.24,
|
||||
-1.16
|
||||
],
|
||||
"nav": [
|
||||
19.83,
|
||||
19.71,
|
||||
19.21,
|
||||
19.89,
|
||||
20.58
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": 0.183,
|
||||
"nav_change_5y": -0.036
|
||||
},
|
||||
"JLPSX": {
|
||||
"sym": "JLPSX",
|
||||
"cik": "0001217286",
|
||||
"trust": "JPMorgan Trust I",
|
||||
"filing": "2026-05-07",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"LAMHX": {
|
||||
"sym": "LAMHX",
|
||||
"cik": "0000887194",
|
||||
"trust": "LORD ABBETT RESEARCH FUND INC",
|
||||
"filing": "2026-02-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
24.79
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"LCORX": {
|
||||
"sym": "LCORX",
|
||||
"cik": "0001511699",
|
||||
"trust": "Managed Portfolio Series",
|
||||
"filing": "2026-08-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.04,
|
||||
-0.06,
|
||||
-0.03,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.2
|
||||
],
|
||||
"nav": [
|
||||
18.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"LCRIX": {
|
||||
"sym": "LCRIX",
|
||||
"cik": "0001511699",
|
||||
"trust": "Managed Portfolio Series",
|
||||
"filing": "2026-08-04",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.02,
|
||||
-0.04,
|
||||
-0.06,
|
||||
-0.03,
|
||||
-0.09
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-1.2
|
||||
],
|
||||
"nav": [
|
||||
18.73
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"LPXAX": {
|
||||
"sym": "LPXAX",
|
||||
"cik": "0001652200",
|
||||
"trust": "Cohen & Steers Low Duration Preferred & Income Fund, Inc.",
|
||||
"filing": "2026-07-02",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.51
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
-0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [],
|
||||
"nav": [
|
||||
9.59,
|
||||
9.43,
|
||||
9.23,
|
||||
8.87,
|
||||
9.36
|
||||
],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": 0.025
|
||||
},
|
||||
"MBXIX": {
|
||||
"sym": "MBXIX",
|
||||
"cik": "0001355064",
|
||||
"trust": "MUTUAL FUND SERIES TRUST",
|
||||
"filing": "2026-06-08",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"MERVX": {
|
||||
"sym": "MERVX",
|
||||
"cik": "0001208133",
|
||||
"trust": "MERGER FUND VL",
|
||||
"filing": "2026-03-05",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"PMAIX": {
|
||||
"sym": "PMAIX",
|
||||
"cik": "0002042316",
|
||||
"trust": "Victory Portfolios IV",
|
||||
"filing": "2026-06-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.04,
|
||||
-0.04
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-6.32,
|
||||
-1.99,
|
||||
-1.1,
|
||||
-1.06,
|
||||
-6.45
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"PMFKX": {
|
||||
"sym": "PMFKX",
|
||||
"cik": "0002042316",
|
||||
"trust": "Victory Portfolios IV",
|
||||
"filing": "2026-06-08",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.04,
|
||||
-0.04
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-6.32,
|
||||
-1.99,
|
||||
-1.1,
|
||||
-1.06,
|
||||
-6.45
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 5
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"PMORX": {
|
||||
"sym": "PMORX",
|
||||
"error": "CIK not found"
|
||||
},
|
||||
"QCMMRX": {
|
||||
"sym": "QCMMRX",
|
||||
"error": "CIK not found"
|
||||
},
|
||||
"QSPNX": {
|
||||
"sym": "QSPNX",
|
||||
"cik": "0001444822",
|
||||
"trust": "AQR Funds",
|
||||
"filing": "2026-02-26",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"RCTIX": {
|
||||
"sym": "RCTIX",
|
||||
"cik": "0001516523",
|
||||
"trust": "Advisers Investment Trust",
|
||||
"filing": "2025-11-26",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"SAFEX": {
|
||||
"sym": "SAFEX",
|
||||
"cik": "0001257927",
|
||||
"trust": "WEITZ FUNDS",
|
||||
"filing": "2026-05-27",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"SCFZX": {
|
||||
"sym": "SCFZX",
|
||||
"cik": "0000887991",
|
||||
"trust": "PRUDENTIAL INVESTMENT PORTFOLIOS 8",
|
||||
"filing": "2025-12-03",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"SVARX": {
|
||||
"sym": "SVARX",
|
||||
"cik": "0001556505",
|
||||
"trust": "Advisors Preferred Trust",
|
||||
"filing": "2026-03-10",
|
||||
"table": {
|
||||
"nii": [
|
||||
-3.72
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-3.72
|
||||
],
|
||||
"nav": [
|
||||
38.76
|
||||
],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"USMSX": {
|
||||
"sym": "USMSX",
|
||||
"cik": "0001659326",
|
||||
"trust": "JPMORGAN TRUST IV",
|
||||
"filing": "2026-05-07",
|
||||
"table": null,
|
||||
"roc_share_5y": null,
|
||||
"nav_change_5y": null
|
||||
},
|
||||
"WMNUX": {
|
||||
"sym": "WMNUX",
|
||||
"cik": "0001545440",
|
||||
"trust": "Ultimus Managers Trust",
|
||||
"filing": "2026-08-03",
|
||||
"table": {
|
||||
"nii": [
|
||||
-0.31
|
||||
],
|
||||
"gains": [],
|
||||
"roc": [
|
||||
0.0
|
||||
],
|
||||
"tot": [
|
||||
-0.31
|
||||
],
|
||||
"nav": [],
|
||||
"ncols": 1
|
||||
},
|
||||
"roc_share_5y": -0.0,
|
||||
"nav_change_5y": null
|
||||
}
|
||||
}
|
||||
39
fundlab/roc_run.log
Normal file
39
fundlab/roc_run.log
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
fund ROC 5y NAV 5y dist/yr (most recent first) filing
|
||||
HMEZX 18.3% -3.6% tot -1.01/roc -0.62 tot -1.00/roc -0.37 to 2025-09-08
|
||||
AFLIX -0.0% - tot -0.78 2026-07-09
|
||||
AGUAX (no per-share table found)
|
||||
ANGLX -0.0% - tot -0.47 2026-04-08
|
||||
ATESX -0.0% - tot -1.14 2026-08-10
|
||||
ATRFX (no per-share table found)
|
||||
BTMIX -0.0% -2.8% tot -0.31 tot -0.29 tot -0.25 tot -0.13 2026-03-04
|
||||
COIAX (no per-share table found)
|
||||
COSIX (no per-share table found)
|
||||
CVSIX (no per-share table found)
|
||||
DMSZX (no per-share table found)
|
||||
DULTX - - tot 0.00 2026-06-09
|
||||
EAGMX -0.0% - tot -2.05 2026-03-31
|
||||
EGRIX -0.0% - tot -2.05 2026-03-31
|
||||
EGRSX -0.0% - tot -2.05 2026-03-31
|
||||
ETSIX -0.0% - tot -2.05 2026-03-31
|
||||
FEMDX - +5.3% tot 0.00 tot 0.00 tot 0.00 tot 0.00 tot 2025-09-26
|
||||
FHCOX -0.0% - tot -1.21 tot -0.81 tot -0.63 tot -0.34 2026-08-25
|
||||
FHMIX -0.0% - tot -1.21 tot -0.81 tot -0.63 tot -0.34 2026-08-25
|
||||
HICOX (no per-share table found)
|
||||
JLPSX (no per-share table found)
|
||||
LAMHX - - tot 0.00 2026-02-04
|
||||
LCORX -0.0% - tot -1.20 tot 0.00 tot 0.00 tot 0.00 tot 2026-08-04
|
||||
LCRIX -0.0% - tot -1.20 tot 0.00 tot 0.00 tot 0.00 tot 2026-08-04
|
||||
LPXAX - +2.5% tot 0.00 tot 0.00 tot 0.00 tot 0.00 tot 2026-07-02
|
||||
MBXIX (no per-share table found)
|
||||
MERVX (no per-share table found)
|
||||
PMAIX -0.0% - tot -6.32 tot -1.99 tot -1.10 tot -1.06 2026-06-08
|
||||
PMFKX -0.0% - tot -6.32 tot -1.99 tot -1.10 tot -1.06 2026-06-08
|
||||
PMORX (CIK not found)
|
||||
QCMMRX (CIK not found)
|
||||
QSPNX (no per-share table found)
|
||||
RCTIX (no per-share table found)
|
||||
SAFEX (no per-share table found)
|
||||
SCFZX (no per-share table found)
|
||||
SVARX -0.0% - tot -3.72 2026-03-10
|
||||
USMSX (no per-share table found)
|
||||
WMNUX -0.0% - tot -0.31 2026-08-03
|
||||
302
fundlab/rocdetect.py
Normal file
302
fundlab/rocdetect.py
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
"""Return-of-capital (ROC) detector from N-CSR annual reports.
|
||||
|
||||
A mutual fund's per-share "Financial Highlights" table (item 7 of the
|
||||
annual report, filed as N-CSR) lists distributions by character:
|
||||
|
||||
Distributions from:
|
||||
Net investment income ...
|
||||
(Realized) capital gains ...
|
||||
(Tax) return of capital ...
|
||||
Total distributions ...
|
||||
|
||||
The "return of capital" line is the definitive answer to "is this
|
||||
fund paying me back my own money?" - the price-data heuristic
|
||||
(NAV falling while paying out) only SUGGESTS it, and for
|
||||
long-duration funds NAV declines are usually rate damage, not ROC.
|
||||
|
||||
Facts used:
|
||||
- The table shows up to 5-10 fiscal years, MOST RECENT LEFT.
|
||||
- Values are parenthesized outflows: "(1.16)" = $1.16 distributed.
|
||||
- A row with fewer tokens than the NII row has blanks dropped; the
|
||||
arithmetic check (NII + gains + ROC == total per column) is used
|
||||
to place a lone value (verified on PGSIX: the lone (0.35) only
|
||||
reconciles in the oldest column: 0.14 + 0.35 = 0.49).
|
||||
|
||||
Run: python -m fundlab.rocdetect [SYM ...]
|
||||
(no args = the 16 shortlist + 22 cross-checked funds)
|
||||
Output: fundlab/roc_results.json (cached per fund in roc_cache/)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from fundlab import edgar
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
CACHE = HERE / "roc_cache"
|
||||
RESULTS = HERE / "roc_results.json"
|
||||
NUM = re.compile(r"\$?\(?[\d,]+(?:\.\d+)?\)?:?")
|
||||
|
||||
|
||||
def _nums(tokens: list[str]) -> list[float | None]:
|
||||
out = []
|
||||
for t in tokens:
|
||||
t = t.strip().rstrip(":")
|
||||
if not re.fullmatch(r"\$?\(?\d[\d,]*(?:\.\d+)?\)?", t):
|
||||
out.append(None)
|
||||
continue
|
||||
neg = t.startswith("(")
|
||||
v = float(t.strip("$()").replace(",", ""))
|
||||
out.append(-v if neg else v)
|
||||
return out
|
||||
|
||||
|
||||
NUMTOK = re.compile(r"\$?\(?\d[\d,]*(?:\.\d+)?\)?")
|
||||
|
||||
|
||||
def _parse_table(block: str) -> dict | None:
|
||||
"""Parse one per-share distribution block."""
|
||||
|
||||
def row(label_rx: str) -> list[float | None]:
|
||||
rm = re.search(label_rx, block, re.I)
|
||||
if not rm:
|
||||
return []
|
||||
tail = re.sub(r"\.{2,}", " ", block[rm.end(): rm.end() + 600])
|
||||
# some reports print "(1.01 )" / "( 1.01 )" - rejoin the parens
|
||||
tail = re.sub(r"\(\s+", "(", tail)
|
||||
tail = re.sub(r"\s+\)", ")", tail)
|
||||
vals: list[str] = []
|
||||
for t in re.findall(r"\S+", tail):
|
||||
if t == "$":
|
||||
continue # "NAV ... $ 15.88 $ 15.23 ..."
|
||||
if NUMTOK.fullmatch(t):
|
||||
vals.append(t)
|
||||
elif vals:
|
||||
break # numbers over - next label reached
|
||||
return _nums(vals[:10])
|
||||
|
||||
nii = row(r"net investment income")
|
||||
gains = row(r"(?:realized |unrealized )?capital gains?")
|
||||
roc = row(r"(?:tax )?return of capital")
|
||||
tot = row(r"total distributions")
|
||||
nav = row(r"net asset value, end of year")
|
||||
if not nii and not tot:
|
||||
return None
|
||||
ncols = max(len(x) for x in (nii, gains, roc, tot, nav))
|
||||
if ncols == 0:
|
||||
return None
|
||||
# place short rows by arithmetic: find the column where the
|
||||
# components sum to the total (within rounding)
|
||||
def _get(row: list[float | None], i: int) -> float:
|
||||
if i < len(row) and row[i] is not None:
|
||||
return row[i]
|
||||
return 0.0
|
||||
|
||||
def place(vals: list[float | None]) -> list[float | None]:
|
||||
if len(vals) == ncols:
|
||||
return vals
|
||||
from itertools import combinations
|
||||
nz = [v for v in vals if v is not None]
|
||||
if not nz:
|
||||
return [0.0] * ncols
|
||||
|
||||
def reconcile(assign: list[int], nz_: list[float]) -> bool:
|
||||
put = {c: v for c, v in zip(assign, nz_)}
|
||||
for c in range(ncols):
|
||||
if not tot or c >= len(tot) or tot[c] is None:
|
||||
continue
|
||||
s = (_get(nii, c) + _get(gains, c) + put.get(c, 0.0))
|
||||
if abs(s - tot[c]) > 0.011 * max(1.0, abs(tot[c])) + 1e-9:
|
||||
return False
|
||||
return True
|
||||
|
||||
# blanks are dropped when the table flattens, so a short row's
|
||||
# values may sit in ANY columns - try placements and keep the
|
||||
# one where every column reconciles (NII+gains+ROC == total)
|
||||
if len(nz) <= 6 and tot:
|
||||
for assign in combinations(range(ncols), len(nz)):
|
||||
if reconcile(list(assign), nz):
|
||||
put = {c: v for c, v in zip(assign, nz)}
|
||||
return [put.get(c, 0.0) for c in range(ncols)]
|
||||
full = [0.0] * ncols
|
||||
for i, v in enumerate(vals):
|
||||
if v is not None:
|
||||
full[i] = v
|
||||
return full
|
||||
roc = place(roc)
|
||||
# sanity: the per-share table has small values. Dollar-basis
|
||||
# statements ("distributions to shareholders: $459,612,118") and
|
||||
# fiscal-year date columns ("2025") leak in from other sections.
|
||||
def _bad(vals: list[float | None]) -> bool:
|
||||
for v in vals:
|
||||
if v is None:
|
||||
continue
|
||||
if abs(v) > 1000:
|
||||
return True
|
||||
if v == int(v) and 1900 <= v <= 2100:
|
||||
return True
|
||||
return False
|
||||
if _bad(tot) or _bad(nav) or _bad(nii):
|
||||
return None
|
||||
if tot and all(v == 0 for v in tot if v is not None):
|
||||
return None # all-zero total = wrong table (these all pay)
|
||||
# table-level validity: every column with a total must reconcile
|
||||
# (NII + gains + ROC == total). Catches rows that leaked in from
|
||||
# the operations section or prose ("...capital gains of $3.00...").
|
||||
if tot:
|
||||
for c in range(ncols):
|
||||
t = tot[c] if c < len(tot) else None
|
||||
if t is None:
|
||||
continue
|
||||
s = _get(nii, c) + _get(gains, c) + (roc[c] if c < len(roc) else 0.0)
|
||||
if abs(s - t) > 0.011 * max(1.0, abs(t)) + 0.005:
|
||||
return None
|
||||
return {"nii": nii, "gains": gains, "roc": roc, "tot": tot,
|
||||
"nav": nav, "ncols": ncols}
|
||||
|
||||
|
||||
def parse_highlights(txt: str, nav_now: float | None = None) -> dict | None:
|
||||
"""Extract the per-share distribution table for ONE fund.
|
||||
|
||||
Anchors = 'distributions from / declared to / to shareholders' lines
|
||||
immediately followed by 'net investment income' (the per-share
|
||||
table, not the dollar-basis statement). Family annual reports
|
||||
carry one table PER FUND (NexPoint's report has three) - when the
|
||||
fund's current NAV is known, pick the table whose end-of-year NAV
|
||||
is closest to it; otherwise the first.
|
||||
"""
|
||||
txt = re.sub(r"\s+", " ", txt)
|
||||
tables: list[dict] = []
|
||||
for m in re.finditer(
|
||||
r"distributions (?:declared )?(?:from|to shareholders)",
|
||||
txt, re.I):
|
||||
if not re.search(r"net investment income",
|
||||
txt[m.end(): m.end() + 300], re.I):
|
||||
continue
|
||||
t = _parse_table(txt[m.start(): m.start() + 3000])
|
||||
if t:
|
||||
tables.append(t)
|
||||
if not tables:
|
||||
return None
|
||||
if nav_now:
|
||||
def navdist(t: dict) -> float:
|
||||
v = t["nav"][0] if t["nav"] and t["nav"][0] else None
|
||||
return abs(v - nav_now) / nav_now if v else 99.0
|
||||
tables.sort(key=navdist)
|
||||
if navdist(tables[0]) > 0.15:
|
||||
return None # no table matches this fund's NAV
|
||||
return tables[0]
|
||||
|
||||
|
||||
def roc_share(h: dict) -> float | None:
|
||||
tot = sum(v or 0 for v in h["tot"])
|
||||
if not tot:
|
||||
return None
|
||||
return sum(v or 0 for v in h["roc"]) / tot
|
||||
|
||||
|
||||
def _nav_now(sym: str) -> float | None:
|
||||
"""Latest raw NAV from the price file (to disambiguate family
|
||||
reports that carry one per-share table per fund)."""
|
||||
try:
|
||||
import pandas as pd
|
||||
p = Path.home() / "prog" / "fin" / "stocks" / f"{sym.lower()}-history.csv"
|
||||
d = pd.read_csv(p, parse_dates=["Date"])
|
||||
c = d["Close"].dropna()
|
||||
return float(c.iloc[-1]) if len(c) else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def detect(sym: str, force: bool = False) -> dict | None:
|
||||
"""Full pipeline for one fund: CIK -> latest N-CSR -> highlights."""
|
||||
CACHE.mkdir(exist_ok=True)
|
||||
cpath = CACHE / f"{sym.lower()}.json"
|
||||
if cpath.exists() and not force:
|
||||
return json.loads(cpath.read_text())
|
||||
tc = edgar.ticker_to_company(sym)
|
||||
if not tc:
|
||||
return {"sym": sym, "error": "CIK not found"}
|
||||
cik, name = tc
|
||||
fil = edgar.cik_recent_filings(cik, "N-CSR", count=1)
|
||||
if not fil:
|
||||
return {"sym": sym, "error": "no N-CSR on file", "cik": cik}
|
||||
f0 = fil[0]
|
||||
txt = edgar.to_text(edgar.sec_get(
|
||||
edgar.doc_url(cik, f0["accession"], f0["doc"]), timeout=120))
|
||||
h = parse_highlights(txt, nav_now=_nav_now(sym))
|
||||
rs = roc_share(h) if h else None
|
||||
out = {
|
||||
"sym": sym, "cik": cik, "trust": name,
|
||||
"filing": f0["filed"],
|
||||
"table": h,
|
||||
"roc_share_5y": (round(rs, 3) if rs is not None else None),
|
||||
"nav_change_5y": (round(h["nav"][0] / h["nav"][-1] - 1, 3)
|
||||
if h and len(h["nav"]) >= 2
|
||||
and h["nav"][0] and h["nav"][-1] else None),
|
||||
}
|
||||
cpath.write_text(json.dumps(out, indent=1))
|
||||
return out
|
||||
|
||||
|
||||
def _default_syms() -> list[str]:
|
||||
dr = json.loads((HERE / "decompose_results.json").read_text())
|
||||
xc = json.loads((HERE / "xcheck_report.json").read_text())
|
||||
return sorted(set(s.upper() for s in dr)
|
||||
| set(s.upper() for s in xc))
|
||||
|
||||
|
||||
def _print(res: dict) -> None:
|
||||
print(f" {'fund':<7} {'ROC 5y':>7} {'NAV 5y':>8} {'dist/yr (most recent first)':<44} filing")
|
||||
for s in sorted(res, key=lambda x: -(res[x].get("roc_share_5y")
|
||||
or -1)):
|
||||
r = res[s]
|
||||
if "error" in r:
|
||||
print(f" {s:<7} ({r['error']})")
|
||||
continue
|
||||
h = r["table"]
|
||||
if not h:
|
||||
print(f" {s:<7} (no per-share table found)")
|
||||
continue
|
||||
yrs = []
|
||||
for i in range(h["ncols"]):
|
||||
t = h["tot"][i] if i < len(h["tot"]) else None
|
||||
ro = h["roc"][i] if i < len(h["roc"]) else None
|
||||
yrs.append(f"tot {t if t is not None else 0:.2f}"
|
||||
+ (f"/roc {ro:.2f}" if ro else ""))
|
||||
rc = r.get("roc_share_5y")
|
||||
nv = r.get("nav_change_5y")
|
||||
print(f" {s:<7} {(f'{rc*100:5.1f}%' if rc is not None else ' -'):>7} "
|
||||
f"{(f'{nv*100:+6.1f}%' if nv is not None else ' -'):>8} "
|
||||
f"{' '.join(yrs)[:44]:<44} {r['filing']}")
|
||||
|
||||
|
||||
def run(syms: list[str] | None = None, force: bool = False) -> dict:
|
||||
syms = syms or _default_syms()
|
||||
res: dict = {}
|
||||
for s in syms:
|
||||
for attempt in range(3):
|
||||
try:
|
||||
r = detect(s, force=force)
|
||||
break
|
||||
except Exception as e: # SEC 503/429 throttling - back off
|
||||
if attempt == 2:
|
||||
r = {"sym": s, "error": f"{type(e).__name__}: {e}"}
|
||||
else:
|
||||
time.sleep(15 * (attempt + 1))
|
||||
r = None
|
||||
if r:
|
||||
res[s.upper()] = r
|
||||
time.sleep(0.5)
|
||||
RESULTS.write_text(json.dumps(res, indent=1))
|
||||
_print(res)
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
args = [a for a in sys.argv[1:] if a != "--force"]
|
||||
run(args or None, force="--force" in sys.argv)
|
||||
Loading…
Reference in New Issue
Block a user