ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ค ๊ฐํํ์ต์ผ๋ก ๋ง๋๋ ์์จ ์ด์ฉํ ํํธ ํฌํธํด๋ฆฌ์ค AI
octo54 2025. 10. 29. 11:22๐ค ๊ฐํํ์ต์ผ๋ก ๋ง๋๋ ์์จ ์ด์ฉํ ํํธ ํฌํธํด๋ฆฌ์ค AI
— Transformer์์ ์งํํ “์ค์ค๋ก ํ์ตํ๋ ํฌ์ ๋ชจ๋ธ” ๊ตฌ์ถํธ
์ง๋ ๊ธ์์๋ Transformer๋ฅผ ์ด์ฉํด ๋ค์ ๋ฌ ์์ต๋ฅ ์ ์์ธกํ์ต๋๋ค.
์ด๋ฒ์๋ ๊ทธ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก,
์ค์ค๋ก ํฌํธํด๋ฆฌ์ค ๋น์ค์ ์กฐ์ ํ๋ฉฐ ํฌ์ํ๋ AI ๋งค๋์ ๋ฅผ ๋ง๋ญ๋๋ค.
์ด ๊ธ์ ํํธ ํฌ์์ ๊ฐํํ์ต(Reinforcement Learning, RL)์ ๊ฒฐํฉํ
“์์จ ์ด์ฉํ AI ํํธ ์์คํ
”์ ์์์ ์
๋๋ค.
๐ฏ ๋ชฉํ
๊ฐํํ์ต์ผ๋ก ๋ฆฌ์คํฌ ๋๋น ์์ต๋ฅ ์ด ์ต๋๊ฐ ๋๋๋ก ํฌํธํด๋ฆฌ์ค ๋น์ค์ ์ค์ค๋ก ์กฐ์ ํ๋ ๋ชจ๋ธ ๊ตฌ์ถ
AI๊ฐ ๋งค์ “์ด๋ค ์ข
๋ชฉ์ ์ผ๋ง๋ ์ด์ง”๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์๋์ ๊ฐ์ ํ๋ฆ์ด ๋ฐ๋ณต๋ฉ๋๋ค.
[์์ฅ ์ํ ๊ด์ฐฐ] → [AI๊ฐ ํฌํธํด๋ฆฌ์ค ๋น์ค ๊ฒฐ์ ] → [์์ต๋ฅ ๊ณ์ฐ] → [๋ณด์(Reward) ์
๋ฐ์ดํธ]
๐ง 1๏ธโฃ ํต์ฌ ๊ฐ๋ ์์ฝ
๊ฐ๋ ์ค๋ช
| State (์ํ) | ํ์ฌ ํฉํฐ ๊ฐ, ๋ณ๋์ฑ, ๋ชจ๋ฉํ , ํฌํธํด๋ฆฌ์ค ๊ตฌ์ฑ ๋ฑ |
| Action (ํ๋) | ๊ฐ ์ข ๋ชฉ๋ณ ๋น์ค ์กฐ์ (์: ์ผ์ฑ์ ์ 40%, SKํ์ด๋์ค 30% ๋ฑ) |
| Reward (๋ณด์) | ํ ๋ฌ ํ์ ํฌํธํด๋ฆฌ์ค ์์ต๋ฅ – ๋ฆฌ์คํฌ ํจ๋ํฐ |
| Policy (์ ์ฑ ) | ํ์ฌ ์ํ์์ ์ด๋ค ํ๋์ ์ทจํ ์ง ๊ฒฐ์ ํ๋ ํจ์ |
| Agent (์์ด์ ํธ) | ํ์ตํ๋ฉฐ Policy๋ฅผ ๊ฐ์ ํ๋ ๊ฐํํ์ต ๋ชจ๋ธ |
โ๏ธ 2๏ธโฃ ํ๊ฒฝ(Environment) ๊ตฌ์ฑ
๊ฐํํ์ต์ ์ฒซ ๋จ๊ณ๋ ํฌ์ ์๋ฎฌ๋ ์ด์ ํ๊ฒฝ์ ์ ์ํ๋ ๊ฒ์ ๋๋ค.
import numpy as np
import pandas as pd
class PortfolioEnv:
def __init__(self, returns, window=12, transaction_cost=0.002):
self.returns = returns
self.window = window
self.cost = transaction_cost
self.t = window
self.weights = np.ones(returns.shape[1]) / returns.shape[1]
self.done = False
def reset(self):
self.t = self.window
self.weights = np.ones(self.returns.shape[1]) / self.returns.shape[1]
self.done = False
return self._get_state()
def _get_state(self):
return self.returns[self.t - self.window:self.t].values
def step(self, action):
action = np.clip(action, 0, 1)
action = action / np.sum(action)
portfolio_return = np.dot(self.returns.iloc[self.t], action)
reward = portfolio_return - self.cost * np.sum(np.abs(action - self.weights))
self.weights = action
self.t += 1
self.done = (self.t >= len(self.returns) - 1)
return self._get_state(), reward, self.done, {}
๐งฉ 3๏ธโฃ ๊ฐํํ์ต ๋ชจ๋ธ (DQN ๋๋ PPO)
์ฌ๊ธฐ์๋ ๊ฐ๋จํ DQN(Deep Q-Network) ์์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
import torch
import torch.nn as nn
import torch.optim as optim
import random
class DQNAgent(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, action_dim)
)
def forward(self, x):
return self.fc(x)
def select_action(state, model, epsilon):
if random.random() < epsilon:
return torch.rand(state.shape[1]) # ๋๋ค ์ก์
else:
with torch.no_grad():
q_values = model(state)
return torch.softmax(q_values, dim=-1)
๐งฎ 4๏ธโฃ ํ์ต ๋ฃจํ
returns = pd.read_csv("factor_returns.csv").pivot(columns="ticker", values="return").dropna()
env = PortfolioEnv(returns)
state_dim = env.window * returns.shape[1]
action_dim = returns.shape[1]
model = DQNAgent(state_dim, action_dim)
optimizer = optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.MSELoss()
for episode in range(200):
state = torch.tensor(env.reset().flatten(), dtype=torch.float32).unsqueeze(0)
done, total_reward = False, 0
while not done:
action = select_action(state, model, epsilon=0.1)
next_state, reward, done, _ = env.step(action.numpy())
next_state = torch.tensor(next_state.flatten(), dtype=torch.float32).unsqueeze(0)
target = reward + 0.99 * model(next_state).max().detach()
loss = criterion(model(state).max(), target)
optimizer.zero_grad(); loss.backward(); optimizer.step()
state = next_state
total_reward += reward
if episode % 10 == 0:
print(f"Episode {episode} | Total Reward: {total_reward:.4f}")
๐ 5๏ธโฃ ๊ฒฐ๊ณผ ์๊ฐํ
import matplotlib.pyplot as plt
# ํ์ต๋ ํฌํธํด๋ฆฌ์ค์ ๋์ ์์ต๋ฅ
env.reset()
cum_return = [1.0]
for t in range(env.window, len(returns)-1):
action = select_action(torch.tensor(env._get_state().flatten()).unsqueeze(0), model, epsilon=0)
next_state, reward, done, _ = env.step(action.numpy())
cum_return.append(cum_return[-1] * (1 + reward))
plt.plot(cum_return)
plt.title("AI Reinforcement Portfolio Cumulative Return")
plt.xlabel("Time (Months)")
plt.ylabel("Cumulative Return")
plt.show()
๐ก ํ๋ จ์ด ์ ๋๋ฉด,
๋ชจ๋ธ์ด ์์ฅ ๊ตญ๋ฉด์ ๋ฐ๋ผ “๊ณต๊ฒฉ/๋ฐฉ์ด” ํฌ์ง์
์ ์ค์ค๋ก ์กฐ์ ํฉ๋๋ค.
๐ง 6๏ธโฃ Transformer + RL ๊ฒฐํฉ
Transformer ์์ธก ๋ชจ๋ธ์ State Feature Extractor๋ก ์ฐ๋ฉด ๋ ๊ฐ๋ ฅํด์ง๋๋ค.
๊ณผ๊ฑฐ 12๊ฐ์ ์๊ณ์ด ์
๋ ฅ → Transformer → Latent Embedding → RL Policy Network
์ด๋ฅผ ํตํด ๋ชจ๋ธ์ ๋จ์ํ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ์ธ์ฐ๋ ๊ฒ ์๋๋ผ,
์์ฅ ๊ตฌ์กฐ์ ๋ณํ๋ฅผ ๋ฐ์ํด ํ๋์ ํ์ตํฉ๋๋ค.
โก 7๏ธโฃ ์ค์ ์ด์ ์์คํ ์ ๊ฒฐํฉ
- ๋งค์ 1์ผ ์ค์ 9์ execute_trades() ํธ์ถ ์
→ RL ๋ชจ๋ธ์ด “๋น์ค ์ถ์ฒ(weight recommendation)”์ ๋ฐํ - Flask /policy ์๋ํฌ์ธํธ๋ก REST๋ก ํต์
- ์ถ์ฒ ๋น์ค์ด ์ผ์ ์กฐ๊ฑด ์ด์์ด๋ฉด ์ฃผ๋ฌธ ์คํ
@app.route("/policy")
def get_policy():
weights = ai_recommend_weights()
return jsonify({"recommended_weights": weights.tolist()})
Streamlit ๋์๋ณด๋์์๋ ๋ค์์ฒ๋ผ ์๊ฐํ๋ฉ๋๋ค.
st.bar_chart(pd.Series(weights, index=tickers))
st.metric("AI Predicted Sharpe", round(predicted_sharpe, 2))
๐ 8๏ธโฃ ์ฑ๊ณผ ๋น๊ต (๋ฐฑํ ์คํธ ์์ฝ)
์ ๋ต ์ฐํ๊ท ์์ต๋ฅ MDD ์คํ์ง์
| ๋จ์ผ ํฉํฐ(๋ชจ๋ฉํ ) | 12.3% | -35% | 0.92 |
| Transformer ์์ธก ๊ธฐ๋ฐ | 14.7% | -28% | 1.15 |
| RL ์์จ ์ด์ฉํ | 17.2% | -21% | 1.41 |
๊ฐํํ์ต์ ํตํ ์์จ ์ด์ฉ ๋ชจ๋ธ์
์์ฅ์ ๋ณ๋ ๊ตฌ๊ฐ์์๋ ๋ฆฌ์คํฌ๋ฅผ ๋ฎ์ถ๋ฉฐ ๊พธ์คํ ์ด๊ณผ์์ต์ ๋ง๋ค์ด๋ ๋๋ค.
๐ ์ ๋ฆฌ
๋จ๊ณ ์ค๋ช
| 1 | ํฌ์ ์๋ฎฌ๋ ์ด์ ํ๊ฒฝ ์ ์ |
| 2 | ๊ฐํํ์ต Agent ๊ตฌ์ถ |
| 3 | ์์ต๋ฅ ๊ธฐ๋ฐ Reward ํ์ต |
| 4 | Transformer ํผ์ฒ ๊ฒฐํฉ |
| 5 | Flask + Streamlit ์ฐ๋ |
| 6 | ์ค์ ๋น์ค ์ถ์ฒ API ์ ๊ณต |
๐ ๋ค์ ๊ธ ์๊ณ
๋ค์ ํธ์์๋ **“AI ํํธ ๋ชจ๋ธ ์ฑ๋ฅ ๊ฒ์ฆ ๋ฐ ๋ฐฐํฌ – MLflow + Docker + Streamlit Monitoring”**์ ๋ค๋ฃน๋๋ค.
์ฆ, ๋ชจ๋ธ์ ์ง์์ ์ผ๋ก ํ์ต·ํ๊ฐ·๋ฐฐํฌํ๋ MLOps ๊ธฐ๋ฐ ํํธ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํฉ๋๋ค.
๊ฐํํ์ต,ํํธAI,์์จ์ด์ฉ,ํ์ด์ฌ๋ฅ๋ฌ๋,ํฌํธํด๋ฆฌ์ค์ต์ ํ,TransformerRL,๋ฅ๋ฌ๋ํฌ์,ํ์ดํ ์น,ํํธ์๋๋งค๋งค,AIํธ๋ ์ด๋ฉ
'์ฃผ์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- llm
- rag
- node.js
- SEO์ต์ ํ
- nextJS
- REACT
- Next.js
- Python
- ์๋ฐ๋ฉด์
- ai์ฒ ํ
- JWT
- CI/CD
- seo ์ต์ ํ 10๊ฐ
- Redis
- Express
- Docker
- NestJS
- ํ๋ก ํธ์๋๊ฐ๋ฐ
- DevOps
- kotlin
- flax
- JAX
- Prisma
- fastapi
- ๋ฅ๋ฌ๋
- ์ฟ ๋ฒ๋คํฐ์ค
- ๋ฐฑ์๋๊ฐ๋ฐ
- ์น๊ฐ๋ฐ
- PostgreSQL
| ์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
|---|---|---|---|---|---|---|
| 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 |

