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

๋ฐ˜์‘ํ˜•

๐Ÿงช ๋‚˜๋งŒ์˜ AI ํ€€ํŠธ ์ „๋žต ๋งŒ๋“ค๊ธฐ – ๋‹จ 3๊ฐœ์˜ ์ง€ํ‘œ๋กœ ์™„์„ฑํ•˜๋Š” ์‹ค์ „ ์ „๋žต ์„ค๊ณ„ ๊ฐ€์ด๋“œ

— “์ฒ˜์Œ๋ถ€ํ„ฐ ์™„๋ฒฝํ•  ํ•„์š” ์—†๋‹ค. ๋‹จ์ˆœํ•˜๋ฉด ๋” ๊ฐ•ํ•˜๋‹ค.”

์ง€๊ธˆ๊นŒ์ง€๋Š”

  • AI ์ž์‚ฐ๋ฐฐ๋ถ„
  • ์ž๋™๋งค์ˆ˜
  • ๋ฆฌ์Šคํฌ ๊ด€๋ฆฌ
  • ๊ฐ•ํ™”ํ•™์Šต ์ „๋žต
    ๊นŒ์ง€ ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์€ ์•„์ฃผ ๋‹ค๋ฅธ ๊ด€์ ์ž…๋‹ˆ๋‹ค.

๐ŸŽฏ ๊ฐœ์ธ ํˆฌ์ž์ž๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ‘๋‚˜๋งŒ์˜ ํ€€ํŠธ ์ „๋žต’
๋‹จ 3๊ฐœ์˜ ์ง€ํ‘œ๋งŒ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋งค์šฐ ๋‹จ์ˆœํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ์ „๋žต์ž…๋‹ˆ๋‹ค.

AI๋กœ ์ „๋žต์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ,
์ „๋žต ์ž์ฒด๊ฐ€ ๊ฐ„๋‹จํ•ด์•ผ AI๊ฐ€ ๋” ์ž˜ ํ•™์Šต๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์ด๋ฒˆ ๊ธ€์€ **“์‚ฌ๋žŒ์ด ์„ค๊ณ„ํ•˜๊ณ  AI๊ฐ€ ํŠœ๋‹ํ•˜๋Š” ์ „๋žต”**์„ ๋งŒ๋“œ๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.


๐ŸŽฏ ์ด๋ฒˆ ๊ธ€์˜ ํ•ต์‹ฌ ๋ชฉํ‘œ

โœ” ์ดˆ๋ณด์ž๋„ ๋”ฐ๋ผ ํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์ „ ํˆฌ์ž ์ „๋žต์„ ํ•˜๋‚˜ ๋งŒ๋“ ๋‹ค.
โœ” ์ง€ํ‘œ๋Š” ๋‹จ 3๊ฐœ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.
โœ” ์กฐ๊ฑด์‹ → ํฌํŠธํด๋ฆฌ์˜ค → ๋ฐฑํ…Œ์ŠคํŠธ → ํŠœ๋‹๊นŒ์ง€ ์™„์„ฑํ•œ๋‹ค.
โœ” AI๊ฐ€ ๊ฐœ์„  ํฌ์ธํŠธ๋ฅผ ์Šค์Šค๋กœ ์ฐพ์•„๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„ํ•œ๋‹ค.


๐Ÿงฉ ์ „๋žต ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹จ 3๊ฐ€์ง€

์ถ”์„ธ + ๋ชจ๋ฉ˜ํ…€ + ๋ณ€๋™์„ฑ
์ด 3๊ฐ€์ง€๋งŒ ์žˆ์–ด๋„ ๊ธฐ๊ด€๊ธ‰ ์ „๋žต์ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.


1๏ธโƒฃ ์ถ”์„ธ ํ•„ํ„ฐ(Trend Filter)

๋ฐ˜์‘ํ˜•

์‹œ์žฅ ๋ฐฉํ–ฅ์„ ๋ฌด์‹œํ•˜๊ณ  ํˆฌ์žํ•˜๋ฉด 100% ๊นจ์ง‘๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๊ฐ€์žฅ ๋จผ์ € ์‹œ์žฅ ์ถ”์„ธ ํ•„ํ„ฐ๋ฅผ ๋‘ก๋‹ˆ๋‹ค.

โœ” 20์ผ > 60์ผ ์ด๋™ํ‰๊ท ์ด๋ฉด ๋งค์ˆ˜ ๊ฐ€๋Šฅ

(์ƒ์Šน ์ถ”์„ธ์— ์žˆ์„ ๋•Œ๋งŒ ์ „๋žต ํ™œ์„ฑํ™”)

def trend_filter(prices):
    ma20 = prices.rolling(20).mean().iloc[-1]
    ma60 = prices.rolling(60).mean().iloc[-1]
    return ma20 > ma60

