REIT 분기 portfolio benchmark
운용 자산 portfolio 의 자산별 vs 시장 median premium/discount 를 자동 계산. Python 노트북 한 번 실행으로 분기 보고서 / IC report 에 들어갈 표 + 차트가 완성됩니다.
When to use this
언제 쓰나
분기말 운용 보고서 / 위탁자 보고서 / IC review 작성 시 portfolio 자산이 시장 평균 대비 어디 위치하는지 보여줘야 합니다. 자체 자산 가격은 운용사 내부 valuation 모델에서 나오지만, 비교 baseline 인 시장 median 은 외부 source 가 필요. JLL/CBRE 보고서는 license-restricted PDF, 한국부동산원 R-ONE 은 권역 인덱스 (자산 매핑 어려움).
Veacon API 는 sigungu_code × property_type × transaction_type × period 단위로 RTMS-grade aggregate 를 즉시 제공. 자체 자산 list 를 for-loop 로 돌려 자산별 cohort 를 매핑하면 portfolio 전체의 market benchmark 가 나옵니다. pandas DataFrame 으로 join 하면 Excel 출력 + 차트까지 한 번에.
What you'll get
결과물
- 자산별 행 + (자체 valuation, market median, premium %, confidence, source_mix) 컬럼이 들어간 DataFrame
- Portfolio-level 가중평균 premium (자산 평형 기준 weighted)
- confidence=high 자산 vs low 자산 분리 차트. 어느 자산은 신뢰 가능한 비교, 어느 자산은 sample 부족인지 명확
- Excel export ready · 분기 보고서 첨부 양식
- 분기 자동화: 같은 노트북 다음 분기에 그대로 재실행
Workflow
5-step recipe
환경 셋업
Python 3.10+, pandas, requests, matplotlib. Veacon API key 는 환경 변수로.
pip install pandas requests matplotlib
export VEACON_API_KEY=veacon_pk_...Portfolio 정의
운용 자산 list 를 CSV (asset_name, sigungu_code, property_type, transaction_type, internal_valuation_krw, area_m2) 로 준비. Excel 에서 export 가능.
asset_name,sigungu_code,property_type,transaction_type,internal_valuation_krw,area_m2
강남파이낸스 (역삼),11680,office,sale,4500000000,250
영등포 IFC,11560,office,sale,4200000000,280
명동 retail flagship,11140,retail,sale,8500000000,180시장 데이터 fetch (per-asset loop)
자산별로 Veacon pulse 호출. property_type + transaction_type + sigungu_code 매칭. period 는 last_3m (분기 보고서) 또는 YYYY-Q1 (특정 분기) 사용.
import os, requests, pandas as pd
API_KEY = os.environ['VEACON_API_KEY']
BASE = 'https://veacon.io/api/v1/real-estate/pulse'
portfolio = pd.read_csv('portfolio.csv')
def fetch_market(row):
r = requests.get(BASE, headers={'X-API-Key': API_KEY}, params={
'sigungu_code': row['sigungu_code'],
'property_type': row['property_type'],
'transaction_type': row['transaction_type'],
'period': 'last_3m',
'geo_precision': 'sigungu',
})
if r.status_code == 404:
return {'sample_count': 0, 'median_price': None, 'confidence': None}
body = r.json()['data'][0]
return {
'sample_count': body['sample_count'],
'median_price': body['median_price'],
'p25_price': body['p25_price'],
'p75_price': body['p75_price'],
'confidence': body['confidence'],
'source_mix': body['source_mix'],
}
market = portfolio.apply(fetch_market, axis=1, result_type='expand')
df = pd.concat([portfolio, market], axis=1)Premium 계산 + roll-up
자산별 premium = (자체 valuation - market median) / market median. Portfolio-level 은 면적 기준 가중평균.
df['premium_pct'] = (
(df['internal_valuation_krw'] - df['median_price']) / df['median_price']
)
# 면적 기준 가중평균
total_area = df['area_m2'].sum()
df['weight'] = df['area_m2'] / total_area
portfolio_premium = (df['premium_pct'] * df['weight']).sum()
print(f"Portfolio weighted premium: {portfolio_premium:+.1%}")
print(f" high-confidence assets: {(df['confidence']=='high').sum()}")
print(f" low-confidence assets: {(df['confidence']=='low').sum()}")Excel export + 차트
xlsxwriter 또는 openpyxl 로 Excel 출력. 시각화는 matplotlib bar chart (자산별 premium bar) + confidence-색상 분리.
분기 자동화: CSV 에 자산만 추가하면 같은 노트북 재실행. 다음 분기에는 5분.
# Excel export
with pd.ExcelWriter('portfolio-benchmark-2026Q1.xlsx', engine='xlsxwriter') as w:
df.to_excel(w, sheet_name='Detail', index=False)
summary = pd.DataFrame([{
'as_of': pd.Timestamp.utcnow().date(),
'portfolio_size': len(df),
'weighted_premium_pct': portfolio_premium,
'high_conf_count': (df['confidence'] == 'high').sum(),
'low_conf_count': (df['confidence'] == 'low').sum(),
}])
summary.to_excel(w, sheet_name='Summary', index=False)
# Chart
import matplotlib.pyplot as plt
colors = df['confidence'].map({'high':'#10b981','medium':'#f59e0b','low':'#ef4444'})
df.plot.bar(x='asset_name', y='premium_pct', color=colors, figsize=(10,5),
title=f'Portfolio premium vs market (weighted: {portfolio_premium:+.1%})')
plt.axhline(0, color='black', linewidth=0.5)
plt.tight_layout()
plt.savefig('portfolio-benchmark-chart.png', dpi=150)Caveats
알아두실 사항
- Rate limit: Pro tier 60 req/min, Team 200 req/min. Portfolio 20개 자산 = 한 번에 fetch 가능. 100개 자산 portfolio 는 분당 분할 또는 Team tier 권장.
- 404 처리: 매칭 cohort 가 없으면 endpoint 가 404 + envelope 반환. Python 코드에서 graceful fallback (median=NaN) 처리. NaN 자산은 portfolio 가중평균에서 제외.
- 자체 valuation 정의 일관성: Premium 계산이 의미 있으려면 internal_valuation_krw 가 sale 가격 기준이어야 함 (장부가 X). REIT 분기말 valuation 사용 권장.
- confidence 가 low 인 자산 은 별도 표 또는 회색 처리. 분기 보고서 첨부 시 위탁자가 신뢰도 의문 제기 가능. 미리 footnote.
- RTMS coverage 는 실제 거래의 약 40-60%. R-ONE + 공시지가 cross-reference 가 confidence 점수에 반영됩니다 (Phase 1.5 라이브).상세.
