AXCS provides preferred equity and rescue capital. In the Austin metro, find market-rate properties of 150+ units built 2000 or later that last sold between mid-2021 and September 2022, with the sale price per unit. For each, show in-place rent change over 12 months, current occupancy, and days on market versus its submarket. Rank them by likelihood that the owner faces a refinancing gap today.
"""Refi-gap screen: Austin MF, 150+ units, built 2000+, last sold Jul-2021..Sep-2022 with a recorded price.
Inputs are copied from RealAI Datamart query results (property_mfr, submarket, market caprate_ts,
market mf_pnl_benchmarks, mortgage_rates). Assumptions are labeled and editable at the top.
"""
import json
# ---------------- Assumptions (editable) ----------------
ACQ_LTV = 0.65 # assumed acquisition loan-to-price (2021-22 vintage), interest-only, no paydown
CAP_TODAY = 0.0490 # Green Street Austin MF cap rate, 2Q26
MKT_OTHER_INC = 0.1290 # Austin other income % of net rent (mf_pnl_benchmarks)
MKT_NOI_MARGIN = 0.4511 # Austin NOI % of EGI (mf_pnl_benchmarks)
# Refi tiers (Freddie CME fixed, 10-yr, 30-yr amort): (LTV max, rate, DSCR min)
TIERS = [(0.65, 0.0606, 1.35), (0.80, 0.0618, 1.25)]
AMORT_YRS = 30
CAP_AT_SALE = {"3Q21": 0.0354, "4Q21": 0.0343, "1Q22": 0.0358, "2Q22": 0.0389, "3Q22": 0.0398}
def quarter(d):
y, m = int(d[:4]), int(d[5:7])
return f"{(m-1)//3+1}Q{str(y)[2:]}"
def constant(r, yrs=AMORT_YRS):
i = r / 12; n = yrs * 12
return 12 * i / (1 - (1 + i) ** -n)
# ---------------- Submarket benchmarks ----------------
SUB = { # id: (name, in-place t12 median chg, occupancy, DOM median)
"716dd44f13f312a4817bbd9423eb3dfe": ("East Central Austin", -0.0353, 0.9260, 63),
"ab4b9968f16b41e70abdec1dadf0974d": ("Far West Blvd", -0.0458, 0.9465, 63),
"bb42723f5a02e4599a1fbd332212f610": ("Round Rock - south", -0.0191, 0.9253, 72),
"6181e5d5b72e4069a7e1d2e65ec08c92": ("Pershing", -0.0268, 0.9131, 72),
"4c7e9a0dd70046840796fcbd67aaaaa0": ("Georgetown - west", -0.0296, 0.9290, 69),
"762e3ab64c7c40341b840a79defcfb9c": ("Cedar Park", -0.0277, 0.9315, 66),
"91823b937bfddb257636785e0ee3a381": ("Walnut Forest", -0.0620, 0.9105, 72),
"d2f950a35ddc82a91e1bd462fb2f0909": ("Round Rock - east", -0.0255, 0.9233, 66),
"fd7bdff3b0991efa1a43d110b35480b0": ("San Marcos/Kyle", -0.0360, 0.9156, 88),
"8acfa38b5a1b4de4c7126d7c954edfa6": ("Brushy Creek", -0.0426, 0.9592, 63),
"8d4dfbd44021ad3126e424824bb3c73b": ("Downtown - south", -0.0539, 0.9532, 67),
}
# ---------------- Properties ----------------
# name, id, submarket, units, yr built, sale date, price, ppu, rent_type,
# in-place avg, in-place t12 median chg, occ, DOM, property NOI margin (None -> market), notes
P = [
("Bell South Shore","b0f5b109f9cf11e435983afc757f4cf3","716dd44f13f312a4817bbd9423eb3dfe",506,2013,"2022-06-09",177156000,350110.67,"MARKET",1955.76,0.0076,0.9506,99,None,""),
("Nalle Woods of Westlake","5618a6580fbbe9ac55b4d5f9bdca9a83","ab4b9968f16b41e70abdec1dadf0974d",238,2003,"2021-07-01",67500000,283613.45,"MARKET",2255.42,-0.0133,0.9496,92,None,""),
("Preserve at Rolling Oaks","2dd0fe6fd999ebf09aa45058e347536b","bb42723f5a02e4599a1fbd332212f610",494,2001,"2022-09-29",137283930,277902.69,"MARKET_AND_AFFORDABLE",1497.22,-0.0221,0.9190,60,0.6157,"Fee owner: Housing Authority of the City of Austin (PFC structure)"),
("Nexus East","cfa587bca572237b50bea121bab99440","6181e5d5b72e4069a7e1d2e65ec08c92",352,2021,"2021-11-22",86875000,246803.98,"MARKET_AND_AFFORDABLE",1565.90,-0.0538,0.9659,152,None,"Bought in lease-up; 57% rent sample coverage"),
("The Summit at Rivery Park","617eace508a346d397fac87ddcde9432","4c7e9a0dd70046840796fcbd67aaaaa0",228,2015,"2022-01-24",51138500,224291.67,"MARKET",1272.60,-0.0245,0.9211,87,None,"56% rent sample coverage"),
("Vera Cedar Park","cd067f2bf9b135a7c42cdd701d10d3df","762e3ab64c7c40341b840a79defcfb9c",242,2022,"2021-12-17",52485125,216880.68,"MARKET",1710.31,-0.0086,0.8430,117,None,"Bought pre-completion"),
("The Reserve at Walnut Creek","0fcfa1dfbda9297a603f4a3f9641cb89","91823b937bfddb257636785e0ee3a381",284,2002,"2022-04-01",59388605,209114.81,"MARKET",1348.63,-0.0493,0.8345,103,None,""),
("Reveal 54","af7af01ac22d70a8fd77d5e857409e70","d2f950a35ddc82a91e1bd462fb2f0909",418,2019,"2021-09-29",85312500,204096.89,"MARKET",1603.83,-0.0313,0.8995,55,0.48,""),
("Palm Valley Apartments","b7ff9ca206175cb45c77cd650e7c51b8","d2f950a35ddc82a91e1bd462fb2f0909",340,2008,"2022-01-14",67250984,197797.01,"MARKET",1255.50,-0.0269,0.9235,48,0.4037,""),
("Ventana at Plum Creek","c8cd2636b6b06a15637962ee2daad3ba","fd7bdff3b0991efa1a43d110b35480b0",180,2018,"2022-02-28",32867700,182598.33,"MARKET",1355.80,-0.0185,0.9667,217,0.4101,"DOM on few leases (9 unleased units)"),
("Lakeline Parmer Lane Apartments","a6b7c5415c2a024dca145a2146518128","8acfa38b5a1b4de4c7126d7c954edfa6",312,2000,"2021-09-15",35000000,112179.49,"MARKET",1169.36,0.0336,0.9135,14,0.3659,"Reported NOI $1.78M used"),
]
LAKELINE_NOI = 1780164.45 # mf_pnl_net_operating_income
recs = []
for (n, pid, sm, u, yb, sd, price, ppu, rt, ipr, ipchg, occ, dom, margin, note) in P:
smn, s_chg, s_occ, s_dom = SUB[sm]
q = quarter(sd)
net_rent = ipr * u * occ * 12
egi = net_rent * (1 + MKT_OTHER_INC)
m = margin if margin is not None else MKT_NOI_MARGIN
noi = LAKELINE_NOI if pid == "a6b7c5415c2a024dca145a2146518128" else egi * m
value = noi / CAP_TODAY
loan = price * ACQ_LTV
proceeds = max(min(ltv * value, noi / (dscr * constant(r))) for ltv, r, dscr in TIERS)
gap = loan - proceeds
recs.append(dict(
entity=n, id=pid, submarket=smn, units=u, year_built=yb, sale_date=sd, sale_qtr=q,
sale_price=price, price_per_unit=ppu, rent_type=rt, note=note,
cap_at_sale=CAP_AT_SALE[q], implied_noi_at_sale=price * CAP_AT_SALE[q],
in_place_rent=ipr, in_place_t12=ipchg, sub_in_place_t12=s_chg, rent_vs_sub=ipchg - s_chg,
occupancy=occ, sub_occupancy=s_occ, occ_vs_sub=occ - s_occ,
dom=dom, sub_dom=s_dom, dom_vs_sub=dom - s_dom,
noi_today=noi, noi_margin=m, noi_chg_vs_sale=noi / (price * CAP_AT_SALE[q]) - 1,
value_today=value, value_per_unit=value / u, value_chg=value / price - 1,
est_loan=loan, refi_proceeds=proceeds, refi_gap=gap, gap_per_unit=gap / u,
gap_pct_of_loan=gap / loan,
))
def label(g):
return "Severe" if g >= 0.30 else ("Material" if g >= 0.10 else ("Thin" if g > 0 else "No gap"))
for r in recs:
r["gap_label"] = label(r["gap_pct_of_loan"])
json.dump(recs, open("refi_gap/records.json", "w"), indent=1)
# Sensitivity: gap % of loan at alternative acquisition LTV and cap rate
sens = []
for r in recs:
row = {"entity": r["entity"]}
for ltv in (0.55, 0.65, 0.75):
for cap in (0.049, 0.0525, 0.055):
v = r["noi_today"] / cap
pr = max(min(l * v, r["noi_today"] / (d * constant(rt))) for l, rt, d in TIERS)
row[f"ltv{int(ltv*100)}_cap{cap*100:.2f}"] = round((r["sale_price"] * ltv - pr) / (r["sale_price"] * ltv), 3)
sens.append(row)
json.dump(sens, open("refi_gap/sensitivity.json", "w"), indent=1)
print(f"debt constants: {[round(constant(t[1]),4) for t in TIERS]}")
hdr = f"{'Property':32} {'$/unit':>8} {'Val/u':>8} {'ValChg':>7} {'NOIchg':>7} {'Loan$M':>7} {'Refi$M':>7} {'Gap$M':>7} {'Gap/u':>8} {'Gap%':>6} {'Label':>8}"
print(hdr)
for r in sorted(recs, key=lambda x: -x["gap_pct_of_loan"]):
print(f"{r['entity'][:32]:32} {r['price_per_unit']:8.0f} {r['value_per_unit']:8.0f} {r['value_chg']:7.1%} {r['noi_chg_vs_sale']:7.1%} "
f"{r['est_loan']/1e6:7.1f} {r['refi_proceeds']/1e6:7.1f} {r['refi_gap']/1e6:7.1f} {r['gap_per_unit']:8.0f} {r['gap_pct_of_loan']:6.1%} {r['gap_label']:>8}")
print()
print(f"{'Property':32} {'IPchg':>7} {'SubIP':>7} {'Occ':>6} {'SubOcc':>6} {'dOcc':>6} {'DOM':>4} {'SubDOM':>6} {'dDOM':>5}")
for r in recs:
print(f"{r['entity'][:32]:32} {r['in_place_t12']:7.2%} {r['sub_in_place_t12']:7.2%} {r['occupancy']:6.1%} {r['sub_occupancy']:6.1%} {r['occ_vs_sub']*100:6.1f} {r['dom']:4d} {r['sub_dom']:6d} {r['dom_vs_sub']:5d}")
print()
for s in sens:
print(s["entity"][:28], {k: v for k, v in s.items() if k != "entity"})
cd /vercel/sandbox && python refi_gap/refi_gap_screen.py
Goal: For a preferred-equity / rescue-capital investor, find public evidence of debt distress or recapitalization for 11 Austin-area apartment properties that last sold between July 2021 and September 2022. This feeds a ranking of which owners likely face a refinancing gap today (current date 2026-09-29).
Properties (name — address — last sale date — sale price — recorded fee owner):
For each property, use web_search (and web_fetch where a result looks relevant) to look for: acquisition financing details (lender, loan amount, loan type e.g., floating-rate bridge / agency / CLO, maturity), foreclosure postings or notices of trustee sale, loan modifications/extensions, special servicing or watchlist mentions (CRE CLO, CMBS/Freddie K-deal), recapitalizations, rescue capital, or resale/listing since the 2021-22 purchase. Also confirm the buyer/sponsor name for the 2021-22 sale. Try 2-3 queries per property (e.g., "<name> Austin apartments loan", "<name> foreclosure", "<sponsor> <name> acquisition"). Keep it efficient; do not spend more than ~4 tool calls per property.
Rules: Report only what a source actually says; do not infer loan terms. Flag conflicts. If nothing is found, say "nothing found". Note that Texas is a non-disclosure state and deed of trust details may not be online.
Output: Save a JSON file at subagents/distress_scan/findings.json with one object per property: {name, sponsor_buyer, lender, loan_amount, loan_type, maturity, distress_signals (list of short strings), sources (list of {url, verbatim_quote})}. Return a compact summary table in your final report with the same fields plus the URL and a short verbatim quote for every fact.
Ran targeted web searches (2-4 per property) for public evidence of debt distress, foreclosure, special servicing, recapitalization, or resale activity on 11 Austin-area apartment properties sold 2021-2022. No property returned a confirmed foreclosure notice, special-servicing/watchlist listing, CMBS/CRE-CLO delinquency report, or recapitalization announcement naming that specific asset. Texas's non-disclosure status and the absence of asset-specific trade-press coverage limited what's discoverable online. Full detail with quotes/URLs saved to subagents/distress_scan/findings.json.
Compact summary table:
| Property | Sponsor/Buyer (confirmed) | Lender/Loan/Maturity | Distress Signals | Confidence |
|---|---|---|---|---|
| Bell South Shore | Bell Partners (Bell Fund VII) | nothing found | None found; Bell reported securing normal acquisition financing in 2023 (multifamilydive.com) | Low-med |
| Nalle Woods of Westlake | Morningside Group | nothing found | None found; still under Morningside mgmt | Low |
| Preserve at Rolling Oaks | Housing Authority of Austin (PFC likely) | nothing found | None found; couldn't locate PFC bond docs | Low |
| Nexus East | TMP Airport Blvd Project LLC (buyer name beyond LLC unconfirmed) | nothing found | None found; Newmark confirmed as sale broker (rebusinessonline.com) | Low |
| Summit at Rivery Park | 1400 Rivery Property LLC (unconfirmed) | nothing found | None found | Low |
| Vera Cedar Park | CRP/SRE Cedar Park II Owner LP — possible Carlyle Realty Partners affiliation (unconfirmed, inferred from unrelated BaFin filing naming "CRP/SRE" entities) | nothing found | None found — flagged conflict: sponsor link is speculative | Low |
| Reserve at Walnut Creek | Reserve Walnut Creek Property Owner LLC (unconfirmed) | nothing found | None found; a SEC CLO exhibit and a generic syndication-loss article both mention "Walnut Creek" but do not refer to this Austin asset — explicitly excluded as false positives | L |
cd /vercel/sandbox && S=skills/multi-entity-analysis/scripts/cross_check.py; python $S --check coverage refi_gap/records.json | head -c 600; echo; python $S --check composite --components gap_pct_of_loan,occ_vs_sub,rent_vs_sub,dom_vs_sub --weights 0.55,-0.15,-0.15,0.15 refi_gap/records.json > refi_gap/composite.json; python -c "
import json;d=json.load(open('refi_gap/composite.json'));
[print(i+1,r['entity'],round(r['score'],1),{k:round(v,2) for k,v in r.get('contributions',{}).items()}) for i,r in enumerate(d['ranked'])]"; python $S --check buckets --field gap_label --expected "Severe,Material,Thin,No gap" refi_gap/records.jsoncd /vercel/sandbox && python - <<'EOF'
import re
p='refi_gap/refi_gap_screen.py'; s=open(p).read()
s=s.replace(''' return "Severe" if g >= 0.30 else ("Material" if g >= 0.10 else ("Thin" if g > 0 else "No gap"))''',''' return "Severe" if g >= 0.40 else ("High" if g >= 0.25 else "Moderate")''')
s+='''
# Current debt yield on assumed loan vs debt yield a 1.25x / 6.18% agency refi requires
req_dy = 1.25 * constant(0.0618)
print(f"required debt yield at 1.25x/6.18%: {req_dy:.2%}")
for r in recs:
print(f"{r['entity'][:32]:32} DY on assumed loan {r['noi_today']/r['est_loan']:.2%} NOI ${r['noi_today']/1e6:.2f}M value ${r['value_today']/1e6:.1f}M")
'''
open(p,'w').write(s)
EOF
python refi_gap/refi_gap_screen.py | tail -13
S=skills/multi-entity-analysis/scripts/cross_check.py
python $S --check buckets --field gap_label --expected "Severe,High,Moderate" refi_gap/records.json | tr -d '\n '; echo
python $S --check composite --components gap_pct_of_loan,occ_vs_sub,rent_vs_sub,dom_vs_sub --weights 0.55,-0.15,-0.15,0.15 refi_gap/records.json > refi_gap/composite.json
python - <<'EOF'
import json
d=json.load(open('refi_gap/composite.json')); R={r['entity']:r for r in json.load(open('refi_gap/records.json'))}
for i,x in enumerate(d['ranked']):
r=R[x['entity']]
print(f"{i+1}. {r['entity']} | score {x['score']:.1f} | {r['gap_label']} | ${r['price_per_unit']:,.0f}/u ({r['sale_date']}) | est val ${r['value_per_unit']:,.0f}/u ({r['value_chg']:+.0%}) | gap ${r['refi_gap']/1e6:.1f}M = ${r['gap_per_unit']:,.0f}/u = {r['gap_pct_of_loan']:.0%} of loan | IP t12 {r['in_place_t12']:+.1%} vs {r['sub_in_place_t12']:+.1%} | occ {r['occupancy']:.1%} vs {r['sub_occupancy']:.1%} | DOM {r['dom']} vs {r['sub_dom']}")
EOF
python $S --check extremum --field gap_per_unit --direction max --claim "Bell South Shore" refi_gap/records.json | tr -d '\n '; echo
python $S --check extremum --field occupancy --direction min --claim "The Reserve at Walnut Creek" refi_gap/records.json | tr -d '\n '; echo
python $S --check predicate --field in_place_t12 --op gt --value 0 --claim "Lakeline Parmer Lane Apartments" refi_gap/records.json | tr -d '\n '; echo
python $S --check predicate --field value_chg --op gt --value 0 --claim "Lakeline Parmer Lane Apartments" refi_gap/records.json | tr -d '\n '; echoEleven market-rate or mixed-income deals fit your filters and have both a recorded price and current operating data. Every one of them likely has a refinancing gap today. The problem is interest rates, not asset value. At a 4.90% Austin multifamily cap rate and about 6.2% on 10-year agency debt at 1.25x coverage , a lender needs about a 9.2% debt yield. If the buyers borrowed 65% of the price, these assets earn only 4.9–7.8% on that loan . Debt coverage is what caps the new loan in every case, not loan-to-value, so the result doesn't change unless cap rates rise above about 5.5%.
The debt is an assumption. I can't see the actual loans (Texas doesn't require sale prices or loan terms to be disclosed). I assumed each buyer borrowed 65% of the price, interest-only, with no paydown.
| # | Property (submarket) | Units / built | Sale date · $/unit | Est. value/unit today | Est. gap ($M · % of loan) | In-place rent 12-mo: property vs submarket | Occupancy: property vs submarket | Days on market: property vs submarket |
|---|---|---|---|---|---|---|---|---|
| 1 | Reserve at Walnut Creek (Walnut Forest) | 284 / 2002 | Apr-22 · $209,115 | $140,369 (−33%) | $17.3M · 45% | −4.9% vs −6.2% | 83.5% vs 91.0% | 103 vs 72 |
| 2 | Summit at Rivery Park (Georgetown W) | 228 / 2015 | Jan-22 · $224,292 | $146,201 (−35%) | $15.4M · 46% | −2.5% vs −3.0% | 92.1% vs 92.9% | 87 vs 69 |
| 3 | Palm Valley (Round Rock E) | 340 / 2008 | Jan-22 · $197,797 | $129,417 (−35%) | $20.2M · 46% | −2.7% vs −2.5% | 92.3% vs 92.3% | 48 vs 66 |
| 4 | Bell South Shore (East Central) | 506 / 2013 | Jun-22 · $350,111 | $231,881 (−34%) | $52.4M · 46% | +0.8% vs −3.5% | 95.1% vs 92.6% | 99 vs 63 |
| 5 | Nexus East (Pershing)† | 352 / 2021 | Nov-21 · $246,804 | $188,646 (−24%) | $21.0M · 37% | −5.4% vs −2.7% | 96.6% vs 91.3% | 152 vs 72 |
| 6 | Vera Cedar Park (Cedar Park) | 242 / 2022 | Dec-21 · $216,881 | $179,827 (−17%) | $10.9M · 32% | −0.9% vs −2.8% | 84.3% vs 93.2% | 117 vs 66 |
| 7 | Ventana at Plum Creek (San Marcos/Kyle) | 180 / 2018 | Feb-22 · $182,598 | $148,613 (−19%) | $7.1M · 33% | −1.8% vs −3.6% | 96.7% vs 91.6% | 217 vs 88‡ |
| 8 | Preserve at Rolling Oaks (Round Rock S)† | 494 / 2001 | Sep-22 · $277,903 | $234,234 (−16%) | $27.4M · 31% | −2.2% vs −1.9% | 91.9% vs 92.5% | 60 vs 72 |
| 9 | Reveal 54 (Round Rock E) | 418 / 2019 | Sep-21 · $204,097 | $191,461 (−6%) | $12.7M · 23% | −3.1% vs −2.5% | 90.0% vs 92.3% | 55 vs 66 |
| 10 | Nalle Woods of Westlake (Far West) | 238 / 2003 | Jul-21 · $283,613 | $267,128 (−6%) | $9.9M · 23% | −1.3% vs −4.6% | 95.0% vs 94.7% | 92 vs 63 |
| 11 | Lakeline Parmer Lane (Brushy Creek) | 312 / 2000 | Sep-21 · $112,179 | $116,442 (+4%) | $3.3M · 15% | +3.4% vs −4.3% | 91.3% vs 95.9% | 14 vs 63 |
Sources: sale data ; property rent, occupancy and days on market ; submarket benchmarks ; modeled value, gap and ranking .
† Mixed market and affordable units. ‡ Ventana's days-on-market figure rests on only 9 unleased units.
No public distress was found. Searches turned up no foreclosure notices, special-servicing mentions or recapitalizations tied to any of these 11 properties. The only practical way to see the actual loans is the deed-of-trust records at the Travis, Williamson and Hays county clerks.
If it would help, I can turn this into an Excel model where you can change the assumed borrowing level, rate and cap rate for each property.
This is a read-only snapshot of a RealAI analysis.