ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐Ÿ›ก๏ธ 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
๋งํฌ
ยซ   2026/02   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
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
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•