feat: Add strategy presets for quick configuration

This commit is contained in:
2026-03-06 20:47:19 +09:00
parent 12460b7c9e
commit 674cb1ef28

View File

@@ -0,0 +1,166 @@
/**
* 전략 프리셋 정의
*
* 사용자가 복잡한 파라미터를 직접 조정하지 않고
* 미리 정의된 설정을 선택할 수 있도록 지원
*/
export interface PresetConfig {
name: string
description: string
emoji: string
risk: 'low' | 'medium' | 'high'
expectedReturn: string
params: Record<string, string | number | boolean>
}
export const STRATEGY_PRESETS: Record<string, PresetConfig> = {
conservative: {
name: '보수적 (안정 중시)',
description: '낮은 위험으로 꾸준한 수익 추구. 손절 타이트, 진입 까다로움',
emoji: '🛡️',
risk: 'low',
expectedReturn: '연 8-12%',
params: {
// 리스크 관리
'MEAN_REVERSION_STOP_LOSS_PCT': -5.0, // 손절 -5%
'MEAN_REVERSION_TAKE_PROFIT_PCT': 8.0, // 익절 +8%
'MAX_TOTAL_POSITIONS': 3, // 최대 3종목
'MDD_LIMIT_PCT': -15.0, // MDD 한도 -15%
// 진입 필터 (까다롭게)
'MEAN_REVERSION_RSI_THRESHOLD': 25, // RSI ≤ 25만 진입
'MIN_AVG_VOLUME_20D': 100000, // 최소 거래량 높게
'MIN_MARKET_CAP': 3000, // 시가총액 3천억 이상
// 지표
'RSI_PERIOD': 14,
'BOLLINGER_PERIOD': 20,
'ADX_THRESHOLD': 30, // 강추세 시 진입 차단
// 데이트레이딩 비활성화
'DAY_TRADE_ENABLED': false,
'DAY_TRADE_MAX_POSITIONS': 0,
},
},
balanced: {
name: '균형형 (기본 설정)',
description: '리스크와 수익의 균형. 대부분의 시장 환경에 적합',
emoji: '⚖️',
risk: 'medium',
expectedReturn: '연 12-18%',
params: {
// 리스크 관리
'MEAN_REVERSION_STOP_LOSS_PCT': -6.0,
'MEAN_REVERSION_TAKE_PROFIT_PCT': 12.0,
'MAX_TOTAL_POSITIONS': 5,
'MDD_LIMIT_PCT': -20.0,
// 진입 필터 (표준)
'MEAN_REVERSION_RSI_THRESHOLD': 30,
'MIN_AVG_VOLUME_20D': 50000,
'MIN_MARKET_CAP': 1000,
// 지표
'RSI_PERIOD': 14,
'BOLLINGER_PERIOD': 20,
'ADX_THRESHOLD': 30,
// 데이트레이딩 제한적 활성화
'DAY_TRADE_ENABLED': true,
'DAY_TRADE_MAX_POSITIONS': 2,
'DAY_TRADE_MAX_CAPITAL_RATIO': 0.15, // 전체 자본의 15%
},
},
aggressive: {
name: '공격적 (수익 극대화)',
description: '높은 수익 목표, 넓은 손절폭. 변동성 수용 필수',
emoji: '🚀',
risk: 'high',
expectedReturn: '연 20-30%',
params: {
// 리스크 관리 (여유롭게)
'MEAN_REVERSION_STOP_LOSS_PCT': -8.0, // 손절 -8%
'MEAN_REVERSION_TAKE_PROFIT_PCT': 20.0, // 익절 +20%
'MAX_TOTAL_POSITIONS': 8, // 최대 8종목
'MDD_LIMIT_PCT': -25.0,
// 진입 필터 (완화)
'MEAN_REVERSION_RSI_THRESHOLD': 35, // RSI ≤ 35
'MIN_AVG_VOLUME_20D': 30000,
'MIN_MARKET_CAP': 500, // 시가총액 500억
// 지표
'RSI_PERIOD': 10, // 더 민감하게
'BOLLINGER_PERIOD': 15,
'ADX_THRESHOLD': 40, // 강추세도 일부 허용
// 데이트레이딩 적극 활용
'DAY_TRADE_ENABLED': true,
'DAY_TRADE_MAX_POSITIONS': 3,
'DAY_TRADE_MAX_CAPITAL_RATIO': 0.25, // 전체 자본의 25%
'DAY_TRADE_ORB_STOP_LOSS_PCT': 0.025, // ORB 손절 -2.5%
},
},
}
export const PRESET_ORDER = ['conservative', 'balanced', 'aggressive'] as const
export type PresetKey = typeof PRESET_ORDER[number]
/**
* 현재 설정이 어떤 프리셋에 가장 가까운지 판단
*/
export function detectCurrentPreset(
configs: Array<{ key: string; value: string }>
): PresetKey | 'custom' {
const configMap = new Map(configs.map(c => [c.key, c.value]))
for (const presetKey of PRESET_ORDER) {
const preset = STRATEGY_PRESETS[presetKey]
let matchCount = 0
let totalChecked = 0
for (const [key, expectedValue] of Object.entries(preset.params)) {
const currentValue = configMap.get(key)
if (currentValue !== undefined) {
totalChecked++
if (String(currentValue) === String(expectedValue)) {
matchCount++
}
}
}
// 80% 이상 일치하면 해당 프리셋으로 간주
if (totalChecked > 0 && matchCount / totalChecked >= 0.8) {
return presetKey as PresetKey
}
}
return 'custom'
}
/**
* 프리셋 적용 시 변경될 파라미터 목록 반환
*/
export function getPresetDiff(
presetKey: PresetKey,
currentConfigs: Array<{ key: string; value: string }>
): Array<{ key: string; from: string; to: string }> {
const preset = STRATEGY_PRESETS[presetKey]
const diffs: Array<{ key: string; from: string; to: string }> = []
for (const [key, newValue] of Object.entries(preset.params)) {
const current = currentConfigs.find(c => c.key === key)
if (current && String(current.value) !== String(newValue)) {
diffs.push({
key,
from: current.value,
to: String(newValue),
})
}
}
return diffs
}