ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ผ ์ค์ ํํธ ํ๋ ์ด์ ์์คํ – ๋ฐฑํ ์คํธ์ ์ค์๊ฐ ๊ฑฐ๋ ๋ฐ์ดํฐ ๋๊ธฐํ ๊ตฌ์ถ
octo54 2025. 11. 4. 11:22๐ผ ์ค์ ํํธ ํ๋ ์ด์ ์์คํ – ๋ฐฑํ ์คํธ์ ์ค์๊ฐ ๊ฑฐ๋ ๋ฐ์ดํฐ ๋๊ธฐํ ๊ตฌ์ถ
— AI๊ฐ ์์ธกํ๊ณ , ์ค์๊ฐ ์์ฅ๊ณผ ์ค์ค๋ก ๋๊ธฐํํ๋ ์์ ํ ํธ๋ ์ด๋ฉ ์์ง ๋ง๋ค๊ธฐ
์ง๋ ๊ธ์์ ์ฐ๋ฆฌ๋ Airflow + MLflow ๊ธฐ๋ฐ์ ์์ ์๋ํ๋ AI ํํธ ํ์ดํ๋ผ์ธ์ ์์ฑํ์ต๋๋ค.
์ด์ ๊ทธ ๋ค์ ๋จ๊ณ, ์ฆ **“์ค์ ๊ฑฐ๋ ๋ฐ์ดํฐ์ ๋๊ธฐํ๋๋ ์ค์ ํ๋ ์ด์ฉ ์์คํ
”**์ ๋ง๋ค ์ฐจ๋ก์
๋๋ค.
์ค๋์ ๋ฐฑํ
์คํธ ์์คํ
๊ณผ ์ค์๊ฐ ๊ฑฐ๋ ๋ชจ๋์ ๊ฒฐํฉํด,
AI ๋ชจ๋ธ์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์์ฅ์์ ์ฆ์ ๊ฒ์ฆํ๊ณ ๋ฐ์ํ๋ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
๐ฏ ์ด๋ฒ ๊ธ์ ๋ชฉํ
1๏ธโฃ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ก ๋ฐฑํ ์คํธ ์ํ
2๏ธโฃ ์ค์๊ฐ ์์ธ(REST/WebSocket)์ ์๋ ๋๊ธฐํ
3๏ธโฃ ๋ฐฑํ ์คํธ ↔ ์ค๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ํตํฉ ์ ์ฅ
4๏ธโฃ ์ฑ๊ณผ ๋ฆฌํฌํธ ์๋ ์ ๋ฐ์ดํธ
โ๏ธ 1๏ธโฃ ์์คํ ๊ตฌ์ฑ๋
[ ๋ฐ์ดํฐ ๊ณ์ธต ]
โโโ PostgreSQL (factor, trade_log, live_quotes)
โโโ Redis (์ค์๊ฐ ์บ์)
โโโ S3 (๋ฐฑํ
์คํธ ๊ฒฐ๊ณผ ๋ฐฑ์
)
[ ์ฒ๋ฆฌ ๊ณ์ธต ]
โโโ Transformer + RL Model (์์ธก)
โโโ Backtest Engine (๋ฐฑํ
์คํธ ์๋ฎฌ๋ ์ดํฐ)
โโโ Trade Executor (์ค๊ฑฐ๋ API)
โโโ Sync Engine (์์ฅ ๋ฐ์ดํฐ ๋๊ธฐํ)
[ ๋์๋ณด๋ ]
โโโ Streamlit (์ฑ๊ณผ ๋ฆฌํฌํธ)
โโโ Grafana (์ค์๊ฐ ๋ชจ๋ํฐ๋ง)
๐ 2๏ธโฃ ๋ฐฑํ ์คํธ ์์ง ๊ตฌ์ถ
๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฌํธํด๋ฆฌ์ค ์ ๋ต์ ์ฑ๊ณผ๋ฅผ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค.
import pandas as pd
import numpy as np
class Backtester:
def __init__(self, price_df, signals_df, initial_cash=1_000_000):
self.price_df = price_df
self.signals_df = signals_df
self.cash = initial_cash
self.holdings = {ticker: 0 for ticker in price_df.columns}
self.value_log = []
def run(self):
for date in self.price_df.index:
prices = self.price_df.loc[date]
signals = self.signals_df.loc[date]
# ๋ฆฌ๋ฐธ๋ฐ์ฑ: ๋น์ค ์กฐ์
total_value = self.cash + sum(self.holdings[t]*prices[t] for t in prices.index)
target_value = {t: total_value * signals[t] for t in prices.index}
# ๋งค๋งค ์คํ
for t in prices.index:
diff = target_value[t] - self.holdings[t]*prices[t]
shares = diff / prices[t]
self.holdings[t] += shares
self.cash -= shares * prices[t]
portfolio_value = self.cash + sum(self.holdings[t]*prices[t] for t in prices.index)
self.value_log.append(portfolio_value)
return pd.Series(self.value_log, index=self.price_df.index)
๐ signals_df ๋ Transformer+RL ๋ชจ๋ธ์ ์์ธก ๋น์ค ๊ฒฐ๊ณผ์ ๋๋ค.
๐ง 3๏ธโฃ ์ค์๊ฐ ๊ฑฐ๋ ๋ฐ์ดํฐ ๋๊ธฐํ
์ค์๊ฐ ์์ฅ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๋ถ๋ถ์
๋๋ค.
(๊ตญ๋ด ํ๊ฒฝ์์๋ ํค์ OpenAPI, Upbit API, Alpha Vantage WebSocket ๋ฑ์ ์ฌ์ฉ)
import websocket, json, threading, time, redis
r = redis.Redis(host="localhost", port=6379)
def on_message(ws, message):
data = json.loads(message)
symbol = data["symbol"]
price = data["price"]
timestamp = data["timestamp"]
r.hset("live_quotes", symbol, price)
print(f"[{symbol}] {price} ({timestamp})")
def start_stream():
ws = websocket.WebSocketApp(
"wss://stream.binance.com/ws/btcusdt@trade",
on_message=on_message
)
ws.run_forever()
threading.Thread(target=start_stream, daemon=True).start()
time.sleep(2)
print("โ
์ค์๊ฐ ์์ธ ์คํธ๋ฆผ ์์ ์๋ฃ")
๐ก ์ด ๋ฐ์ดํฐ๋ Redis์ ์ ์ฅ๋์ด Flask API๋ Streamlit ๋์๋ณด๋์์ ์ฆ์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.
๐ 4๏ธโฃ ๋ฐฑํ ์คํธ ↔ ์ค์๊ฐ ๋ฐ์ดํฐ ํตํฉ
import pandas as pd
def sync_backtest_live():
backtest = pd.read_sql("SELECT * FROM backtest_results", con=engine)
live_quotes = {k.decode(): float(v) for k, v in r.hgetall("live_quotes").items()}
merged = backtest.copy()
merged["current_price"] = merged["ticker"].map(live_quotes)
merged["current_pnl"] = (merged["current_price"] - merged["entry_price"]) * merged["quantity"]
merged.to_sql("portfolio_snapshot", engine, if_exists="replace", index=False)
์ด ํจ์๋
๋ฐฑํ
์คํธ ๊ฒฐ๊ณผ + ์ค์๊ฐ ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ํตํฉํ์ฌ
ํ์ฌ ์์ต(PnL), ํ๊ฐ๊ธ์ก, ์์ต๋ฅ ๋ฑ์ ์๋ ๊ณ์ฐํฉ๋๋ค.
๐ 5๏ธโฃ Streamlit ์ค์๊ฐ ์ฑ๊ณผ ๋ฆฌํฌํธ
import streamlit as st
import pandas as pd
from sqlalchemy import create_engine
engine = create_engine("postgresql://quant_user:quant_pass@localhost:5432/quantdb")
st.title("๐ Quant AI Live Performance Dashboard")
df = pd.read_sql("SELECT * FROM portfolio_snapshot", engine)
col1, col2 = st.columns(2)
col1.metric("์ด ํฌ์๊ธ", f"{df['current_price'].sum():,.0f} ์")
col2.metric("ํ๊ท ์์ต๋ฅ ", f"{(df['current_pnl'].sum()/df['entry_price'].sum()):.2%}")
st.line_chart(df.set_index("date")["current_pnl"])
st.dataframe(df)
๐ ์ด Streamlit ๋์๋ณด๋๋ ๋งค์ด ์ ๋ฐ์ดํธ๋๋ ์ค์๊ฐ PnL, ๋์ ์์ต๋ฅ , ํฌํธ ๋น์ค ๋ณํ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
๐งฎ 6๏ธโฃ ์ฑ๊ณผ ๋น๊ต ์๋ ๋ฆฌํฌํธ
๋ฆฌํฌํธ๋ ๋งค์ผ ์๋ ์์ฑ๋์ด MLflow์ ์ ๋ก๋๋ฉ๋๋ค.
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
import datetime
def generate_daily_report():
doc = SimpleDocTemplate(f"reports/quant_{datetime.date.today()}.pdf")
styles = getSampleStyleSheet()
elements = [Paragraph("๐ Daily Quant Report", styles["Title"])]
df = pd.read_sql("SELECT * FROM portfolio_snapshot", engine)
total_return = df["current_pnl"].sum()/df["entry_price"].sum()
elements.append(Paragraph(f"์ด ์์ต๋ฅ : {total_return:.2%}", styles["Normal"]))
doc.build(elements)
print("โ
์ผ์ผ ๋ฆฌํฌํธ ์์ฑ ์๋ฃ")
๐งฐ 7๏ธโฃ Airflow DAG๊ณผ ์ฐ๊ฒฐ
def sync_task():
sync_backtest_live()
generate_daily_report()
requests.post(os.getenv("SLACK_WEBHOOK_URL"), json={"text": "๐ ์ค์๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ ๋ฐ ๋ฆฌํฌํธ ์๋ฃ"})
sync_operator = PythonOperator(
task_id="sync_and_report",
python_callable=sync_task,
)
์ด์ Airflow์์ ๋งค์ผ ์ค์ 9์๋ง๋ค
- ์์ฅ ๋ฐ์ดํฐ ๊ฐฑ์
- PnL ๋๊ธฐํ
- ๋ฆฌํฌํธ ์์ฑ
- Slack ์๋ฆผ
์ด ์๋์ผ๋ก ์คํ๋ฉ๋๋ค.
โ๏ธ 8๏ธโฃ ์ฑ๋ฅ ๊ฒ์ฆ (์ํ ๊ฒฐ๊ณผ)
๊ตฌ๋ถ ์ฐํ๊ท ์์ต๋ฅ MDD ์คํ์ง์ ์๋ํ ๋ ๋ฒจ
| ๋จ์ ๋ฐฑํ ์คํธ | 12.8% | -37% | 0.95 | ์๋ |
| AI ์์ธก + ๋ฆฌ๋ฐธ๋ฐ์ฑ | 15.9% | -26% | 1.22 | ๋ฐ์๋ |
| AI + ์ค์๊ฐ ๋๊ธฐํ ์์คํ | 18.7% | -19% | 1.47 | ์์ ์๋ |
์ค์๊ฐ ์์ฅ ๋ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐํํ์ต ๋ชจ๋ธ์ด ์ค์ค๋ก ํฌํธํด๋ฆฌ์ค๋ฅผ ์กฐ์ ํ๋ฉด์
๋ฆฌ์คํฌ๋ ์ค๊ณ ๋์ ์์ต๋ฅ ์ ๋์ฑ ์์ ์ ์ผ๋ก ์ฆ๊ฐํฉ๋๋ค.
๐ ์ ๋ฆฌ
๊ตฌ์ฑ ์์ ์ญํ
| Backtester | ๊ณผ๊ฑฐ ๋ฐ์ดํฐ ์๋ฎฌ๋ ์ด์ |
| Live Sync | ์ค์๊ฐ ๊ฑฐ๋์ ๋ฐ์ดํฐ ์์ง |
| PostgreSQL + Redis | ์ ์ฅ ๋ฐ ์บ์ฑ |
| Streamlit | ์ค์๊ฐ ์๊ฐํ |
| Airflow | ํ์ดํ๋ผ์ธ ์๋ํ |
| MLflow | ๋ชจ๋ธ ๊ด๋ฆฌ ๋ฐ ๋ฆฌํฌํธ ๋ฒ์ ๊ด๋ฆฌ |
๊ฒฐ๊ณผ์ ์ผ๋ก,
์ด์ AI ๋ชจ๋ธ์ด ๊ณผ๊ฑฐ๋ฅผ ํ์ตํ๊ณ ,
ํ์ฌ ์์ฅ๊ณผ ์ค์๊ฐ์ผ๋ก ์ํธ์์ฉํ๋ฉฐ,
๊ฒฐ๊ณผ๋ฅผ ์ค์ค๋ก ๊ธฐ๋กํ๊ณ ํ๊ฐํ๋ ์์คํ ์ด ์์ฑ๋์์ต๋๋ค.
๐ ๋ค์ ๊ธ ์๊ณ
๋ค์ ํธ์์๋ **“๋ฆฌ์คํฌ ๊ด๋ฆฌ ์๋ํ – VaR, CVaR, ํ๋ณต ๊ธฐ๊ฐ ๊ธฐ๋ฐ์ ๋์ ๋ฆฌ์คํฌ ์ปจํธ๋กค๋ฌ ๊ตฌํ”**์ ๋ค๋ฃน๋๋ค.
์ฆ, ๋ชจ๋ธ์ด ์์ธกํ ์์ฅ ์ํ์ ๋ฐ๋ผ ์๋์ผ๋ก ํฌํธํด๋ฆฌ์ค ๋น์ค์ ์ค์ด๊ฑฐ๋ ํ๋ํ๋
“AI ๋ฆฌ์คํฌ ๋งค๋์ ”๋ฅผ ๋ง๋ค์ด๋ด
๋๋ค.
ํํธํ๋,AIํธ๋ ์ด๋ฉ,๋ฐฑํ ์คํธ,์ค์๊ฐ๋ฐ์ดํฐ,ํ์ด์ฌํธ๋ ์ด๋ฉ,Streamlit,Airflow,Redis,PostgreSQL,ํํธ์๋ํ
'์ฃผ์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- nextJS
- rag
- kotlin
- Next.js
- ๋ฅ๋ฌ๋
- ์ฟ ๋ฒ๋คํฐ์ค
- fastapi
- Redis
- SEO์ต์ ํ
- ํ๋ก ํธ์๋๊ฐ๋ฐ
- ์๋ฐ๋ฉด์
- PostgreSQL
- CI/CD
- Express
- ai์ฒ ํ
- Prisma
- Docker
- ์น๊ฐ๋ฐ
- Python
- DevOps
- JAX
- REACT
- llm
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- flax
- JWT
- node.js
- NestJS
- ๋ฐฑ์๋๊ฐ๋ฐ
- seo ์ต์ ํ 10๊ฐ
| ์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
|---|---|---|---|---|---|---|
| 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 |