๋. ๋งค์šฐ ๋‹จ์ˆœํ•˜์ง€๋งŒ ํšจ๊ณผ๋Š” ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค.


2๏ธโƒฃ ๋ชจ๋ฉ˜ํ…€ ์ ์ˆ˜(Momentum Score)

๊ฐ€์žฅ ๊ฐ•ํ•œ ์ข…๋ชฉ์„ ์„ ํƒํ•˜๋Š” ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.

def momentum(prices):
    return prices.pct_change(60).iloc[-1]

์ตœ๊ทผ 3๊ฐœ์›” ๊ฐ•ํ–ˆ๋˜ ์ข…๋ชฉ์ด
์•ž์œผ๋กœ๋„ ๊ฐ•ํ•  ํ™•๋ฅ ์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค.
(์ด๊ฒƒ์€ ์ „ ์„ธ๊ณ„ ๊ธˆ์œต์‹œ์žฅ์—์„œ ์ˆ˜์‹ญ ๋…„ ๋™์•ˆ ๊ฒ€์ฆ๋œ ํŒฉํ„ฐ์ž…๋‹ˆ๋‹ค.)


3๏ธโƒฃ ๋ณ€๋™์„ฑ ํ•„ํ„ฐ(Volatility Filter)

์œ„ํ—˜ํ•œ ์‹œ์žฅ์—์„œ๋Š” ๋น„์ค‘์„ ์ค„์—ฌ ์„ฑ๊ณผ์˜ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•ฉ๋‹ˆ๋‹ค.

def volatility(prices):
    return prices.pct_change().std()
  • ๋ณ€๋™์„ฑ ↑ → ๋น„์ค‘ ์ถ•์†Œ
  • ๋ณ€๋™์„ฑ ↓ → ๋น„์ค‘ ํ™•๋Œ€

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ์ดˆ๊ฐ„๋‹จ ์ „๋žต ์„ค๊ณ„์˜ 3์š”์†Œ์ž…๋‹ˆ๋‹ค.


๐Ÿ›  4๏ธโƒฃ ์ „๋žต ์กฐํ•ฉํ•˜๊ธฐ

์ด์ œ ์กฐ๊ฑด ๋ช‡ ์ค„๋กœ ์ „๋žต์„ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

def strategy_signal(prices):
    if not trend_filter(prices):
        return 0   # ๋งค์ˆ˜ ๊ธˆ์ง€

    mom = momentum(prices)
    vol = volatility(prices)

    score = mom / vol  # ์œ„ํ—˜ ๋Œ€๋น„ ๊ฐ•๋„
    return score

์ด ์ ์ˆ˜๊ฐ€ ๋†’์€ ์ข…๋ชฉ ์ƒ์œ„ N๊ฐœ๋ฅผ ๋งค์ˆ˜ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.


๐Ÿ“ˆ 5๏ธโƒฃ ๋ฐฑํ…Œ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ (ํŒŒ์ด์ฌ 10์ค„)

def backtest(prices_df, top_n=5):
    returns = prices_df.pct_change().shift(-1)
    signals = prices_df.apply(strategy_signal)

    selected = signals.nlargest(top_n).index
    portfolio = returns[selected].mean(axis=1)
    return portfolio.cumsum()

Streamlit ๋Œ€์‹œ๋ณด๋“œ๋กœ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™”๋„ ๊ฐ€๋Šฅ:

st.line_chart(backtest(price_df))

๐Ÿง  6๏ธโƒฃ AI ํŠœ๋‹ ์ ์šฉ – Optuna๋กœ ์ „๋žต ๊ฐœ์„ 

์‚ฌ๋žŒ์ด ๋งŒ๋“  ์ „๋žต ๊ณจ๊ฒฉ์„
AI๊ฐ€ ์ตœ์ ํ™”ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠœ๋‹ํ•  ํŒŒ๋ผ๋ฏธํ„ฐ ์˜ˆ์‹œ:

  • ๋ชจ๋ฉ˜ํ…€ ๊ธฐ๊ฐ„(30~120)
  • ์ด๋™ํ‰๊ท  ๊ธฐ๊ฐ„(20/60, 50/200 ๋“ฑ)
  • ๋ณ€๋™์„ฑ ๊ณ„์‚ฐ ๊ธฐ๊ฐ„
  • ์ƒ์œ„ ์ข…๋ชฉ ์ˆ˜(top_n)
  • ๋ฆฌ๋ฐธ๋Ÿฐ์‹ฑ ์ฃผ๊ธฐ(1๋‹ฌ/2์ฃผ/1์ฃผ)
def objective(trial):
    mom_window = trial.suggest_int("mom", 30, 120)
    vol_window = trial.suggest_int("vol", 10, 40)
    top_n = trial.suggest_int("top_n", 3, 10)

    result = backtest_custom(mom_window, vol_window, top_n)
    sharpe = result.mean() / result.std()
    return -sharpe

