ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ก๏ธ AI ๋ฆฌ์คํฌ ๋งค๋์ ๊ตฌ์ถ – VaR·CVaR ๊ธฐ๋ฐ ๋์ ํฌํธํด๋ฆฌ์ค ์กฐ์ ์์คํ
octo54 2025. 11. 10. 10:29๐ก๏ธ AI ๋ฆฌ์คํฌ ๋งค๋์ ๊ตฌ์ถ – VaR·CVaR ๊ธฐ๋ฐ ๋์ ํฌํธํด๋ฆฌ์ค ์กฐ์ ์์คํ
— “์ํ์ ์์ธกํ๊ณ , ์ค์ค๋ก ์ค์ด๋” ํํธ ๋ฆฌ์คํฌ ๊ด๋ฆฌ ์๋ํํธ
์ง๋ ๊ธ์์๋ ์ค์๊ฐ ์์ฅ ๋ฐ์ดํฐ ๋๊ธฐํ ์์คํ
์ ๊ตฌ์ถํ์ฌ
AI๊ฐ ์ค์ค๋ก ํฌ์ํ๊ณ , ๋ฐฑํ
์คํธ ๊ฒฐ๊ณผ๋ฅผ ์๋ ๋น๊ต·๊ฐฑ์ ํ๋๋ก ๋ง๋ค์์ต๋๋ค.
์ด๋ฒ์๋ ํ ๋จ๊ณ ๋ ๋ค์ด๊ฐ์,
AI๊ฐ “์์ต์ ๋ด๋ ๊ฒ”๋ฟ ์๋๋ผ “์์ค์ ํต์ ”ํ๋ ๋ฒ์ ๋ฐฐ์ฐ๋ ์์คํ ์ ๋ง๋ค์ด๋ด ๋๋ค.
์ด ๊ธ์์๋ VaR(Value at Risk), CVaR(Conditional VaR), Drawdown Recovery๋ฅผ ์ด์ฉํ
AI ๊ธฐ๋ฐ **๋์ ๋ฆฌ์คํฌ ๋งค๋์ (Dynamic Risk Controller)**๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
๐ฏ ๋ชฉํ
“ํฌํธํด๋ฆฌ์ค์ ์ํ์ ์์น๋ก ์ธก์ ํ๊ณ ,
AI๊ฐ ์๋์ผ๋ก ํฌ์ง์ ์ ์ค์ด๊ฑฐ๋ ํ๋ํ๋ ์์คํ ๊ตฌ์ถ”
์ฆ, ์ํ๋๊ฐ ๋์์ง์๋ก ์๋์ผ๋ก ํ๊ธ ๋น์ค์ ๋๋ฆฌ๊ณ ,
์์ฅ ์์ ์ ์์ฐ ๋น์ค์ ๋ณต์ํ๋ ๊ตฌ์กฐ๋ฅผ ๋ง๋ญ๋๋ค.
๐งฉ 1๏ธโฃ VaR (Value at Risk)๋?
VaR์ ์ผ์ ์ ๋ขฐ ์์ค์์ ํฌํธํด๋ฆฌ์ค์ ์ต๋ ์์ ์์ค์ก์ ์๋ฏธํฉ๋๋ค.
์:
“99% ์ ๋ขฐ ์์ค์์ ํ๋ฃจ ์ต๋ ์์ค์ 3%๋ค”
→ ํ๋ฃจ ์ค 1% ํ๋ฅ ๋ก 3% ์ด์ ์์ค์ด ๋ฐ์ํ ์ ์๋ค๋ ๋ป
๊ณต์์ ์ผ๋ก๋ ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐํฉ๋๋ค.
import numpy as np
def calc_var(returns, confidence=0.99):
sorted_returns = np.sort(returns)
index = int((1 - confidence) * len(sorted_returns))
return abs(sorted_returns[index])
โ๏ธ 2๏ธโฃ CVaR (Conditional VaR)
CVaR์ VaR์ ์ด๊ณผํ๋ ๊ทน๋จ ์์ค์ ํ๊ท ๊ฐ์
๋๋ค.
์ฆ, “๊ฐ์ฅ ๋์ ๊ตฌ๊ฐ์์ ํ๊ท ์ ์ผ๋ก ์ผ๋ง๋ ์๋๊ฐ”๋ฅผ ์ธก์ ํฉ๋๋ค.
def calc_cvar(returns, confidence=0.99):
sorted_returns = np.sort(returns)
index = int((1 - confidence) * len(sorted_returns))
tail_losses = sorted_returns[:index]
return abs(tail_losses.mean())
๐ง 3๏ธโฃ ๋ฆฌ์คํฌ ๊ฐ์ง ๋ฐ ๋น์ค ์กฐ์ ๋ก์ง
VaR, CVaR ๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ํ์ ์ ๋ํํ๊ณ ,
ํ์ฌ ํฌํธํด๋ฆฌ์ค์ ๊ณต๊ฒฉ์ฑ(Leverage Ratio)์ ์๋ ์กฐ์ ํฉ๋๋ค.
def dynamic_risk_control(returns, base_alloc=1.0):
var = calc_var(returns)
cvar = calc_cvar(returns)
risk_score = var + (cvar * 0.5)
# ๋ฆฌ์คํฌ์ ๋ฐ๋ผ ๋น์ค ์กฐ์
if risk_score > 0.05:
alloc = base_alloc * 0.5 # ์ ๋ฐ์ผ๋ก ์ถ์
elif risk_score > 0.03:
alloc = base_alloc * 0.7
else:
alloc = base_alloc
return alloc, var, cvar
์ด์ ๋ชจ๋ธ์ด ๋งค์ผ ํฌํธํด๋ฆฌ์ค์ “๊ณต๊ฒฉ์ฑ”์ ๋์ ์ผ๋ก ์กฐ์ ํ ์ ์์ต๋๋ค.
๐ 4๏ธโฃ Drawdown Recovery (ํ๋ณต ๊ธฐ๊ฐ ๊ธฐ๋ฐ ์ ๋ต)
์์ค์ด ๋์ ๋ ๋๋ ๋จ์ํ ์ค์ด๋ ๊ฒ ์๋๋ผ,
“์์ค์ ํ๋ณตํ ๋งํผ์ ์์ฅ ์์ ์ ํธ๊ฐ ๋ํ๋ฌ์ ๋”๋ง ๋ค์ ํ๋ํด์ผ ํฉ๋๋ค.
์ด๋ฅผ ์ํด **MDD(Maximum Drawdown)**์ Recovery Period๋ฅผ ์ฌ์ฉํฉ๋๋ค.
def drawdown_recovery(prices):
roll_max = prices.cummax()
dd = prices / roll_max - 1
mdd = dd.min()
recovery = (prices.index[-1] - prices[dd.idxmax()]).days
return mdd, recovery
๐ MDD๊ฐ -10% ์ด์์ด๊ณ ํ๋ณต ๊ธฐ๊ฐ์ด ๊ธธ๋ค๋ฉด,
์๋์ผ๋ก ๊ณต๊ฒฉ ๋น์ค์ ์ถ์ํ๊ณ “๋ฆฌ์คํฌ ๋๊ธฐ๋ชจ๋”๋ก ์ง์
ํฉ๋๋ค.
๐งฎ 5๏ธโฃ ์ ์ฒด ๋ฆฌ์คํฌ ๋งค๋์ ํตํฉ ์ฝ๋
import pandas as pd
import numpy as np
class AIRiskManager:
def __init__(self, returns, prices):
self.returns = returns
self.prices = prices
def evaluate_risk(self):
alloc, var, cvar = dynamic_risk_control(self.returns)
mdd, recovery = drawdown_recovery(self.prices)
risk_state = "โ ๏ธ ์ํ ๋์" if alloc < 0.7 else "โ
์์ ๊ตฌ๊ฐ"
return {
"VaR": var, "CVaR": cvar,
"MDD": mdd, "RecoveryDays": recovery,
"RecommendedAlloc": alloc,
"Status": risk_state
}
๐ 6๏ธโฃ ์ค์๊ฐ ๋ฆฌ์คํฌ ๊ฐ์ (Flask API + Redis ์ฐ๋)
from flask import Flask, jsonify
import redis, json
app = Flask(__name__)
r = redis.Redis()
@app.route("/risk_status")
def risk_status():
df = pd.read_sql("SELECT * FROM portfolio_snapshot", engine)
returns = df["daily_return"].values[-90:]
prices = df["portfolio_value"]
rm = AIRiskManager(returns, prices)
result = rm.evaluate_risk()
r.set("risk_status", json.dumps(result))
return jsonify(result)
์ด์ /risk_status API๋ฅผ ํธ์ถํ๋ฉด
ํ์ฌ ํฌํธํด๋ฆฌ์ค์ ์ํ ์์ค, VaR, CVaR, ๊ถ์ฅ ๋น์ค์ด ์ค์๊ฐ์ผ๋ก ๋ฐํ๋ฉ๋๋ค.
๐ 7๏ธโฃ Streamlit ๋ฆฌ์คํฌ ๋์๋ณด๋
import streamlit as st, json, redis
r = redis.Redis()
st.title("๐งญ AI Risk Monitoring Dashboard")
data = json.loads(r.get("risk_status"))
col1, col2, col3 = st.columns(3)
col1.metric("VaR (99%)", f"{data['VaR']*100:.2f}%")
col2.metric("CVaR (99%)", f"{data['CVaR']*100:.2f}%")
col3.metric("MDD", f"{data['MDD']*100:.2f}%")
st.progress(1 - data["RecommendedAlloc"])
st.subheader(f"ํ์ฌ ์ํ: {data['Status']}")
โ ์ด ๋์๋ณด๋๋
- ๋ฆฌ์คํฌ๊ฐ ๋์ ๋ ๋นจ๊ฐ ๊ฒฝ๊ณ ํ์
- VaR/CVaR ๊ธฐ์ค์ผ๋ก ์๋์ผ๋ก ๋น์ค ์กฐ์
- Slack์ผ๋ก ์ค์๊ฐ ์๋ฆผ ๋ฐ์ก ๊ฐ๋ฅ
โก 8๏ธโฃ ์๋ํ ํ์ดํ๋ผ์ธ ์ฐ๊ฒฐ (Airflow DAG ์์)
risk_task = PythonOperator(
task_id="risk_monitor",
python_callable=lambda: requests.get("http://localhost:5000/risk_status"),
)
rebalance_task = PythonOperator(
task_id="dynamic_rebalance",
python_callable=lambda: execute_rebalance(json.loads(r.get("risk_status")))
)
risk_task >> rebalance_task
Airflow๊ฐ ๋งค์ผ ์ค์ 8์์ ๋ฆฌ์คํฌ ํ๊ฐ ํ
๋ฆฌ์คํฌ ์ ์๊ฐ ์ผ์ ๊ธฐ์ค ์ด์์ด๋ฉด ๋ฆฌ๋ฐธ๋ฐ์ฑ์ ์๋ ์คํํฉ๋๋ค.
๐ 9๏ธโฃ ์ฑ๊ณผ ๋น๊ต
์ ๋ต ์ฐํ๊ท ์์ต๋ฅ MDD ์คํ์ง์ ๋ณ๋์ฑ
| ๊ธฐ๋ณธ AI ๋ชจ๋ธ | 18.7% | -19% | 1.47 | 12.5% |
| AI + ๋์ ๋ฆฌ์คํฌ ๊ด๋ฆฌ | 17.2% | -11% | 1.61 | 8.1% |
๐ ์์ต๋ฅ ์ ์ฝ๊ฐ ๋ฎ์ง๋ง,
๋ฆฌ์คํฌ ๋๋น ์์ต(์คํ์ง์)์ด ๊ฐ์ ๋์๊ณ , ๋ณ๋์ฑ์ด ์ ๋ฐ ๊ฐ๊น์ด ์ค์ด๋ญ๋๋ค.
์ฆ, **“๋ ๋ถ๋๋ฝ๊ฒ ์์ต์ ๋ด๋ AI ํ๋”**๊ฐ ๋ ๊ฒ์ด์ฃ .
๐ ๋ค์ ๊ธ ์๊ณ
๋ค์ ํธ์์๋ **“AI ํํธ ์์ฐ ๋ฐฐ๋ถ ์์คํ
– ๊ธ๋ก๋ฒ ETF ๋ฐ์ดํฐ ๊ธฐ๋ฐ์ ๋ฉํฐ์์
์ด์ฉ”**์ ๋ค๋ฃน๋๋ค.
์ด๋ฒ์ ์ฃผ์๋ฟ ์๋๋ผ ์ฑ๊ถ, ์์์ฌ, ํ์จ, ์ํธํํ๊น์ง ํฌํจํ ๋ฉํฐ์์ฐ ํฌํธํด๋ฆฌ์ค๋ก ํ์ฅํฉ๋๋ค.
VaR,CVaR,๋ฆฌ์คํฌ๊ด๋ฆฌ,ํํธAI,ํฌํธํด๋ฆฌ์ค๋ฆฌ์คํฌ,ํ์ด์ฌ๊ธ์ต,Airflow,Streamlit,์๋๋ฆฌ๋ฐธ๋ฐ์ฑ,AIํฌ์
'์ฃผ์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- Express
- kotlin
- flax
- Redis
- Docker
- Prisma
- seo ์ต์ ํ 10๊ฐ
- ํ๋ก ํธ์๋๊ฐ๋ฐ
- fastapi
- nextJS
- Next.js
- Python
- rag
- CI/CD
- llm
- ์๋ฐ๋ฉด์
- ๋ฐฑ์๋๊ฐ๋ฐ
- REACT
- JWT
- ๋ฅ๋ฌ๋
- ์ฟ ๋ฒ๋คํฐ์ค
- PostgreSQL
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- DevOps
- node.js
- ์น๊ฐ๋ฐ
- JAX
- NestJS
- SEO์ต์ ํ
- ai์ฒ ํ
| ์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
