Overview
HTFC v2는 기존 HTFC 아키텍처에 공유 인코더 + 심볼 임베딩 방식을 도입하여 16개 종목의 데이터로 학습하는 멀티심볼 확장 버전이다.
핵심 변경: 하나의 WaveEncoder가 모든 종목의 파동 패턴을 공유 학습하되, 각 종목의 고유 특성은 학습 가능한 심볼 임베딩으로 구분한다. 데이터 다양성 20배 증가 효과 + 모델 크기 거의 동일.
16개 종목 입력 (시장 센서)
→ 공유 WaveEncoder × 6 TF → WSE per symbol per TF
→ Cross-Scale Attention (탑다운 체인)
→ Cross-Symbol Aggregation → Market Context Vector
→ EntryHead (타겟 심볼 WSE + Market Context)
→ Buy/Sell/NoTrade + SL/TP
TF 체인: D1 → H4 → H1 → M30 → M15 → M5
(regime) (direction) (swing) (momentum) (setup) (entry)
종목 구성 (16개)
트레이딩 대상 (4개) — 실제 진입/청산
심볼역할스프레드
| EURUSD | 메이저, 최고 유동성 | ~0.6 pip |
| GBPUSD | 메이저, 변동성 큼 | ~0.9 pip |
| AUDUSD | 상품 통화 | ~0.8 pip |
| NZDUSD | 상품 통화, AUD와 상관 | ~1.2 pip |
시장 센서 (12개) — 입력만, 트레이딩 안 함
심볼역할제공하는 정보
| USDJPY | 메이저 | 금리차 센티먼트, 리스크온/오프 |
| USDCAD | 메이저 | 원유 연동, 북미 경제 |
| USDCHF | 메이저 | 안전자산 흐름 |
| AUDCAD | 크로스 | 상품 통화 간 상대 강도 |
| AUDCHF | 크로스 | 리스크 vs 안전자산 |
| EURNZD | 크로스 | 유럽 vs 오세아니아 |
| USDX | 인덱스 | 달러 종합 강도 |
| US100 | 주식지수 | 리스크 센티먼트, 기술주 흐름 |
| XAUUSD | 금/달러 | 안전자산 수요, 인플레이션 기대 |
| XAUAUD | 금/호주달러 | 금 vs 상품 통화 상대 가치 |
| XBRUSD | 브렌트유 | 에너지, 글로벌 수요 |
| CORN | 곡물 | 인플레이션 압력, 상품 사이클 |
종목 간 관계 맵
┌─── USDX (달러 종합) ───┐
│ │
┌──────┼──────┐ ┌──────┼──────┐
│ 달러 메이저 │ │ 달러 약세 │
│ USDJPY │ │ EURUSD ★ │
│ USDCAD │ │ GBPUSD ★ │
│ USDCHF │ │ AUDUSD ★ │
└─────────────┘ │ NZDUSD ★ │
└─────────────┘
┌─────────────┐ ┌─────────────┐
│ 크로스 관계 │ │ 자산군 교차 │
│ AUDCAD │ │ XAUUSD (금) │
│ AUDCHF │ │ XAUAUD │
│ EURNZD │ │ XBRUSD (유) │
└─────────────┘ │ US100 (주식)│
│ CORN (곡물) │
└─────────────┘
★ = 트레이딩 대상
심볼 카테고리 임베딩
SYMBOL_CATEGORIES = {
# category_id: 자산군 분류
0: "usd_major", # EURUSD, GBPUSD, USDJPY, USDCAD, USDCHF
1: "commodity_fx", # AUDUSD, NZDUSD
2: "cross", # AUDCAD, AUDCHF, EURNZD
3: "index", # USDX, US100
4: "metal", # XAUUSD, XAUAUD
5: "energy_agri", # XBRUSD, CORN
}
SYMBOL_IDS = {
"EURUSD": 0, "GBPUSD": 1, "AUDUSD": 2, "NZDUSD": 3,
"USDJPY": 4, "USDCAD": 5, "USDCHF": 6,
"AUDCAD": 7, "AUDCHF": 8, "EURNZD": 9,
"USDX": 10, "US100": 11,
"XAUUSD": 12, "XAUAUD": 13,
"XBRUSD": 14, "CORN": 15,
}
Architecture
전체 구조
입력: 16 symbols × 6 TFs × N bars × 22 features
┌──────────────────────────────────────────────────┐
│ Shared WaveEncoder (TF별 1개, 총 6개) │
│ │
│ 입력: [bar_features(22) + symbol_embed(16) │
│ + category_embed(8)] = 46-dim │
│ │
│ TCN (causal dilated conv) + positional encoding │
│ → 32-dim WSE per symbol per TF │
│ │
│ 파라미터: ~420K × 6 TF = ~2.52M │
│ (기존과 동일, 입력 projection만 46→hidden으로 변경) │
└──────────────────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ Cross-Scale Attention (탑다운 체인) │
│ │
│ D1 WSE(16sym) → H4 WSE(16sym) → ... → M5 WSE │
│ │
│ 각 TF에서: child WSE가 parent WSE에 attend │
│ "부모 파동의 어디에 내가 있는가?" │
│ │
│ 결과: TF별 context-enriched WSE (16sym × 6TF) │
└──────────────────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ Cross-Symbol Aggregation │
│ │
│ 방법: Attention-weighted pooling │
│ │
│ 타겟 심볼의 M5 WSE = Query │
│ 전체 16심볼의 M5 WSE = Key/Value │
│ → Market Context Vector (32-dim) │
│ │
│ "EURUSD 진입 판단 시, │
│ USDJPY/XAUUSD/US100 등의 상태가 │
│ 얼마나 관련있는가?" 를 자동 학습 │
│ │
│ 파라미터: ~8K (매우 경량) │
└──────────────────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ EntryHead (타겟 심볼별 1회 추론) │
│ │
│ 입력: GatedFusion( │
│ target_M5_WSE(32) ← 타겟의 M5 상태 │
│ + ancestor_WSEs(32×5) ← 타겟의 D1~M15 상태 │
│ + market_context(32) ← 16심볼 종합 맥락 │
│ ) │
│ │
│ 출력: {action, confidence, SL, TP} │
│ │
│ 파라미터: ~170K (기존 153K + context 입력 확장) │
└────────────────────────────────────────────────────┘
파라미터 총계
Shared WaveEncoder × 6 TF: 2,520K (기존과 거의 동일)
Cross-Scale Attention: 25K (기존과 동일)
Symbol Embedding (16 × 16): 256
Category Embedding (6 × 8): 48
Input Projection (46 → hidden): ~5K (기존 22→hidden 에서 확장)
Cross-Symbol Aggregation: ~8K (신규)
EntryHead: 170K (약간 확장)
─────────────────────────────────────────
총계: ~2.73M (기존 3.36M 이하)
기존보다 오히려 작다. 심볼별 독립 인코더를 공유 인코더로 바꾸면서 절약.
Core Components
1. Symbol Embedding
class SymbolEmbedding(nn.Module):
"""
각 종목의 고유 특성을 학습 가능한 벡터로 표현.
symbol_embed: 종목 고유 ID → 16-dim 벡터
"EURUSD는 유동성 높고 변동성 낮다" 같은 특성을 학습
category_embed: 자산군 카테고리 → 8-dim 벡터
"이건 메이저 FX다" vs "이건 상품이다" 같은 그룹 특성
합산: 16 + 8 = 24-dim → bar features(22)와 concat → 46-dim
"""
def __init__(self, n_symbols=16, n_categories=6):
super().__init__()
self.symbol_embed = nn.Embedding(n_symbols, 16)
self.category_embed = nn.Embedding(n_categories, 8)
def forward(self, symbol_id, category_id):
# 출력: 24-dim vector (시퀀스의 모든 봉에 동일하게 더해짐)
return torch.cat([
self.symbol_embed(symbol_id),
self.category_embed(category_id)
], dim=-1)
2. Shared WaveEncoder (수정)
class SharedWaveEncoder(nn.Module):
"""
기존 WaveEncoder를 모든 심볼이 공유하도록 수정.
핵심 변경:
- input_dim: 22 → 46 (bar features + symbol/category embed)
- TCN 구조: 동일 (causal dilated conv)
- 출력: 32-dim WSE (동일)
효과:
- EURUSD에서 배운 "급락 후 반등" 패턴을 GBPUSD에서도 활용
- 심볼 임베딩이 "이 패턴의 이 심볼 버전" 을 조정
- 학습 데이터 16배 증가 효과
"""
def __init__(self, input_dim=46, hidden_dim=64, wse_dim=32,
tcn_channels=[64, 64, 64], kernel_size=3):
super().__init__()
self.input_projection = nn.Linear(input_dim, hidden_dim)
self.tcn = TCN(
num_inputs=hidden_dim,
num_channels=tcn_channels,
kernel_size=kernel_size,
dropout=0.1
)
self.positional_encoding = PositionalEncoding(hidden_dim)
self.wse_projection = nn.Linear(hidden_dim, wse_dim)
def forward(self, x, symbol_embed):
"""
x: [batch, seq_len, 22] (bar features)
symbol_embed: [batch, 24] (symbol + category embed)
return: [batch, wse_dim] (32-dim WSE)
"""
# 심볼 임베딩을 모든 타임스텝에 broadcast
sym = symbol_embed.unsqueeze(1).expand(-1, x.size(1), -1)
x = torch.cat([x, sym], dim=-1) # [batch, seq_len, 46]
x = self.input_projection(x) # [batch, seq_len, 64]
x = self.positional_encoding(x)
x = self.tcn(x) # [batch, seq_len, 64]
x = x[:, -1, :] # 마지막 타임스텝
wse = self.wse_projection(x) # [batch, 32]
return wse
3. Cross-Symbol Aggregation (신규)
class CrossSymbolAggregation(nn.Module):
"""
타겟 심볼의 진입 판단을 위해 전체 16심볼의 상태를 종합.
Attention-weighted pooling:
- Query: 타겟 심볼의 WSE
- Key/Value: 전체 16심볼의 WSE
학습 효과 예시:
- EURUSD 매수 판단 시, USDJPY 하락(달러 약세 확인) → 높은 가중치
- XAUUSD 급등(리스크오프) → AUDUSD 매수 억제 방향으로 작용
- CORN/XBRUSD 동반 상승(인플레이션) → 금리 민감 통화에 영향
"""
def __init__(self, wse_dim=32):
super().__init__()
self.query_proj = nn.Linear(wse_dim, wse_dim)
self.key_proj = nn.Linear(wse_dim, wse_dim)
self.value_proj = nn.Linear(wse_dim, wse_dim)
self.scale = wse_dim ** 0.5
self.output_proj = nn.Linear(wse_dim, wse_dim)
def forward(self, target_wse, all_wses):
"""
target_wse: [batch, 32] (타겟 심볼의 M5 WSE)
all_wses: [batch, 16, 32] (전체 16심볼의 M5 WSE)
return: [batch, 32] (Market Context Vector)
"""
Q = self.query_proj(target_wse).unsqueeze(1) # [B, 1, 32]
K = self.key_proj(all_wses) # [B, 16, 32]
V = self.value_proj(all_wses) # [B, 16, 32]
attn = torch.matmul(Q, K.transpose(-2, -1)) / self.scale
attn = F.softmax(attn, dim=-1) # [B, 1, 16]
context = torch.matmul(attn, V).squeeze(1) # [B, 32]
return self.output_proj(context)
4. EntryHead (확장)
class EntryHeadV2(nn.Module):
"""
기존 EntryHead에 Market Context 입력 추가.
입력 구성:
- target_m5_wse (32): 타겟 심볼의 M5 파동 상태
- ancestor_wses (32×5): 타겟의 D1~M15 파동 상태
- market_context (32): 16심볼 종합 시장 맥락 ← 신규
총 입력: 32 + 160 + 32 = 224-dim (기존 192 + 32)
"""
def __init__(self, wse_dim=32, n_timeframes=6):
super().__init__()
input_dim = wse_dim * n_timeframes + wse_dim # 192 + 32 = 224
self.gate = nn.Sequential(
nn.Linear(input_dim, input_dim),
nn.Sigmoid()
)
self.classifier = nn.Sequential(
nn.Linear(input_dim, 128),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(128, 64),
nn.ReLU(),
nn.Dropout(0.1),
nn.Linear(64, 3) # Buy / Sell / NoTrade
)
self.sl_tp_head = nn.Sequential(
nn.Linear(input_dim, 64),
nn.ReLU(),
nn.Linear(64, 2) # SL, TP (ATR 배수)
)
def forward(self, target_wses, market_context):
"""
target_wses: [batch, 6, 32] (D1~M5 WSE for target symbol)
market_context: [batch, 32] (Cross-Symbol output)
"""
flat = target_wses.reshape(target_wses.size(0), -1) # [B, 192]
x = torch.cat([flat, market_context], dim=-1) # [B, 224]
gate = self.gate(x)
x = x * gate # Gated Fusion
action_logits = self.classifier(x) # [B, 3]
sl_tp = self.sl_tp_head(x) # [B, 2]
return action_logits, sl_tp
5. Full Chain (통합)
class HTFCv2(nn.Module):
"""
전체 HTFC v2 체인.
Forward 흐름:
1. 16심볼 × 6TF 데이터를 공유 인코더로 WSE 추출
2. 탑다운 Cross-Scale Attention (D1→M5)
3. Cross-Symbol Aggregation (타겟 기준 시장 맥락)
4. EntryHead (진입 판단)
"""
TIMEFRAMES = ["D1", "H4", "H1", "M30", "M15", "M5"]
def __init__(self, config):
super().__init__()
self.symbol_embedding = SymbolEmbedding(
n_symbols=config.n_symbols, # 16
n_categories=config.n_categories # 6
)
# TF별 공유 인코더 (6개)
# 같은 TF 내에서는 모든 심볼이 같은 인코더 사용
self.shared_encoders = nn.ModuleDict({
tf: SharedWaveEncoder(
input_dim=config.bar_features + 24, # 22 + 24 = 46
hidden_dim=config.hidden_dim, # 64
wse_dim=config.wse_dim, # 32
)
for tf in self.TIMEFRAMES
})
# 탑다운 체인 어텐션 (기존과 동일)
self.cross_scale = nn.ModuleDict({
f"{parent}_{child}": CrossScaleAttention(config.wse_dim)
for parent, child in zip(self.TIMEFRAMES[:-1], self.TIMEFRAMES[1:])
})
# 심볼 간 종합 (신규)
self.cross_symbol = CrossSymbolAggregation(config.wse_dim)
# 진입 판단
self.entry_head = EntryHeadV2(
wse_dim=config.wse_dim,
n_timeframes=len(self.TIMEFRAMES)
)
def forward(self, batch):
"""
batch: {
'bars': {tf: {sym: [B, seq_len, 22]} for all tf, sym},
'symbol_ids': {sym: int},
'category_ids': {sym: int},
'target_symbol': str, # e.g. "EURUSD"
}
"""
# Step 1: 전체 심볼 × TF의 WSE 추출
all_wses = {} # {tf: {sym: [B, 32]}}
for tf in self.TIMEFRAMES:
all_wses[tf] = {}
for sym in batch['bars'][tf]:
sym_embed = self.symbol_embedding(
batch['symbol_ids'][sym],
batch['category_ids'][sym]
)
wse = self.shared_encoders[tf](
batch['bars'][tf][sym],
sym_embed
)
all_wses[tf][sym] = wse
# Step 2: 탑다운 Cross-Scale (심볼별 독립)
for i in range(len(self.TIMEFRAMES) - 1):
parent_tf = self.TIMEFRAMES[i]
child_tf = self.TIMEFRAMES[i + 1]
key = f"{parent_tf}_{child_tf}"
for sym in all_wses[child_tf]:
if sym in all_wses[parent_tf]:
all_wses[child_tf][sym] = self.cross_scale[key](
child_wse=all_wses[child_tf][sym],
parent_wse=all_wses[parent_tf][sym]
)
# Step 3: Cross-Symbol Aggregation
target = batch['target_symbol']
target_m5_wse = all_wses["M5"][target]
all_m5_wses = torch.stack([
all_wses["M5"][sym] for sym in sorted(all_wses["M5"].keys())
], dim=1) # [B, 16, 32]
market_context = self.cross_symbol(target_m5_wse, all_m5_wses)
# Step 4: EntryHead
target_chain_wses = torch.stack([
all_wses[tf][target] for tf in self.TIMEFRAMES
], dim=1) # [B, 6, 32]
action_logits, sl_tp = self.entry_head(
target_chain_wses, market_context
)
return {
'action_logits': action_logits,
'sl_tp': sl_tp,
'all_wses': all_wses, # 디버깅/시각화용
'market_context': market_context
}
Features (22 per bar, 전 심볼 동일)
FEATURES = {
# 가격 기반 (6)
"returns": [
"log_return", # log(close/prev_close)
"high_low_range", # (high-low) / close
"body_ratio", # |close-open| / (high-low)
"upper_wick_ratio", # upper_wick / (high-low)
"lower_wick_ratio", # lower_wick / (high-low)
"gap", # (open - prev_close) / prev_close
],
# 변동성 (4)
"volatility": [
"atr_norm", # ATR(14) / close
"bb_width", # (BB_upper - BB_lower) / BB_mid
"realized_vol_20", # 20-bar realized volatility
"vol_of_vol", # volatility of volatility
],
# 모멘텀/추세 (4) — TCN이 학습하도록 최소 가공
"momentum": [
"roc_5", # rate of change 5-bar
"roc_20", # rate of change 20-bar
"close_vs_ema20", # (close - EMA20) / ATR
"close_vs_ema50", # (close - EMA50) / ATR
],
# 거래량 (2)
"volume": [
"volume_norm", # volume / SMA(volume, 20)
"volume_delta", # (volume - prev_volume) / prev_volume
],
# 시간 인코딩 (4)
"time": [
"hour_sin", # sin(2π × hour/24)
"hour_cos", # cos(2π × hour/24)
"dow_sin", # sin(2π × day_of_week/5)
"dow_cos", # cos(2π × day_of_week/5)
],
# 심볼 간 상관 (2) — 실시간 계산
"cross_symbol": [
"corr_vs_usdx_20", # 20-bar rolling corr with USDX
"relative_strength_20", # 같은 카테고리 내 상대 강도
],
}
# 총 22개 피처 — 기술지표 미사용, TCN이 패턴 학습
Training Pipeline (5 Phases)
Phase 1: Data Collection & Preprocessing
data_config = {
"symbols": [
"AUDUSD", "EURUSD", "GBPUSD", "NZDUSD", # 트레이딩 대상
"USDCAD", "USDCHF", "USDJPY", # 메이저 센서
"AUDCAD", "AUDCHF", "EURNZD", # 크로스 센서
"US100", "USDX", # 인덱스 센서
"XBRUSD", "XAUAUD", "XAUUSD", # 상품 센서
"CORN", # 농산물 센서
],
"timeframes": ["D1", "H4", "H1", "M30", "M15", "M5"],
"history_bars": {
"D1": 2000, # ~8년
"H4": 5000, # ~3년
"H1": 10000, # ~2년
"M30": 20000, # ~2년
"M15": 40000, # ~2년
"M5": 60000, # ~1년
},
"trading_targets": ["EURUSD", "GBPUSD", "AUDUSD", "NZDUSD"],
"preprocessing": {
"normalization": "per_symbol_rolling_zscore",
"window": 252, # 1년 롤링 (D1 기준)
"clip": 5.0, # ±5σ 클리핑
"missing_fill": "ffill_then_zero",
},
}
비 FX 종목 주의사항:
special_handling = {
"US100": {
"trading_hours": "주중 거의 24시간이나 갭 존재",
"weekend_gap": True,
"scale": "가격 레벨 ~18000, 정규화 필수",
},
"CORN": {
"trading_hours": "CME 시간만 (제한적)",
"missing_bars": "많음 — ffill 필수",
"liquidity": "FX 대비 매우 낮음",
},
"XBRUSD": {
"rollover": "선물 만기 롤오버 처리 필요",
"gap_risk": "주말 지정학 이벤트 시 갭",
},
}
Phase 2: Self-Supervised Pre-training (공유 인코더)
목표: 공유 WaveEncoder가 "모든 종목에 공통된 파동 패턴"을 학습
태스크: Next-bar prediction (MSE)
핵심 변경:
- 기존: TF별 독립 인코더를 TF별 독립 학습
- v2: TF별 공유 인코더를 16심볼 데이터로 동시 학습
학습 순서:
1. D1 인코더: 16심볼 × D1 데이터로 프리트레이닝
2. H4 인코더: 16심볼 × H4 데이터로 프리트레이닝
3. ... (H1, M30, M15, M5)
각 TF 인코더는 16심볼의 데이터를 번갈아 학습:
- epoch 내에서 16심볼 데이터를 셔플
- 심볼 임베딩 덕분에 "이건 EURUSD의 패턴" vs "이건 CORN의 패턴" 구분
- 하지만 TCN 가중치는 공유 → 공통 파동 구조 학습
에포크 수: 30 per TF (기존 20보다 증가, 데이터 16배 많으므로)
pretrain_config = {
"task": "next_bar_mse",
"epochs_per_tf": 30,
"batch_size": 64, # 심볼 간 mix
"lr": 1e-3,
"symbol_sampling": "uniform", # 모든 심볼 균등 샘플링
"curriculum": False, # 순서 무관하게 랜덤 학습
}
프리트레이닝 성공 기준:
각 TF 인코더의 next-bar MSE:
- 전체 16심볼 평균 MSE < 0.05
- 심볼별 MSE 편차 < 2× (특정 심볼만 나쁘지 않아야)
- CORN/XBRUSD 같은 비 FX도 FX와 비슷한 수렴 속도
→ 이것이 확인되면 공유 인코더가 범용 패턴을 학습한 증거
Phase 3: Entry Head Training
기존과 동일하되, Market Context 입력 추가.
라벨링: 트레이딩 대상 4개 심볼에 대해서만 Triple Barrier 라벨 생성
센서 12개: 라벨 없음, WSE 추출에만 사용
학습 데이터 흐름:
1. 16심볼 전체의 WSE를 top-down 체인으로 추출
2. Cross-Symbol Aggregation으로 Market Context 생성
3. 타겟 심볼(4개)의 WSE + Market Context → EntryHead
4. Triple Barrier 라벨과 비교하여 학습
entry_train_config = {
"target_symbols": ["EURUSD", "GBPUSD", "AUDUSD", "NZDUSD"],
"labels": "triple_barrier",
"label_params": {
"profit_taking": 2.0, # ATR 배수
"stop_loss": 1.0, # ATR 배수
"max_holding": {"M5": 36, "M15": 24, "M30": 16,
"H1": 24, "H4": 20, "D1": 10},
},
"loss": "class_weighted_cross_entropy + sl_tp_huber",
"class_weights": "inverse_frequency",
"epochs": 50,
"lr": 5e-4,
"early_stopping": {"patience": 10, "metric": "val_accuracy"},
# 4개 타겟을 번갈아 학습 (멀티태스크 효과)
"target_sampling": "round_robin",
}
Phase 3 성공 기준:
val_accuracy > 45% (베이스라인 33.3%, 기존 HTFC v1 41.8%)
- 4%p 이상 개선이면 Cross-Symbol 정보가 유효한 증거
- 심볼별 정확도 편차 < 5%p (특정 심볼만 잘하면 안됨)
- Attention 가중치 분석: USDJPY/XAUUSD에 높은 가중치 기대
Phase 4: End-to-End Fine-tuning
finetune_config = {
"epochs": 15,
"discriminative_lr": {
# TF별 차등 학습률 (기존과 동일 원칙)
"D1_encoder": 0.01, # 거의 동결
"H4_encoder": 0.05,
"H1_encoder": 0.1,
"M30_encoder": 0.3,
"M15_encoder": 0.5,
"M5_encoder": 1.0, # 가장 적극 조정
# 신규 컴포넌트
"symbol_embedding": 0.1, # 느리게 조정
"cross_symbol_aggregation": 0.5,
"entry_head": 1.0,
},
"base_lr": 1e-4,
}
Phase 5: Walk-Forward Validation & Backtest
walkforward_config = {
"train_window": "6months",
"test_window": "2months",
"step": "1month",
"purge_gap": "24h",
"embargo": "12h",
# 스트레스 테스트 기간
"stress_periods": [
"2020-03 (COVID crash)",
"2022-02 (Russia-Ukraine)",
"2022-09 (UK mini-budget, GBP crash)",
"2023-03 (SVB crisis)",
"2024-08 (Yen carry unwind)",
"2025-04 (Trump tariff, if applicable)",
],
# Go/No-Go 기준
"pass_criteria": {
"sharpe_ratio": "> 1.0",
"max_drawdown": "< 20%",
"profit_factor": "> 1.3",
"total_trades": "> 200",
"win_rate": "> 50%",
},
}
기대 효과: v1 vs v2 비교
레짐 감지 능력
v1 (4 페어):
EURUSD 급락 → "하락인가?" (맥락 부족)
v2 (16 종목):
EURUSD 급락 + GBPUSD 급락 + USDJPY 급등 + USDCHF 급등
+ XAUUSD 급등 + US100 급락
→ Cross-Symbol Attention이 "글로벌 리스크오프" 패턴을 감지
→ AUDUSD/NZDUSD 매수 시그널 억제
달러 요인 분리
v1: EURUSD 하락 → 유로 약세? 달러 강세? 구분 불가
v2: EURUSD 하락 + GBPUSD 하락 + AUDUSD 하락 + USDX 상승
+ 하지만 XAUUSD 보합, US100 보합
→ "달러 강세, 리스크 중립"
→ EURNZD(달러 무관)는 별도 판단 가능
상품 사이클 연동
v1: AUDUSD에 대한 상품 가격 영향 → 수동 피처로 넣거나 누락
v2: XBRUSD 상승 + CORN 상승 + AUDUSD/NZDUSD/USDCAD 반응
→ 인코더가 "상품 사이클 상승기" 패턴을 WSE에 인코딩
→ 상품 통화 매수 bias 학습
Project Structure
wave/
config/
base.yaml # 공통 설정
symbols.yaml # 16개 심볼 정의, 카테고리 매핑
nzdusd.yaml # 심볼별 오버라이드 (선택)
scripts/
collect.py # 16심볼 데이터 수집
train.py # 전체 학습 파이프라인
backtest.py # 워크포워드 백테스트
live.py # 실거래
analyze_attention.py # Cross-Symbol Attention 시각화 (신규)
src/
data/
collector.py # MT5 16심볼 수집 (확장)
synthetic.py # 합성 데이터 (16심볼 상관관계 포함)
preprocessor.py # 심볼별 정규화
labeler.py # Triple Barrier (타겟 4심볼만)
resampler.py # 타임프레임 리샘플링
dataset.py # MultiSymbolDataset (신규)
models/
symbol_embedding.py # SymbolEmbedding (신규)
tcn.py # TCN (기존)
wave_encoder.py # SharedWaveEncoder (수정)
cross_attention.py # CrossScaleAttention (기존)
cross_symbol.py # CrossSymbolAggregation (신규)
entry_head.py # EntryHeadV2 (확장)
chain.py # HTFCv2 (수정)
training/
losses.py # 손실 함수
pretrain.py # 공유 인코더 프리트레이닝 (수정)
entry_train.py # 엔트리 학습 (확장)
finetune.py # 파인튜닝
walk_forward.py # 워크포워드 검증
backtest/
engine.py # 백테스트 엔진
metrics.py # 평가 지표
live/
executor.py # MT5 주문 실행
monitor.py # 실시간 모니터링
runner.py # 메인 루프
state_manager.py # 상태 관리
analysis/ # (신규)
attention_viz.py # Cross-Symbol Attention 히트맵
wse_clustering.py # WSE 클러스터링 (레짐 분석)
symbol_importance.py # 심볼별 기여도 분석
utils/
config.py
logging_setup.py
CLI Usage
# 16심볼 데이터 수집
python scripts/collect.py --config config/symbols.yaml [--force-refresh]
# 학습 (전체 파이프라인)
python scripts/train.py --config config/base.yaml --device cuda [--phase all]
# 특정 Phase만 실행
python scripts/train.py --phase pretrain # Phase 2만
python scripts/train.py --phase entry # Phase 3만
python scripts/train.py --phase finetune # Phase 4만
# 백테스트
python scripts/backtest.py \
--model-path saved_models/htfc_v2.pt \
--target-symbols EURUSD GBPUSD AUDUSD NZDUSD
# Cross-Symbol Attention 분석
python scripts/analyze_attention.py \
--model-path saved_models/htfc_v2.pt \
--target EURUSD \
--date-range 2024-01-01 2024-12-31
# 실거래
python scripts/live.py \
--model-path saved_models/htfc_v2.pt \
--target-symbols EURUSD AUDUSD \
--dry-run
RTX 4060 (8GB VRAM) 메모리 예산
모델 파라미터 (fp16): ~5.5 MB
옵티마이저 상태 (AdamW): ~16.5 MB
활성화 메모리 (batch=64):
- 16심볼 × 6TF WSE 추출: ~400 MB
- Cross-Scale Attention: ~50 MB
- Cross-Symbol Aggregation: ~10 MB
- EntryHead: ~20 MB
그래디언트: ~5.5 MB
─────────────────────────────────────
총 예상: ~510 MB
8GB VRAM 대비 사용률: ~6.4%
여유: 충분 (batch 늘리거나 hidden_dim 확장 가능)
Design Decisions (v1 유지 + v2 추가)
- TCN over Transformer: 유지. dilated receptive field가 파동 구조에 적합
- Supervised over RL: 유지. 결정론적 라벨, 보상 설계 취약성 회피
- Rule-based exits: 유지. 모델 SL/TP 예측 + 규칙 청산
- 22 minimal features: 유지. 기술지표 미사용, TCN이 패턴 학습
- 32-dim WSE: 유지. 정보 병목으로 과적합 방지
- (v2) Shared encoder + symbol embedding: 모델 크기 유지하면서 데이터 16배
- (v2) Trading target ≠ Input set: 16개 입력, 4개만 트레이딩
- (v2) Cross-Symbol at WSE level: 원시 데이터가 아닌 학습된 표현 간 관계
- (v2) Category embedding: 자산군 그룹 특성을 명시적으로 제공
v1 → v2 마이그레이션
v1 학습 결과를 v2에 활용하는 방법:
1. 공유 인코더 초기화:
- v1의 NZDUSD 인코더 가중치로 v2 공유 인코더를 초기화
- 다른 심볼은 심볼 임베딩이 차이를 학습
2. Cross-Scale Attention:
- v1 가중치 그대로 로드 가능 (구조 동일)
3. EntryHead:
- 입력 차원 변경(192→224)으로 직접 로드 불가
- 기존 가중치의 앞 192차원만 로드, 나머지 32차원은 랜덤 초기화
4. 신규 컴포넌트:
- SymbolEmbedding: 랜덤 초기화
- CrossSymbolAggregation: 랜덤 초기화
→ Phase 3~4에서 학습'주식분석' 카테고리의 다른 글
| B-04. 푸리에 변환과 주기 분석 — 시장의 박자를 찾아라 (0) | 2026.05.12 |
|---|---|
| HTFC v4 Transformer 학습 및 실거래 준비 과정 (0) | 2026.04.30 |
| A-05. WaveRader 회원가입부터 첫 분석까지 — 완전 초보 가이드 (0) | 2026.04.28 |
| A-04. WaveRader vs 기존 HTS/MTS — 무엇이 다른가 (0) | 2026.04.27 |
| A-3.기업분석·경제지표·포트폴리오·알림 (0) | 2026.04.26 |