AI๊ฐ€ ์ž๋™์œผ๋กœ ์ „๋žต์„ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“Š 7๏ธโƒฃ ์‹ค์ œ ์ „๋žต ์„ฑ๋Šฅ (์˜ˆ์‹œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ)

์ „๋žต ์—ฐํ‰๊ท  ์ˆ˜์ต๋ฅ  MDD ์ƒคํ”„์ง€์ˆ˜

S&P500 ๋‹จ์ˆœ ๋งค์ˆ˜ 10.5% -34% 0.85
3์ง€ํ‘œ ์ „๋žต(๊ธฐ๋ณธ๊ฐ’) 16.1% -21% 1.32
AI ํŠœ๋‹ ์ „๋žต 18.7% -18% 1.49

AI๊ฐ€ ๋ณด์กฐํ•ด์ฃผ๋Š” ์ „๋žต์ด ๊ฐ€์žฅ ์ข‹์•˜์Šต๋‹ˆ๋‹ค.


๐Ÿ’ก 8๏ธโƒฃ ๊ฐœ์ธ ํˆฌ์ž์ž๊ฐ€ ์ฆ‰์‹œ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

์ „๋žต์„ ๋งŒ๋“  ๋’ค, ์ด๋ ‡๊ฒŒ๋งŒ ์šด์˜ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค:


โœ” ๋งค์›” ๋ง ์ž‘๋™

  1. Streamlit ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ์—ด๊ณ 
  2. ์ด๋ฒˆ ๋‹ฌ ์ƒ์œ„ ์ข…๋ชฉ 5๊ฐœ ํ™•์ธ
  3. ๋™์ผ ๋น„์ค‘์œผ๋กœ ๋งค์ˆ˜

์ข…๋ชฉ์€ ๋งค๋‹ฌ 5๊ฐœ๋งŒ.
๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ๊ด€๋ฆฌ๊ฐ€ ์•ˆ ๋ฉ๋‹ˆ๋‹ค.


โœ” ๋ฆฌ์Šคํฌ ๋†’์œผ๋ฉด "ํ˜„๊ธˆ 50%"

AI ๋ฆฌ์Šคํฌ ๋งค๋‹ˆ์ €(VIX, ๋ณ€๋™์„ฑ, ๊ธˆ๋ฆฌ)๋ฅผ ๋‹จ์ˆœํ™”ํ•ด์„œ
์œ„ํ—˜์ด ๋†’์œผ๋ฉด ํ˜„๊ธˆ ๋น„์ค‘์„ ์ž๋™์œผ๋กœ ๋Š˜๋ฆฝ๋‹ˆ๋‹ค.


โœ” ๋‚™ํญ ์‹ฌํ•˜๋ฉด ๊ฐ•์ œํ˜„๊ธˆํ™”

์ถ”์„ธ ํ•„ํ„ฐ๊ฐ€ ๊นจ์ง„ ๊ฒฝ์šฐ(20 < 60)
→ ์ „๋Ÿ‰ ํ˜„๊ธˆ ๋Œ€๊ธฐ (๋‹จ ํ•œ ์ค„ ์กฐ๊ฑด์‹์œผ๋กœ ํ•ด๊ฒฐ)


๐Ÿ“˜ ๋‹ค์Œ ๊ธ€ ์˜ˆ๊ณ 

๋‹ค์Œ ํŽธ์—์„œ๋Š”

“ํ€€ํŠธ ์ „๋žต์„ ์‹ค์ œ ํˆฌ์ž๊ณ„์ขŒ(๋ฏธ๋ž˜์—์…‹, ํ‚ค์›€, IBKR)์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ• – API ํŠธ๋ ˆ์ด๋”ฉ ์™„์ „ ์ •๋ฆฌ”

๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

์ฆ‰,
AI ์ „๋žต → ์ฃผ๋ฌธ ์ƒ์„ฑ → ์ž๋™ ๋งค์ˆ˜/๋งค๋„
๊นŒ์ง€ ์ด์–ด์ง€๋Š” ์ง„์งœ ํˆฌ์ž ์ž๋™ํ™” ์‹œ์Šคํ…œ์„ ์™„์„ฑํ•ฉ๋‹ˆ๋‹ค.


 

ํ€€ํŠธ์ „๋žต,AIํ€€ํŠธ,RSI,MACD,๋ชจ๋ฉ˜ํ…€์ „๋žต,๋ณ€๋™์„ฑ์ „๋žต,๋ฐฑํ…Œ์ŠคํŠธ,ETF์ „๋žต,OptunaํŠœ๋‹,๊ฐœ์ธํ€€ํŠธ


 

โ€ป ์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค.
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
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
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•